apigenie-generatorOpenAPI clientsclient fetch
client fetch
Generate a TypeScript client for the Fetch API from an OpenAPI document.
Usage
apigenie-generator client fetch [...OPTIONS] INPUT_FILE
Description
The generator writes TypeScript sources with no runtime dependencies: requests go through the
global fetch() (or one you pass), so the client runs in browsers and in Node.js 18 or later. The
input is an OpenAPI 3.0, 3.1 or 3.2 document.
| File | Contents |
|---|---|
src/types.ts |
a type per component schema, the ...Params interface of each operation, and the named types of inline bodies |
src/operations.ts |
an async function per operation |
src/metadata.ts |
DEFAULT_BASE_URL, the AuthCredentials interface and SECURITY_SCHEMES |
src/runtime.ts |
configure(), ApiError, parameter serialization, authentication, body encoding |
src/index.ts |
exports the types, the operations and the public part of the runtime |
package.json, tsconfig.json |
an ES module package built with tsc into dist/ (layout: package only) |
With layout: sources, the five files are written directly to the output directory, to be
compiled as part of your own project. A client of a shipping API, generated with layout: sources
into api/:
import { configure, ApiError, listShipments, getShipment, downloadLabelFile } from "./api/index.js";
configure({
baseUrl: "https://eu.api.carpetexpress.example/v2",
auth: {
apiKey: "ce_live_123", // sent in the X-Api-Key header
oauth2: () => fetchAccessToken(), // called before every request that needs it
},
});
try {
const page = await listShipments({ status: ["in_transit", "delivered"], limit: 20 });
const shipment = await getShipment(
{ shipmentId: "shp_01J9Z", expand: ["labels"] },
{ signal: AbortSignal.timeout(5000), headers: { "X-Request-Id": "req-1" } },
);
const label: Blob = await downloadLabelFile({ labelId: "lbl_1", extension: "pdf" });
} catch (error) {
if (error instanceof ApiError) {
console.error(error.status, error.body); // status 0: no response was received
}
}
Configuration at run time
configure(settings) sets the client-wide settings; settings it doesn’t give keep their values.
Every operation function also takes an optional last argument, RequestOptions, with the same
settings for that call only, and an AbortSignal.
| Setting | Meaning |
|---|---|
baseUrl |
Base URL of the API. Defaults to DEFAULT_BASE_URL: the URL of the document’s first server when it is absolute and has no variables, otherwise empty, and a call without a base URL throws an ApiError. |
fetch |
The fetch() implementation; the global one by default. |
headers |
Headers sent with every request. |
auth |
Credentials, by security scheme name (AuthCredentials). |
signal |
RequestOptions only: aborts the request. |
Operations
Every operation is an exported async function named after its operationId in camel case
(list_shipments becomes listShipments), or after its method and path when it has none
(GET /pets/{id} becomes getPetsId); see action_naming. The summary and the description
become its JSDoc comment, and deprecated operations are marked @deprecated.
export async function getShipment(params: GetShipmentParams, options?: RequestOptions): Promise<Shipment>
export async function listShipments(params: ListShipmentsParams = {}, options?: RequestOptions): Promise<ShipmentPage>
export async function getAccount(options?: RequestOptions): Promise<Account>
- Parameters of all locations (path, query, header, cookie) are properties of one
...Paramsobject, under their names in the document (params["If-Match"]). A name used in two locations gets the location as a prefix for the second one (queryId).Accept,Content-TypeandAuthorizationheader parameters are left out. When no parameter is required, the object defaults to{}. - Serialization follows each parameter’s
styleandexplode:simple,labelandmatrixpath parameters;form,spaceDelimited,pipeDelimitedanddeepObjectquery parameters. Values that areundefinedornullare not sent;Datevalues are sent in ISO 8601 form. - The request body is the
bodyproperty of the params (requestBodywhen a parameter is already namedbody). An operation with several request media types gets one: JSON first, thenapplication/x-www-form-urlencoded,multipart/form-data,text/*, and other types. JSON bodies are typed by their schema and sent withJSON.stringify; form bodies are objects (orURLSearchParams), multipart bodiesFormData, text bodiesstring, and other media typesBlob. - The result is the body of the success response (
2XX, ordefaultwhen no success response is documented): its schema’s type for JSON,stringfortext/*,Blobfor other media types. Several success responses give a union (Promise<Shipment | Job>), and a response without content addsundefined; an operation whose responses have no content returnsPromise<void>. TheAcceptheader is set from the media type of the response. - Security is the operation’s requirements, or the document’s when the operation declares none. Before the request is sent, the first alternative whose credentials are all configured is applied; when none is, the request goes out without credentials.
Types
Component schemas become exported interfaces (plain objects) or type aliases, named in Pascal case
(user_profile becomes UserProfile, x-apigenie.codegen.name overrides the name):
| Schema | TypeScript |
|---|---|
| object with properties | interface; optional properties are marked ?, deprecated ones @deprecated |
additionalProperties |
Record<string, T>, or an index signature next to properties |
enum, const |
union of literals ("available" | "sold", 1 | 2 | 3) |
oneOf, anyOf |
union (Circle | Square) |
allOf |
intersection (Shape & { name?: string }) |
prefixItems |
tuple ([number, number]) |
type: [T, "null"], OpenAPI 3.0 nullable: true |
T | null |
format: binary string |
Blob |
other strings, date-time included |
string |
integer, number |
number |
{} |
unknown |
Recursive schemas refer to themselves (children?: Tree[]). The client doesn’t validate values
against their schemas: constraints such as minimum, pattern or if/then/else generate no
code.
Authentication
AuthCredentials has an optional property per security scheme of the document. A credential is
a string, or a function returning a string or a promise of one, called before every request that
needs it (to refresh tokens).
| Scheme | Sent as |
|---|---|
apiKey |
the header, query parameter or cookie the scheme names |
http with scheme: basic |
Authorization: Basic ..., the credential being user:password |
http with scheme: bearer |
Authorization: Bearer <credential> |
other http schemes |
Authorization: <scheme> <credential> |
oauth2, openIdConnect |
Authorization: Bearer <credential> |
The client implements no OAuth 2.0 flow: it sends the access token you supply.
Errors
Every failure is an ApiError (a subclass of Error) with:
| Property | Value |
|---|---|
status |
the HTTP status, or 0 when no response was received |
body |
the response body: parsed JSON for JSON media types, otherwise text, undefined when empty |
response |
the Response, when there was one |
cause |
the underlying error, e.g. a network error or a SyntaxError of invalid JSON |
A response with a status outside 200-299 throws, as do a network failure, a missing base URL or path parameter, and a success response whose JSON can’t be parsed.
Extensions
| Extension | Effect |
|---|---|
x-apigenie.codegen.name |
name of the type of a component schema |
x-apigenie.codegen.action-name |
name of the function of an operation, when action_naming lists extension |
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.
fetch.overlay.yaml:
overlay: 1.0.0
info:
title: TypeScript names
version: 1.0.0
actions:
- target: $.components.schemas.Pet
update:
x-apigenie:
codegen:
name: Animal
apigenie-generator client fetch openapi.yaml --overlay fetch.overlay.yaml -o out
Limitations
From the codegen conformance suite:
- Operation-level and path-level
serversare ignored: every request goes to the base URL. x-internalis not honoured: such operations are part of the client.- A parameter described with
contentinstead ofschemais serialized with theformstyle, not as JSON. - One request media type is generated per operation, so an operation accepting both
application/merge-patch+jsonandapplication/json-patch+jsoncan send only the first. - Streaming responses (
text/event-stream,application/jsonl) are read as one JSON value;itemSchemais not used. - Form-encoded bodies don’t apply the
encodingstyles of their properties: an object property is sent as[object Object]. - Callbacks, webhooks and links aren’t generated: they describe requests the server makes, or documentation.
- Swagger 2.0 documents are not read; convert them with
apigenie convert. Documents referencing other files must be bundled first withapigenie bundle.
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_fetch.overlay in the configuration file (with paths relative
to it). Warnings and errors about a value an overlay set point to the overlay.
–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
Required. Directory where the client is generated.
–package-name
Name of the npm package in package.json. Defaults to the document’s info.title in lower case
with hyphens between words (Carpet Express Shipping API becomes carpet-express-shipping-api),
or api-client when the title has no letters or digits.
–package-version
Version of the npm package in package.json. Defaults to the document’s info.version, or
0.0.0 when it is empty.
Configuration
version: '1.0'
commands:
generate:
client_fetch:
layout: sources
import_extension: ''
action_naming: [id, extension, url]
| Option | Type | Default | Description |
|---|---|---|---|
layout |
package or sources |
package |
package writes an npm package (package.json, tsconfig.json, sources in src/); sources writes only the sources, directly in the output directory. |
import_extension |
.js or '' |
.js |
Extension of relative imports between the generated files: .js for Node.js ES modules (NodeNext resolution), '' for bundlers. |
action_naming |
id, extension, url, or a list of them |
[id, url] |
Where function names come from, in order of preference: the operationId, the x-apigenie.codegen.action-name extension, or the method and path. |