apigenie-generatorOpenAPI serversserver orpc

server orpc

Generate a TypeScript server based on oRPC from an OpenAPI document.

Usage

apigenie-generator server orpc [...OPTIONS] INPUT_FILE

Description

The input must be an OpenAPI 3.0, 3.1 or 3.2 document; convert Swagger 2.0 documents with apigenie convert, and bundle documents referencing other files with apigenie bundle.

Every operation becomes an oRPC procedure, with Zod (v4) schemas validating its input and output. The generated npm package contains:

File Content
src/schemas.ts Zod schemas, with their types, of the components, bodies, inputs and outputs
src/contract/<group>.ts the contract of each procedure: route, input, output and errors
src/contract/index.ts the contract router, by group
src/handlers/<group>.ts a handler per procedure, throwing NOT_IMPLEMENTED
src/orpc.ts the context of the procedures and implement(contract)
src/router.ts the router assembling the handlers
src/server.ts a Node.js HTTP server with oRPC’s OpenAPIHandler
src/main.ts starts the server on the port in PORT (3000 by default)
src/index.ts exports of the package

Procedures are grouped by the first tag of their operations, or the first segment of their paths, and named after their operationIds.

The handlers, orpc.ts, server.ts, main.ts, package.json and tsconfig.json are meant to be edited, and are only written when they don’t exist. Regenerating updates the schemas, the contract and the router; the TypeScript compiler then reports the handlers that new operations need.

apigenie-generator server orpc openapi.yaml -o server
cd server && npm install && npm run dev

The server answers the operations under the path of the first server of the document (e.g. /v1), and serves its OpenAPI document at /spec.json and an API reference at /. Operations with servers of their own (operation or path item servers) with another path, e.g. a health check on the root of a status host, are also answered at that path.

Inputs and outputs

A procedure receives the path parameters merged with the query parameters (GET) or the body (other methods), oRPC’s compact input structure, unless that would lose part of the request: operations with header or cookie parameters, query parameters in other methods than GET, or bodies which can’t be merged with the path parameters get the detailed structure, with params, query, headers (in lower case) and body. Parameters are converted from strings to the types of their schemas, and array parameters accept repeated values, a single value, and the delimited values of the form (with explode: false), spaceDelimited and pipeDelimited styles. Cookie parameters are read from the Cookie header (headers.cookie), parameters described by content: application/json are parsed as JSON, and a path segment of several parameters, such as /labels/{labelId}.{extension}, is routed as one parameter and split into its parameters.

The body is read in any of the operation’s media types:

  • JSON bodies, including other JSON media types such as application/merge-patch+json, which the server parses before oRPC, and JSON Lines, which the procedure receives as an array;
  • application/x-www-form-urlencoded and multipart/form-data bodies, whose fields are converted to the types of their schemas (an empty field is null where the schema allows it) and whose binary parts are Files;
  • text/plain bodies as strings, other text and binary bodies as Files.

A procedure returns the body of its response. When an operation has success responses with different bodies, or response headers, it returns { status, headers, body } objects instead. JSON bodies are objects; other bodies (text, files) are Blobs, which the server sends with their media type. A text/event-stream response is an eventIterator() of its itemSchema (the contentSchema of the events’ data, or the item of the operation’s JSON Lines response); when the operation also answers JSON, the handler returns either a value or an async iterator, as the client accepts. The writeOnly properties of a response are left out of what the server sends, and the readOnly properties of a request out of what the handler receives.

A oneOf with a discriminator and a defaultMapping (x-defaultMapping in 3.0 and 3.1 documents) validates the option its property selects, or the default one; closed allOf compositions (unevaluatedProperties: false) reject properties none of their schemas declare.

Each 4xx and 5xx response becomes an error of the procedure: NOT_FOUND, CONFLICT and the other codes of oRPC, or HTTP_<status> for other statuses. 4XX and 5XX ranges become the errors of their first status (BAD_REQUEST, INTERNAL_SERVER_ERROR), and a default response next to success responses INTERNAL_SERVER_ERROR, unless the document declares those statuses. Their response bodies are their data, which the server sends as the body of the response:

throw errors.NOT_FOUND({ data: { code: 404, message: "No such pet" } });

Not supported, and reported as warnings: path parameters in other styles than simple, object query parameters in the form style (read in the deepObject style), and operations with other methods than GET, POST, PUT, DELETE, PATCH and HEAD (QUERY is routed with oRPC 2), which are skipped. oRPC describes the procedures a server answers, not the requests it sends, so callbacks and webhooks are not generated; it streams async iterators as server-sent events only, so a JSON Lines response is answered as a Blob the handler builds.

Extensions

Extension Effect
x-apigenie.codegen.name name of the schema and type of a component schema (AnimalSchema, Animal)
x-apigenie.codegen.action-name name of the procedure of an operation, when action_naming lists extension

The extensions can live in an overlay for this target instead of in the document, e.g. orpc.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 server orpc openapi.yaml --overlay orpc.overlay.yaml -o out

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.server_orpc.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

Directory where the package is generated.

–package-name

Name of the package, <title>-server by default.

–package-version

Version of the package, the version of the API by default.

Configuration

version: '1.0'
commands:
  generate:
    server_orpc:
      orpc_version: 1
      input_structure: auto
Option Description
orpc_version 1 (default) for oRPC 1, 2 for oRPC 2 (beta): routes declared with oc.meta(openapi(...)) and queryStyles
input_structure auto (default), compact (header parameters, and query parameters of other methods than GET, are dropped) or detailed
layout package (default) for an npm package, sources for the sources only
import_extension extension of relative imports: .js (default, Node.js) or "" (bundlers)
action_naming sources of procedure names, in order: id (operationId), extension (x-apigenie), url; [id, url] by default
additional_properties loose (default) keeps the properties of objects their schemas don’t list, strip removes them
describe true attaches the descriptions of schemas with .describe() (default: false)