mirror of
https://github.com/nuxt/nuxt.git
synced 2024-11-11 08:33:53 +00:00
docs: add server routes documentation (#4174)
Co-authored-by: pooya parsa <pyapar@gmail.com>
This commit is contained in:
parent
ed4946b06a
commit
529712d498
@ -1,7 +0,0 @@
|
|||||||
# API Routes
|
|
||||||
|
|
||||||
::NeedContribution
|
|
||||||
::
|
|
||||||
|
|
||||||
::ReadMore{link="/guide/directory-structure/server"}
|
|
||||||
::
|
|
173
docs/content/2.guide/2.features/9.server-routes.md
Normal file
173
docs/content/2.guide/2.features/9.server-routes.md
Normal file
@ -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.
|
@ -4,104 +4,4 @@ title: server
|
|||||||
head.title: Server directory
|
head.title: Server directory
|
||||||
---
|
---
|
||||||
|
|
||||||
# Server directory
|
::ReadMore{link="/guide/features/server-routes"}
|
||||||
|
|
||||||
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)
|
|
||||||
::
|
|
||||||
|
Loading…
Reference in New Issue
Block a user