# Generate a client and a server

Source: https://apigenie.pl/docs/guides/generate-a-client-and-a-server

This guide generates both sides of an API from its OpenAPI document, `openapi.yaml`: a TypeScript
client for the Fetch API and an Express server. The same steps work for the other targets of
[`apigenie-generator`](/docs/reference/generator), in Java, Go, Python, C# and Elixir, and for
AsyncAPI, GraphQL and Protobuf documents.

You need the CLI installed; the [Quickstart](/docs/quickstart) shows how. Lint the document first
([Lint and format API descriptions](/docs/guides/lint-and-format-api-descriptions)): a clean
contract gives cleaner code.

## Generate the client

```sh
apigenie-generator client fetch openapi.yaml -o client --package-name shipping-client
```

The output is an npm package with no runtime dependencies: requests go through the global
`fetch()`, so the client runs in browsers and in Node.js 18 or later. Each operation is an `async`
function named after its `operationId`, with its parameters and its result typed from the document:

```ts
import { configure, ApiError, listShipments, getShipment } from "shipping-client";

configure({
  baseUrl: "https://api.example.com/v2",
  auth: { apiKey: "ce_live_123" },
});

try {
  const page = await listShipments({ status: ["in_transit"], limit: 20 });
  const shipment = await getShipment({ shipmentId: "shp_01J9Z" });
} catch (error) {
  if (error instanceof ApiError) {
    console.error(error.status, error.body);
  }
}
```

To compile the client as part of your own project instead of as a package, set `layout: sources`
for `client_fetch` in the configuration (see [Configure the generators](#configure-the-generators)
below): the generator then writes only the sources.

## Generate the server

```sh
apigenie-generator server express openapi.yaml -o server --package-name shipping-server
```

The generator writes typed handler interfaces and a router that decodes and validates every
request. Your code implements the handlers in files of its own, so regenerating never overwrites it:

```ts
import express from "express";
import { BASE_PATH, createRouter, HttpError, type ShipmentsHandlers } from "shipping-server";

const shipments: Partial<ShipmentsHandlers> = {
  async getShipment(request) {
    const shipment = await db.shipments.find(request.params.shipmentId);
    if (shipment === undefined) {
      throw new HttpError(404, "No such shipment");
    }
    return { status: 200, body: shipment };
  },
};

const app = express();
app.use(BASE_PATH, createRouter({ shipments }));
app.listen(8080);
```

Operations are grouped by their first tag (`ShipmentsHandlers`), and the status, body and headers
a handler returns are typed per status from the document. A change to the contract that the
handlers don't follow is a compile error.

## Configure the generators

Generator settings go in the `commands.generate` section of `apigenie.yaml`, one entry per target,
so the command lines stay short and the settings are reviewed like code. Here the client's imports
suit a bundler, and an overlay adjusts the document for the server:

```yaml
version: '1.0'
commands:
  generate:
    client_fetch:
      import_extension: ''
    server_express:
      overlay:
        - overlays/express.overlay.yaml
```

Each target's page lists its settings and the vendor extensions it reads, such as
[client fetch](/docs/reference/generator/client-fetch) and
[server express](/docs/reference/generator/server-express). Extensions that matter to one generator
only can live in an [OpenAPI Overlay](/docs/reference/cli/overlay) of that generator, listed under
`overlay` or given with `--overlay`, instead of in the API description.

## Regenerate in CI

Generate into the repository and let CI check that the generated code matches the contract, so
nobody edits it by hand and nobody forgets to regenerate:

```sh
apigenie-generator client fetch openapi.yaml -o client --package-name shipping-client
apigenie-generator server express openapi.yaml -o server --package-name shipping-server
git diff --exit-code client server
```

Once the server runs, check that it keeps the contract with a validating proxy:
[Mock and contract-test an API](/docs/guides/mock-and-contract-test-an-api).

## Next steps

- [apigenie-generator](/docs/reference/generator): every target, by standard.
- [Overlays](/docs/reference/generator#overlays): settings outside the API description.
- [Generate code](/use-cases/code-generation): what the generator covers.
