apigenie-generatorOpenAPI clientsclient elixir

client elixir

Generate an Elixir client on Req from an OpenAPI document.

From an AsyncAPI document, the command generates a WebSocket and Kafka client library instead; see apigenie-generator client elixir (AsyncAPI).

Usage

apigenie-generator client elixir [...OPTIONS] INPUT_FILE

Description

The generator writes a Mix project (Elixir 1.18 or later) depending on Req 0.5 or later and Jason. Its code passes mix format --check-formatted, mix compile --warnings-as-errors, mix credo --strict and mix dialyzer.

File Contents
lib/<app>.ex the root module, with new/1 creating a client
lib/<app>/api/<tag>.ex a module per tag (Default for operations without tags), with a function per operation
lib/<app>/models/*.ex a module per schema: structs, enums, unions and aliases, with new/1, new!/1 and to_map/1
lib/<app>/client.ex, api_error.ex the client struct and the error of operations
lib/<app>/metadata.ex the servers and the security schemes of the document
lib/<app>/runtime/*.ex, models/decode.ex, models/encode.ex the encoding of parameters and bodies, and the decoding of responses
mix.exs, .formatter.exs, .gitignore, README.md the project
client =
  CarpetExpress.new(
    base_url: "https://api.example.com/v2",
    auth: [bearer_jwt: System.fetch_env!("API_TOKEN")],
    req_options: [receive_timeout: 10_000, retry: :transient]
  )

{:ok, shipment} = CarpetExpress.Api.Shipments.get_shipment(client, shipment_id: "shp_123")
shipment = CarpetExpress.Api.Shipments.get_shipment!(client, shipment_id: "shp_123")

Functions

Every operation is a function named after its operationId in snake_case, in the module of its first tag:

  • op(client, params \\ [], opts \\ []), or op(client, body, params \\ [], opts \\ []) when the operation has a request body;
  • params is a keyword list of the path, query, header and cookie parameters, keyed by their names in snake_case (shipment_id: "...", if_match: ...); missing required parameters and unknown ones give an error before anything is sent;
  • opts are the options of the call: :content_type (the media type of the body when the operation accepts several), :headers and :req_options (options of Req.request/2, e.g. retry: false or into: File.stream!("label.pdf")).

A ! variant of each function returns the body itself and raises the error.

Responses and errors

A response with a 2XX status gives {:ok, body}: the body decoded into its model (new/1 of its module), a list of them, a string for text/* media types, the bytes for other media types, or nil without content. Any other status gives {:error, %ApiError{reason: :status}}, with the status, the headers and the decoded body (a problem document, the error’s model). The other reasons are :transport (the request failed), :decode (the body doesn’t match its schema), :params and :auth.

Parameters and bodies

Parameters are encoded in their styles: simple, label and matrix path parameters, form, spaceDelimited, pipeDelimited and deepObject query parameters, headers, cookies, and parameters described with content as JSON. Models, enums (atoms), dates and times are encoded with their schemas.

Media type Body
JSON (application/json, *+json) a model struct or a plain map
application/x-www-form-urlencoded a model struct or a map, its fields in the styles of their encoding
multipart/form-data a map or a keyword list of the parts: files as {content, filename: ..., content_type: ...} or the content alone, lists of files, values and JSON parts
text/* a string
anything else iodata, or an enumerable of chunks

Servers

The base URL is the first server of the document, or the :base_url option of new/1. Operations with servers of their own are sent there, unless operation_servers: false.

Security

new/1 takes the credentials by security scheme in :auth, keyed by the scheme names in snake_case (CarpetExpress.Metadata.security_schemes/0 lists them). A credential is the value (an API key, a token, {user, password} for HTTP basic) or a supplier called before each request (fn -> {:ok, token} end, or {module, function, args}), e.g. to fetch and refresh OAuth2 tokens. Each request uses the first security requirement of its operation whose schemes all have a credential: API keys in headers, the query or cookies, HTTP bearer and basic, OAuth2 and OpenID Connect tokens as bearer tokens. Mutual TLS is set up with req_options: [connect_options: [transport_opts: [certfile: ..., keyfile: ...]]].

Types

The models are the modules of the Elixir models: a struct per object (with allOf flattened), atoms for string enums, a module dispatching on the discriminator for oneOf and anyOf, Date, DateTime, NaiveDateTime and Time for dates and times, binaries for format: byte (decoded from base64) and format: binary, additional_properties maps, and | nil for nullable values.

Extensions

Extension Effect
x-apigenie.codegen.name name of the module of a component schema, unless module_overrides names it
x-apigenie.codegen.action-name name of the function of an operation without an operationId (with the default action_naming, which lists id first)
x-apigenie.codegen.disabled true on an operation or its path item leaves the operation out
x-internal true on an operation or its path item leaves the operation out, unless internal_operations is set
x-defaultMapping defaultMapping of a discriminator in OpenAPI 3.0 and 3.1 documents: the schema of the values whose discriminator value isn’t mapped

The extensions can live in an overlay for this target instead of in the document, e.g. elixir.overlay.yaml:

overlay: 1.0.0
info:
  title: Elixir names
  version: 1.0.0
actions:
  - target: $.components.schemas.Pet
    update:
      x-apigenie:
        codegen:
          name: Animal
  - target: $.paths['/admin']
    update:
      x-internal: true
apigenie-generator client elixir openapi.yaml --overlay elixir.overlay.yaml -o out

Limitations

  • text/event-stream and JSON Lines responses are read whole, as a string and as bytes.
  • The models don’t validate minimum, maximum, pattern and the other constraints, and ignore prefixItems, patternProperties and conditional schemas.
  • readOnly and writeOnly properties are fields of the same struct.
  • Callbacks, webhooks and links aren’t generated.

Options

-c, –config

Path to the configuration file to use. See the “Configuration” section for more information.

–overlay OVERLAY

Path to an OpenAPI Overlay (1.0 to 1.2) applied to the input before generating, e.g. one setting the extensions of the “Extensions” section. Can be repeated: the overlays apply in order, after those listed under commands.generate.client_elixir.overlay in the configuration file (with paths relative to it). Warnings and errors about a value an overlay set point to the overlay. Not for a .proto input.

–strict

Makes an overlay action whose target selects nothing an error (exit status 2, nothing is generated) instead of a warning (OVERLAY:LINE:COL: action #N (TARGET) selects no nodes.).

-o, –output

Directory where the project is generated.

–package-name

Name of the Mix application, converted to snake_case (carpet-express gives carpet_express and the root module CarpetExpress). Defaults to the name of the output directory.

–package-version

Version of the Mix project; 0.1.0 by default.

-p, –property NAME=VALUE

Sets a generator option (see below), e.g. -p dev_deps=false. Options given on the command line take precedence over the configuration file. Lists are comma-separated (-p include_tags=pets,store) and mappings too (-p module_overrides=pet-owner=Owner).

Configuration

version: '1.0'
commands:
  generate:
    client_elixir:
      app: carpet_express
      namespace: CarpetExpress
      exclude_tags: [internal]
Option Type Default Description
app string name of the output directory Name of the Mix application (snake_case, the directory under lib/); also set by --package-name.
namespace string the application in PascalCase Root module of the generated modules, e.g. CarpetExpress.
include_tags list of strings Generates only the operations with one of these tags.
exclude_tags list of strings Skips the operations with one of these tags.
skip_prune boolean false Keeps the component schemas that no generated operation uses.
internal_operations boolean false Also generates the operations marked x-internal: true.
dev_deps boolean true Lists credo and dialyxir as dependencies of mix.exs (only: :dev).
action_naming list of id, extension, url id, extension, url Where function names come from, in order of preference.
field_prefix string field_ Prefix of struct fields whose property names give no valid name.
module_overrides map of strings Module names of component schemas, e.g. pet-owner: Owner.