CRUD
Шість ендпоїнтів створюються як справжні файли, а не впроваджуються у рантаймі.
CRUD — це не рантайм-магія, а згенеровані файли, які можна читати й редагувати. CLI створює два невеликі файли маршрутів на модель; далі фреймворк обслуговує їх як будь-який інший файл маршруту. Нічого не синтезується з прапорця.
hopak generate crud post
# → Created file app/routes/api/posts.ts
# → Created file app/routes/api/posts/[id].ts
Згенеровані файли використовують crud-хелпери з @hopak/core:
// app/routes/api/posts.ts
import { crud } from '@hopak/core';
import post from '../../models/post';
export const GET = crud.list(post);
export const POST = crud.create(post);
// app/routes/api/posts/[id].ts
import { crud } from '@hopak/core';
import post from '../../../models/post';
export const GET = crud.read(post);
export const PUT = crud.update(post);
export const PATCH = crud.patch(post);
export const DELETE = crud.remove(post);
Це вся REST-поверхня. Шість ендпоїнтів під /api/<plural>/:
| Метод | Шлях | Хелпер | Поведінка |
|---|---|---|---|
GET | /api/posts | crud.list(post) | Список із пагінацією |
GET | /api/posts/:id | crud.read(post) | Один рядок, 404 якщо немає |
POST | /api/posts | crud.create(post) | Валідація тіла, створення, 201 |
PUT | /api/posts/:id | crud.update(post) | Повна валідація тіла |
PATCH | /api/posts/:id | crud.patch(post) | Часткова валідація тіла |
DELETE | /api/posts/:id | crud.remove(post) | 204 при успіху, 404 якщо немає |
curl -X POST http://localhost:3000/api/posts \
-H 'content-type: application/json' \
-d '{"title":"Hello Hopak","content":"It works!"}'
# → 201 {"id":1,"title":"Hello Hopak","content":"It works!", ...}
curl http://localhost:3000/api/posts?limit=10&offset=20
# → {"items":[...],"total":42,"limit":10,"offset":20}
limit за замовчуванням — 20, максимум — 100. Помилки валідації повертають 400 з деталями по полях; порушення UNIQUE повертають 409; поля password / secret / token вирізаються з відповідей (зокрема тих, що завантажені через include).
Кастомізація ендпоїнту
Просто відредагуйте згенерований файл. Щоб замінити POST /api/posts власною логікою, видаліть POST export із app/routes/api/posts.ts і напишіть власний обробник:
// app/routes/api/posts.ts
import { crud, defineRoute } from '@hopak/core';
import post from '../../models/post';
export const GET = crud.list(post);
export const POST = defineRoute({
handler: async (ctx) => {
// your custom create logic — e.g. force-prefix the title,
// enforce auth, etc. — then call ctx.db!.model('post').create(...)
},
});
Інші п’ять дієслів залишаються як є. Оскільки все у вихідних файлах, тут немає магії «override» — ви просто змінюєте те, що експортує файл.
Захист CRUD-verb через middleware
Кожен crud.* helper приймає опціональний другий аргумент з before, after, wrap:
import { crud } from '@hopak/core';
import { requireRole } from '@hopak/auth';
import { requireAuth } from '../../middleware/auth';
import post from '../../models/post';
export const GET = crud.list(post);
export const POST = crud.create(post, { before: [requireAuth()] });
export const DELETE = crud.remove(post, {
before: [requireAuth(), requireRole('admin')],
});
Опції стосуються тільки цього дієслова. Повний контракт Before / After / Wrap — див. Middleware.
Відмова від CRUD для моделі
Не запускайте для неї hopak generate crud. Модель усе одно стане таблицею, ви лише не експонуєте HTTP-маршрути. Щоб додати їх пізніше, виконайте команду — або напишіть файл вручну, якщо вам потрібні URL поза /api/<plural>/.