import { InstallTabs } from '@site/src/components/InstallTabs';

# Open API

## Installation

Much like the other packages, `@ts-rest/open-api` is easy to download, also note if you want to serve a Swagger UI you'll want to download `swagger-ui-express` for express, or `@nestjs/swagger ` for Nest.

<InstallTabs packageName="@ts-rest/open-api" />

## Generating a OpenAPI Document

```typescript
import { myContract } from './my-api';
import { generateOpenApi } from '@ts-rest/open-api';

const openApiDocument = generateOpenApi(myContract, {
  info: {
    title: 'Posts API',
    version: '1.0.0',
  },
});
```

No kidding, that's it 🥳 You can now serve this document however you want, use it for CodeGen for your non-TS clients, or use it to generate a Swagger UI!

:::info
Our OpenAPI generator uses `@anatine/zod-openapi` to generate open-api docs for your Zod schemas, so make sure to use Zod everywhere on your API to get the best experience.
:::

## Serving a Swagger UI

In Express use `swagger-ui-express`:

```typescript
import { myContract } from './my-api';
import { generateOpenApi } from '@ts-rest/open-api';
import * as swaggerUi from 'swagger-ui-express';

const openApiDocument = generateOpenApi(myContract, {
  info: {
    title: 'Posts API',
    version: '1.0.0',
  },
});

app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(openApiDocument));
```

In NestJS use `@nestjs/swagger`:

```typescript
import { myContract } from './my-api';
import { generateOpenApi } from '@ts-rest/open-api';
import { NestFactory } from '@nestjs/core';
import { SwaggerModule } from '@nestjs/swagger';
import { AppModule } from './app.module';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);

  const document = generateOpenApi(myContract, {
    info: {
      title: 'Posts API',
      version: '1.0.0',
    },
  });

  SwaggerModule.setup('api', app, document);
  //                   ^ Path for swagger

  await app.listen(3000);
}
bootstrap();
```

Don't worry if you don't use express or Nest, whatever library you want to use is OK our OpenAPI returns a plain JSON object which is fully compliant with the OpenAPI spec.

## Enabling `operationId`'s (Recommended!)

If your contract has unique names for all of your endpoints, you can enable `operationId`'s by setting `setOperationId` to `true` in the options:

```typescript
const openApiSchema = generateOpenApi(
  postsApi,
  {
    info: {
      title: 'Posts API',
      version: '1.0.0',
    },
  },
  {
    setOperationId: true,
  }
);
```

Below is an example of what the OpenAPI document would look like with `operationId`'s enabled:

```typescript
{
  "openapi": "3.0.2",
  "paths": {
    "/posts": {
      "get": {
        "description": "Get all posts",
        "tags": [],
        "parameters": [
          {
            "name": "userId",
            "in": "query",
            "schema": {
              "type": "number"
            }
          }
        ],
        "operationId": "getPosts", // <--- This is the operationId
        "responses": {
```

## JSON Query Params

If you've enabled JSON Query params for your server and client, you can enable `jsonQuery` to mark the query params as `application/json` in the OpenAPI document:

```typescript
const openApiSchema = generateOpenApi(
  postsApi,
  {
    info: {
      title: 'Posts API',
      version: '1.0.0',
    },
  },
  {
    jsonQuery: true,
  }
);
```

You'll want to do this to let your non ts-rest clients know that they should send the query params as JSON.
