Перейти к содержимому

17. API-маршруты (Endpoints)

Astro позволяет создавать серверные API-эндпоинты прямо в папке src/pages/api/. Это полноценные HTTP-обработчики — GET, POST, PUT, DELETE — без отдельного бэкенд-сервера.

Думай об API-маршрутах Astro как о serverless-функциях, встроенных прямо в твой проект: создал файл — получил эндпоинт.


src/pages/api/posts.ts
import type { APIRoute } from 'astro';
export const GET: APIRoute = async ({ request, url, cookies }) => {
const posts = await fetchPosts();
return new Response(JSON.stringify(posts), {
status: 200,
headers: { 'Content-Type': 'application/json' },
});
};
export const POST: APIRoute = async ({ request }) => {
const body = await request.json();
const newPost = await createPost(body);
return new Response(JSON.stringify(newPost), { status: 201 });
};

Astro использует стандартные Web API:

// Request
const url = new URL(request.url);
const params = url.searchParams; // GET-параметры
const body = await request.json(); // JSON-тело
const formData = await request.formData(); // Form data
const headers = request.headers; // Заголовки
// Response
return new Response(JSON.stringify(data), {
status: 200,
headers: {
'Content-Type': 'application/json',
'Cache-Control': 'max-age=3600',
'X-Custom-Header': 'value',
},
});

src/pages/api/posts/[id].ts
export const GET: APIRoute = async ({ params }) => {
const { id } = params;
const post = await getPost(id);
if (!post) {
return new Response(JSON.stringify({ error: 'Not found' }), {
status: 404,
});
}
return new Response(JSON.stringify(post));
};
export const DELETE: APIRoute = async ({ params }) => {
await deletePost(params.id);
return new Response(null, { status: 204 });
};

src/pages/contact.astro
<form method="POST" action="/api/contact">
<input name="email" type="email" />
<textarea name="message"></textarea>
<button type="submit">Отправить</button>
</form>
src/pages/api/contact.ts
export const POST: APIRoute = async ({ request, redirect }) => {
const data = await request.formData();
const email = data.get('email');
const message = data.get('message');
await sendEmail({ email, message });
return redirect('/thanks', 302);
};

src/middleware.ts
export const onRequest = async (context, next) => {
// Проверка API-ключа для /api/* маршрутов
if (context.url.pathname.startsWith('/api/')) {
const apiKey = context.request.headers.get('X-API-Key');
if (apiKey !== import.meta.env.SECRET_API_KEY) {
return new Response(JSON.stringify({ error: 'Unauthorized' }), {
status: 401,
});
}
}
return next();
};

// Хелпер для JSON-ответов
function json(data: unknown, status = 200) {
return new Response(JSON.stringify(data), {
status,
headers: { 'Content-Type': 'application/json' },
});
}
// Использование
export const GET: APIRoute = () => json({ ok: true });
export const POST: APIRoute = async ({ request }) => {
const body = await request.json();
return json({ created: true, id: 42 }, 201);
};