fresh — это современный фреймворк для разработки
приложений на базе Deno, ориентированный на максимальную
производительность и реактивность. Одной из ключевых возможностей
является работа с API-маршрутами, позволяющая создавать
серверные эндпоинты для обработки запросов.
В fresh каждый маршрут API создаётся как отдельный файл
в директории routes. Структура проекта может выглядеть
следующим образом:
/routes
├─ api/
│ ├─ users.ts
│ └─ products.ts
└─ index.tsx
Файлы внутри папки api автоматически интерпретируются
как серверные обработчики, где имя файла соответствует пути маршрута.
Например, routes/api/users.ts будет доступен по URL
/api/users.
Маршрут API в fresh представляет собой экспорт
функций, соответствующих HTTP-методам:
import { Handlers } from "$fresh/server.ts";
export const handler: Handlers = {
async GET(req, ctx) {
return new Response(JSON.stringify({ message: "GET запрос получен" }), {
headers: { "Content-Type": "application/json" },
});
},
async POST(req, ctx) {
const data = await req.json();
return new Response(JSON.stringify({ received: data }), {
headers: { "Content-Type": "application/json" },
});
},
};
req — объект запроса, предоставляет доступ к
параметрам, телу и заголовкам.ctx — контекст запроса, включающий параметры маршрута и
другие данные.Параметры маршрута задаются с помощью квадратных скобок в имени
файла. Например, маршрут для пользователя по id:
routes/api/users/[id].ts
Доступ к параметру осуществляется через объект
ctx.params:
export const handler: Handlers = {
GET(_req, ctx) {
const { id } = ctx.params;
return new Response(JSON.stringify({ userId: id }), {
headers: { "Content-Type": "application/json" },
});
},
};
Query-параметры извлекаются через URL из объекта
Request:
export const handler: Handlers = {
GET(req) {
const url = new URL(req.url);
const page = url.searchParams.get("page") || "1";
return new Response(JSON.stringify({ page }), {
headers: { "Content-Type": "application/json" },
});
},
};
Маршруты API позволяют работать с асинхронными операциями, включая запросы к базе данных:
import { getUserById } from "../. ./db/users.ts";
export const handler: Handlers = {
async GET(_req, ctx) {
const { id } = ctx.params;
const user = await getUserById(id);
if (!user) {
return new Response(JSON.stringify({ error: "Пользователь не найден" }), { status: 404 });
}
return new Response(JSON.stringify(user), {
headers: { "Content-Type": "application/json" },
});
},
};
Ключевые моменты:
Response.В fresh можно реализовать промежуточные функции для
обработки аутентификации или логирования:
export const handler: Handlers = {
async GET(req, ctx) {
if (!req.headers.get("Authorization")) {
return new Response(JSON.stringify({ error: "Не авторизован" }), { status: 401 });
}
return new Response(JSON.stringify({ message: "Доступ разрешён" }), {
headers: { "Content-Type": "application/json" },
});
},
};
Middleware не требует отдельного файла — достаточно встроить проверки в обработчик. Для сложных сценариев можно создавать отдельные функции для повторного использования.
Все маршруты API в fresh ориентированы на работу с
REST-подходом и JSON. Форматирование ответа обязательно
должно содержать заголовок:
headers: { "Content-Type": "application/json" }
Это обеспечивает корректное взаимодействие с фронтенд-приложением или внешними сервисами.
С помощью файлов [param].ts и [...rest].ts
можно реализовать динамическую маршрутизацию и вложенные пути:
[id].ts — захват одного сегмента пути.[...path].ts — захват всех оставшихся сегментов,
полезно для маршрутов типа /api/files/*.Для внешних API важно правильно настроить CORS:
export const handler: Handlers = {
GET(_req) {
return new Response(JSON.stringify({ message: "CORS включён" }), {
headers: {
"Content-Type": "application/json",
"Access-Control-Allow-Origin": "*",
},
});
},
};
Это позволяет делать запросы к API с других доменов без ошибок браузера.
API-маршруты в fresh можно тестировать с помощью:
fetch, Postman,
curl.Пример теста на GET-запрос:
import { assertEquals } from "https://deno.land/std/testing/asserts.ts";
import { handler } from "./users.ts";
Deno.test("GET /api/users returns status 200", async () => {
const req = new Request("http://localhost/api/users");
const resp = await handler.GET(req, {} as any);
assertEquals(resp.status, 200);
});
Тесты помогают убедиться, что маршруты корректно обрабатывают запросы и возвращают ожидаемый формат данных.
Встроенные методы HTTP позволяют возвращать корректные коды ошибок:
400 Bad Request — некорректные данные.401 Unauthorized — отсутствует авторизация.404 Not Found — ресурс не найден.500 Internal Server Error — внутренняя ошибка
сервера.Пример обработки с try/catch:
export const handler: Handlers = {
async GET(_req) {
try {
const data = await fetchData();
return new Response(JSON.stringify(data), { headers: { "Content-Type": "application/json" } });
} catch (err) {
return new Response(JSON.stringify({ error: err.message }), { status: 500 });
}
},
};
Cache-Control.Маршруты API в fresh обеспечивают высокую
производительность, гибкость и простоту интеграции с современными
фронтенд-фреймворками.