# Express Endpoints quickstart

Create and call an Astro API route with Express-style request and response helpers.

Source: https://withastro-utils.github.io/docs/guides/express-endpoints/

Use Express-style routing and middleware in an Astro API endpoint. This example accepts JSON and returns a greeting.

## Install the package and adapter

```sh title="Terminal"
npm install @astro-utils/express-endpoints @astrojs/node
```

```sh title="Terminal"
pnpm add @astro-utils/express-endpoints @astrojs/node
```

```sh title="Terminal"
yarn add @astro-utils/express-endpoints @astrojs/node
```

```sh title="Terminal"
bun add @astro-utils/express-endpoints @astrojs/node
```

## Enable server rendering

```js title="astro.config.mjs"
import { defineConfig } from 'astro/config';
import node from '@astrojs/node';

export default defineConfig({ 
    output: 'server', 
    adapter: node({ mode: 'standalone' }) 
});
```

## Create a route

```ts title="src/pages/api/hello.ts"
import { ExpressRoute } from '@astro-utils/express-endpoints';

const router = new ExpressRoute();

router.body('json');

export const POST = router.route((req, res) => {
    const name = typeof req.body?.name === 'string' ? req.body.name.trim() : '';
    if (!name) {
        res.status(400).json({ error: 'Name is required.' });
        return;
    }
    res.json({ message: `Hello, ${name}!` });
});
```

## Call it

Start your project with its `dev` script. Use the port printed by Astro in this request:

```sh title="Terminal"
curl -X POST http://localhost:4321/api/hello \
    -H 'Content-Type: application/json' \
    -d '{"name":"Alex"}'
```

The response is `{"message":"Hello, Alex!"}`. Sending `{}` returns status 400 and `{"error":"Name is required."}`. The example has no artificial delay or external service dependency.

## Parse a different body

`router.body('multipart')` makes uploaded files available on `req.filesOne` and `req.filesMany`. Use `urlencoded` for an ordinary HTML form or `text` for a text body. 
The default `auto` mode selects the parser from `Content-Type`.

See [request examples](https://withastro-utils.github.io/docs/reference/express/request/index.md) and [response examples](https://withastro-utils.github.io/docs/reference/express/response/index.md).

## Add schema validation

For schema-based validation, install the Zod major version supported by the package's [express-zod-safe](https://www.npmjs.com/package/express-zod-safe) integration:

```sh title="Terminal"
npm install zod@^4
```

```sh title="Terminal"
pnpm add zod@^4
```

```sh title="Terminal"
yarn add zod@^4
```

```sh title="Terminal"
bun add zod@^4
```

```ts title="src/pages/api/validated-hello.ts"
import { ExpressRoute } from '@astro-utils/express-endpoints';
import { z } from 'zod';

const router = new ExpressRoute();

router.validate({ 
    body: z.object({ 
        name: z.string().trim().min(1) 
    })
});

export const POST = router.route((req, res) => {
    res.json({ message: `Hello, ${req.body.name}!` });
});
```

By default, it's relax validation that ignore extra properties, defaults to:
- defaultSchemaObject: lax
- missingSchemaBehavior: any

Validation applies to the next route created by this router. Review [middleware and error handling](https://withastro-utils.github.io/docs/reference/express/router-and-errors/index.md) before composing several handlers.
