# server orpc

Source: https://apigenie.pl/techdocs/reference/cli-generate_server_orpc

Generate a TypeScript server based on [oRPC](https://orpc.dev) from an OpenAPI document.

## Usage

```sh
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`](/techdocs/reference/cli-convert), and bundle documents referencing other files
with [`apigenie bundle`](/techdocs/reference/cli-bundle).

Every operation becomes an oRPC procedure, with [Zod](https://zod.dev) (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 `operationId`s.

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.

```sh
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 `File`s;
- `text/plain` bodies as strings, other text and binary bodies as `File`s.

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 `Blob`s, 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:

```ts
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`:

```yaml
overlay: 1.0.0
info:
  title: TypeScript names
  version: 1.0.0
actions:
  - target: $.components.schemas.Pet
    update:
      x-apigenie:
        codegen:
          name: Animal
```

```sh
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

```yaml
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`)                                 |
