API Documentation

Live on this server

Generates an Open API definition and serves Swagger UI, Redoc and Scalar.

ApiDocumentationSample.cs89 lines
using GenHTTP.Api.Content;
using GenHTTP.Api.Protocol;

using GenHTTP.Modules.ApiBrowsing;
using GenHTTP.Modules.Layouting;
using GenHTTP.Modules.OpenApi;
using GenHTTP.Modules.Reflection;
using GenHTTP.Modules.Webservices;

public static class ApiDocumentationSample
{

    public static IHandlerBuilder Create()
    {
        /*
         *
         * Generates an Open API definition for a web service and lets developers
         * explore and try the API in their browser. The viewers are hosted by the
         * server itself, so no internet connection is required.
         *
         * Works the same way for functional handlers and controllers.
         *
         * See https://genhttp.org/documentation/content/concerns/open-api/
         * and https://genhttp.org/documentation/content/handlers/api-browsing/
         *
         */

        return Layout.Create()
                     .AddService<BookService>("books")
                     .AddOpenApi() // GET /samples/api-docs/openapi.json (or .yaml)
                     .AddSwaggerUi() // GET /samples/api-docs/swagger/
                     .AddRedoc() // GET /samples/api-docs/redoc/
                     .AddScalar(title: "Book API"); // GET /samples/api-docs/scalar/
    }

    public record Book(int Id, string Title);

    public class BookService
    {
        private static readonly List<Book> Books =
        [
            new(1, "Lord of the Rings")
        ];

        [ResourceMethod]
        public List<Book> List()
        {
            lock (Books) return [..Books];
        }

        [ResourceMethod(":id")]
        public Book Get(int id)
        {
            lock (Books)
            {
                return Books.FirstOrDefault(b => b.Id == id) ?? throw new ProviderException(ResponseStatus.NotFound, $"There is no book with id {id}");
            }
        }

        [ResourceMethod(Method.Put)]
        public Book Create(Book book)
        {
            lock (Books)
            {
                if (Books.Count >= 50)
                {
                    throw new ProviderException(ResponseStatus.Conflict, "The shelf is full, please delete a book first");
                }

                var toAdd = book with
                {
                    Id = Books.Select(b => b.Id).DefaultIfEmpty().Max() + 1
                };

                Books.Add(toAdd);

                return toAdd;
            }
        }

        [ResourceMethod(Method.Delete, ":id")]
        public void Delete(int id)
        {
            lock (Books) Books.RemoveAll(b => b.Id == id);
        }

    }

}

Try it

Send the requests to the sample running on this server - change the path, headers or body as you like, or copy them as curl commands.

  1. Swagger UI

    PAGE /samples/api-docs/swagger/ Open
  2. Redoc

    PAGE /samples/api-docs/redoc/ Open
  3. Scalar

    PAGE /samples/api-docs/scalar/ Open
  4. Fetch the Open API definition

    GET
    curl -i 'https://genhttp.org/samples/api-docs/openapi.json'
  5. Fetch a book that does not exist

    404, as documented in the definition

    GET
    curl -i 'https://genhttp.org/samples/api-docs/books/42'