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

# Express Server

## Installation

<InstallTabs packageName="@ts-rest/express" />

## Usage

```typescript
import { initServer } from '@ts-rest/express';
import { contract } from './contract';

const app = express();
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());

const s = initServer();
const router = s.router(contract, {
  getPost: async ({ params: { id } }) => {
    const post = prisma.post.findUnique({ where: { id } });

    return {
      status: 200,
      body: post ?? null,
    };
  },
});

createExpressEndpoints(contract, router, app);
```

`createExpressEndpoints` is a function that takes a contract, a corresponding router with implementations and middleware for each endpoint, and an express app, and it will
create the corresponding express routes for each endpoint with the correct method, paths, and middleware and attach them to your express app.

## Options

You can pass an optional options object as the last argument for `createExpressEndpoints`.

```typescript
type Options = {
  logInitialization?: boolean; // print route initialization logs to console
  jsonQuery?: boolean;
  responseValidation?: boolean;
  globalMiddleware?: ((req, res, next) => void)[];
  requestValidationErrorHandler?:
    | 'default'
    | 'combined'
    | ((err: RequestValidationError, req, res, next) => void);
};
```

### Response Validation

To enable response parsing and validation, you can use the `validateResponses` option.
If a corresponding response Zod schema is defined in the contract for the returned status code, the response will be parsed and validated.
If validation fails, a `ResponseValidationError` will be thrown, causing a 500 response to be returned.

```typescript
createExpressEndpoints(contract, router, app, {
  responseValidation: true,
});
```

### Request Validation Error Handling

The default functionality of handling request validation errors is to return a 400 response with the first validation error the validator encounters.

You can pass `combined` to the `requestValidationErrorHandler` option to return a 400 response with all validation errors in the body in this form.

```typescript
{
  pathParameterErrors: z.ZodError | null;
  headerErrors: z.ZodError | null;
  queryParameterErrors: z.ZodError | null;
  bodyErrors: z.ZodError | null;
}
```

You can also pass a custom error handler function to the `requestValidationErrorHandler` option.

```typescript
createExpressEndpoints(contract, router, app, {
  requestValidationErrorHandler: (err, req, res, next) => {
    //             err is typed as ^ RequestValidationError
    return res.status(400).json({
      message: 'Validation failed'
    });
  },
});
```
