Skip to content
This repository has been archived by the owner on Apr 6, 2023. It is now read-only.

docs: add server routes documentation #4174

Merged
merged 18 commits into from
Apr 9, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 0 additions & 7 deletions docs/content/2.guide/2.features/9.api-routes.md

This file was deleted.

173 changes: 173 additions & 0 deletions docs/content/2.guide/2.features/9.server-routes.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
# Server Routes

Nuxt automatically scans files inside the `~/server/api`, `~/server/routes`, and `~/server/middleware` directories to register API and server handlers with HMR support.

Each file should export a default function defined with `defineEventHandler()`.

The handler can directly return JSON data, a `Promise` or use `event.res.end()` to send response.

::ReadMore{link="https://nitro.unjs.io/guide/routing.html" title="Nitro Route Handling Docs"}
::

## Usage Example

Create a new file in `server/api/hello.ts`:

```ts [/server/api/hello.ts]
export default defineEventHandler((event) => {
return {
api: 'works'
}
})
```

You can now universally call this API using `await $fetch('/API/hello')`.

## Server Routes

Files inside the `~/server/api` are automatically prefixed with `/api` in their route.
For adding server routes without `/api` prefix, you can instead put them into `~/server/routes` directory.

**Example:**

```ts [/server/routes/hello.ts]
export default defineEventHandler(() => 'Hello World!')
```

Given the Example above, the `/hello` route will be accessible at <http://localhost:3000/hello>.

## Server Middleware

Nuxt will automatically read in any file in the `~/server/middleware` to create server middleware for your project.

Middleware handlers will run on every request before any other server route to add check and some headers, log requests, or extend the event's request object.

::alert{type=warning}
Middleware handlers should not return anything (nor close or respond to the request) and only inspect or extend the request context or throw an error.
::

**Examples:**

```ts [/server/middleware/log.ts]
export default defineEventHandler((event) => {
console.log('New request: ' + event.req.url)
})
```

```ts [/server/middleware/auth.ts]
export default defineEventHandler((event) => {
event.context.auth = { user: 123 }
})
```

## Matching Route Parameters

Server routes can use dynamic parameters within brackets in the file name like `/api/hello/[:name].ts` and accessed via `event.context.params`.

**Example:**

```ts [/server/api/hello/[name].ts]
export default defineEventHandler(event => `Hello, ${event.context.params.name}!`)
```

You can now universally call this API using `await $fetch('/API/hello/nuxt')` and get `Hello, nuxt!`.

## Matching HTTP Method

Handle file names can be suffixed with `.get`, `.post`, `.put`, `.delete`, ... to match request's [HTTP Method](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods).

```ts [/server/api/test.get.ts]
export default defineEventHandler(() => 'Test get handler')
```

```ts [/server/api/test.post.ts]
export default defineEventHandler(() => 'Test post handler')
```

Given the Example above, fetching `/test` with:

- **GET** method: Returns `Test get handler`
- **POST** method: Returns `Test post handler`
- Any other method: Returns 404 error

## Catch-all route

Catch-all routes are helpful for fallback route handling. For Example, creating a file in the `~/server/api/foo/[...].ts` will register a catch-all route for all requests that do not match any route handler, such as `/api/foo/bar/baz`.

**Examples:**

```ts [/server/api/foo/[...].ts]
export default defineEventHandler(() => `Default foo handler`)
```

```ts [/server/api/[...].ts]
export default defineEventHandler(() => `Default api handler`)
```

## Handling Requests with Body

```ts [/server/api/submit.post.ts]
export default defineEventHandler(async (event) => {
const body = await useBody(event)
return { body }
})
```

You can now universally call this API using `$fetch('/api/submit', { method: 'post', body: { test: 123 } })`.

::alert{type=warning title=Attention}
We are using `submit.post.ts` in the filename only to match requests with `POST` method that can accept the request body. When using `useBody` within a GET request, `useBody` will throw a `405 Method Not Allowed` HTTP error.
::

