howdy/openapi

OpenAPI 3.1 documents for Howdy apps.

Routes added with howdy/openapi/endpoint are documented from the schemas they read and the docs they declare. Ordinary controller routes are left out, so an app chooses what it publishes.

import howdy/openapi

let spec =
  openapi.new(title: "Users API", version: "1.0.0")
  |> openapi.bearer_auth("bearer")

howdy.new()
|> howdy.controller(user.controller())
|> openapi.serve(spec, at: "/openapi.json")
|> openapi.reference(at: "/docs", document: "/openapi.json")
|> howdy.start

serve documents the controllers mounted before it, so call it after them. An app with a howdy/version group gets a document per version; see version_document.

Types

A document serve serves. Tools such as howdy_admin find them with served.

pub type Served {
  Served(
    path: String,
    version: option.Option(String),
    main: Bool,
    document: String,
  )
}

Constructors

  • Served(
      path: String,
      version: option.Option(String),
      main: Bool,
      document: String,
    )

    Arguments

    path

    Where the document is served.

    version

    The version it describes, if the app has a version group.

    main

    Whether it is the document at the path given to serve, rather than one of the per-version documents beside it.

    document

    The document, as JSON text.

The document’s own details: title, version, servers and security schemes.

pub opaque type Spec

Values

pub fn api_key_cookie(
  spec: Spec,
  name: String,
  cookie cookie: String,
) -> Spec

Declare an API key sent in a cookie, such as a session cookie.

pub fn api_key_header(
  spec: Spec,
  name: String,
  header header: String,
) -> Spec

Declare an API key sent in a request header.

pub fn bearer_auth(spec: Spec, name: String) -> Spec

Declare a bearer token scheme, authorization: Bearer <token>, named name. Endpoints require it with endpoint.security(name).

pub fn description(spec: Spec, text: String) -> Spec

A description of the API. OpenAPI allows Markdown here.

pub fn document(spec: Spec, app: howdy.App) -> json.Json

The document for the endpoints of the controllers mounted on app so far. With a howdy/version group, it is the document of the default version, or of the newest without a default; see version_document. Panics if an endpoint reads a path parameter its route does not capture, two different schemas share a name, or two endpoints share an operation id.

pub fn new(title title: String, version version: String) -> Spec

version is the version of your API, not of OpenAPI, and is the document’s info.version. With a howdy/version group, each version’s document shows it followed by that version’s name, as in 1.0.0 (v2); see version_document.

pub fn reference(
  app: howdy.App,
  at path: String,
  document url: String,
) -> howdy.App

Serve an interactive API reference at path, for the document serve serves at the URL document. With a version group, the page offers every version’s document, opening on the one document describes. The page loads Scalar’s API reference from the jsDelivr CDN, so browsers viewing it need to reach cdn.jsdelivr.net.

pub fn require(spec: Spec, scheme: String) -> Spec

Require a declared scheme for every endpoint that does not name its own with endpoint.security.

pub fn serve(
  app: howdy.App,
  spec: Spec,
  at path: String,
) -> howdy.App

Serve the document as JSON at path. With a version group, path serves the document, and each version’s is served beside it: /openapi.json gives /openapi/v1.json, /openapi/v2.json and so on. The documents are built once, here, from the controllers already mounted.

pub fn served(app: howdy.App) -> List(Served)

The documents serve added to app, in the order they were added.

pub fn server(spec: Spec, url: String) -> Spec

A base URL the API is served from, such as https://api.example.com. Without one, clients use the URL the document was fetched from.

pub fn version_document(
  spec: Spec,
  app: howdy.App,
  name: String,
) -> Result(json.Json, Nil)

The document for one version of the API: the app’s unversioned endpoints, which answer whatever the version, and the version’s own, including those it falls back to. The document’s info.version is the spec’s version followed by the version’s name in parentheses, as in 1.0.0 (v2), so both are seen.

How a client asks for the version is documented the way OpenAPI expects:

  • version.path(): paths start with the version, as in /v2/users.
  • version.header(name): each operation takes the header, required unless this is the default version.
  • version.accept(vendor): JSON responses have the vendor media type, such as application/vnd.howdy.v2+json, so clients send it in accept.
  • version.custom(fn): nothing can be said; describe it yourself.

Error if the app has no such version.

pub fn versions(app: howdy.App) -> List(String)

The versions app has documents for, in declaration order. Empty without a version group.

✨ Search Document