Ir para o conteúdo principal

API Routes

Analog supports defining API routes that can be used to serve data to the application.

Defining an API Route

API routes are defined in the src/server/routes/api folder. API routes are also filesystem based, and are exposed under the default /api prefix.

import { defineHandler } from 'h3';

export default defineHandler(() => ({ message: 'Hello World' }));

Defining XML Content

To create an RSS feed for your site, set the content-type to be text/xml and Analog serves up the correct content type for the route.

//server/routes/api/rss.xml.ts

import { defineHandler } from 'h3';

export default defineHandler((event) => {
const feedString = `<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
</rss>
`;
event.res.headers.set('content-type', 'text/xml');
return feedString;
});

Note: For SSG content, set Analog to prerender an API route to make it available as prerendered content:

// vite.config.ts
...
prerender: {
routes: async () => {
return [
...
'/api/rss.xml',
...
.
];
},
sitemap: {
host: 'https://analog-blog.netlify.app',
},
},

The XML is available as a static XML document at /dist/analog/public/api/rss.xml

Dynamic API Routes

Dynamic API routes are defined by using the filename as the route path enclosed in square brackets. Parameters can be accessed via event.context.params.

// /server/routes/api/v1/hello/[name].ts
import { defineHandler } from 'h3';

export default defineHandler(
(event) => `Hello ${event.context.params?.['name']}!`,
);

Another way to access route parameters is by reading them from event.context.params inside the handler.

// /server/routes/api/v1/hello/[name].ts
import { defineHandler } from 'h3';

export default defineHandler((event) => {
const name = event.context.params?.['name'] ?? 'friend';
return `Hello, ${name}!`;
});

Specific HTTP request method

File names can be suffixed with .get, .post, .put, .delete, etc. to match the specific HTTP request method.

GET

// /server/routes/api/v1/users/[id].get.ts
import { defineHandler } from 'h3';

export default defineHandler(async (event) => {
const id = event.context.params?.['id'];
// TODO: fetch user by id
return `User profile of ${id}!`;
});

POST

// /server/routes/api/v1/users.post.ts
import { defineHandler } from 'h3';

export default defineHandler(async (event) => {
const body = await event.req.json();
// TODO: Handle body and add user
return { updated: true };
});

The h3 JSDocs provide more info and utilities for headers, cookies, redirects, and more.

Requests with Query Parameters

Sample query /api/v1/query?param1=Analog&param2=Angular

// routes/api/v1/query.ts
import { defineHandler } from 'h3';

export default defineHandler((event) => {
const param1 = event.url.searchParams.get('param1');
const param2 = event.url.searchParams.get('param2');

return `Hello, ${param1} and ${param2}!`;
});

Validated API Routes

For route handlers that need runtime validation and typed inputs, use defineApiRoute() from @analogjs/router/server/actions. It can validate route params, query strings, request bodies, and response payloads with any Standard Schema-compatible library.

// src/server/routes/api/v1/users/[id].put.ts
import { defineApiRoute } from '@analogjs/router/server/actions';
import * as v from 'valibot';

export default defineApiRoute({
params: v.object({
id: v.pipe(
v.string(),
v.transform((value) => Number(value)),
),
}),
body: v.object({
name: v.pipe(v.string(), v.minLength(1)),
}),
handler: async ({ params, body }) => {
return updateUser(params.id, body.name);
},
});

For the full validation guide, including server actions, content frontmatter, and Standard Schema examples, see Schema Validation.

Catch-all Routes

Catch-all routes are helpful for fallback route handling.

// routes/api/[...].ts
import { defineHandler } from 'h3';

export default defineHandler(() => `Default page`);

Error Handling

If no errors are thrown, a status code of 200 OK will be returned. Any uncaught errors will return a 500 Internal Server Error HTTP Error. To return other error codes, throw an exception with createError.

// routes/api/v1/[id].ts
import { createError, defineHandler } from 'h3';

export default defineHandler((event) => {
const param = event.context.params?.['id'];
const id = Number.parseInt(param ?? '', 10);

if (!Number.isInteger(id)) {
throw createError({
statusCode: 400,
statusMessage: 'ID should be an integer',
});
}
return `ID is ${id}`;
});

Accessing Cookies

Analog allows setting and reading cookies in your server-side calls.

Setting cookies

//(home).server.ts
import { PageServerLoad } from '@analogjs/router';
import { setCookie } from 'h3';

import { Product } from '../products';

export const load = async ({ fetch, event }: PageServerLoad) => {
setCookie(event, 'products', 'loaded', {
path: '/',
});
const products = await fetch<Product[]>('/api/v1/products');

return {
products: products,
};
};

Reading cookies

//index.server.ts
import { PageServerLoad } from '@analogjs/router';
import { getCookie } from 'h3';

export const load = async ({ event }: PageServerLoad) => {
const productsCookie = getCookie(event, 'products');

console.log('products cookie', productsCookie);

return {
shipping: true,
};
};

More Info

API routes are powered by Nitro and h3. See the Nitro and h3 docs for more examples around building API routes.