## Access Request Cookies

```ts
export default defineEventHandler((event) => {
const cookies = useCookies(event)
return { cookies }
})
```

## Using a nested router

```ts [/server/api/hello.ts]
import { createRouter } from 'h3'

const router = createRouter()

router.get('/', () => 'Hello World')

export default router
```

## Return a legacy handler or middleware

```ts [/server/api/legacy.ts]
export default (req, res) => {
res.end('Legacy handler')
}
```

::alert{type=warning}
Legacy support is possible using [unjs/h3](https://github.com/unjs/h3) but it adviced to avoid legacy handlers as much as you can.
::

```ts [/server/middleware/legacy.ts]
export default (req, res, next) => {
console.log('Legacy middleware')
next()
}
```

::alert{type=warning}
Never combine `next()` callback with a legacy middleware that is `async` or returns a `Promise`!
::

## Server Utils

Server routes are powered by [unjs/h3](https://github.com/unjs/h3) which comes with a handy set of helpers.

::ReadMore{link="https://www.jsdocs.io/package/h3#package-index-functions" title="Available H3 Request Helpers"}
::

You can add more helpers by yourself inside the `~/server/utils` directory.
102 changes: 1 addition & 101 deletions docs/content/2.guide/3.directory-structure/13.server.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,104 +4,4 @@ title: server
head.title: Server directory
---

# Server directory

Nuxt uses the `server/` directory to create any backend logic for your application. It supports HMR and powerful features.

TheΒ `server/`Β directory contains API endpoints and server middleware for your project.

## API Routes

Nuxt will automatically read in any files in theΒ `~/server/api`Β directory to create API endpoints.

Each file should export a default function that handles API requests. It can return a promise or JSON data directly (or use `res.end()`).

### Examples

#### Hello world

```js [server/api/hello.ts]
export default (req, res) => 'Hello World'
```

See the result on <http://localhost:3000/api/hello>.

#### Async function

```js [server/api/async.ts]
export default async (req, res) => {
await someAsyncFunction()

return {
someData: true
}
}
```

**Example:** Using Node.js style

```ts [server/api/node.ts]
import type { IncomingMessage, ServerResponse } from 'http'

export default async (req: IncomingMessage, res: ServerResponse) => {
res.statusCode = 200
res.end('Works!')
}
```

#### Accessing req data

```js
import { useBody, useCookies, useQuery } from 'h3'

export default async (req, res) => {
const query = useQuery(req)
const body = await useBody(req) // only for POST | PUT | PATCH | DELETE requests
const cookies = useCookies(req)

return { query, body, cookies }
}
```

Learn more about [h3 methods](https://www.jsdocs.io/package/h3#package-index-functions).

## Server Middleware

Nuxt will automatically read in any files in theΒ `~/server/middleware`Β to create server middleware for your project.

These files will be run on every request, unlike [API routes](#api-routes) that are mapped to their own routes. This is typically so you can add a common header to all responses, log responses or modify the incoming request object for later use in the request chain.

Each file should export a default function that will handle a request.

```js
export default async (req, res) => {
req.someValue = true
}
```

There is nothing different about the `req`/`res` objects, so typing them is straightforward.

```ts
import type { IncomingMessage, ServerResponse } from 'http'

export default async (req: IncomingMessage, res: ServerResponse) => {
req.someValue = true
}
```

To pass the request deeper into the application, you can `return` inside the function:

```js
export default async (req, res) => {
const isNotHandledByThisMiddleware = req.url.includes('/some-unhandled-url-path/')
if(isNotHandledByThisMiddleware) {
return
}

// Actual logic here
}
```

::alert{type=info icon=πŸ”Ž}
Find more information about custom middleware in the documentation for [nuxt.config.js](/guide/directory-structure/nuxt.config#servermiddleware)
::
::ReadMore{link="/guide/features/server-routes"}