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 \\ []), orop(client, body, params \\ [], opts \\ [])when the operation has a request body;paramsis 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;optsare the options of the call::content_type(the media type of the body when the operation accepts several),:headersand:req_options(options ofReq.request/2, e.g.retry: falseorinto: 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-streamand JSON Lines responses are read whole, as a string and as bytes.- The models don’t validate
minimum,maximum,patternand the other constraints, and ignoreprefixItems,patternPropertiesand conditional schemas. readOnlyandwriteOnlyproperties 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. |