Skip to main content

elysia-api-routes

Create and update QuickStack Elysia REST API routes using the project's established /api/v1 route conventions. Use when adding or editing files under src/server/api/v1, defining Elysia query/params/body/response schemas, or handling REST API authorization and errors.

Informations de source

Dépôt
biersoeckli/quickstack
Dernière activité de la source
9 août 2026 à 17:04
Langue détectée de SKILL.md
anglais
Étoiles
362
Forks
36

Options d'installation

Le prompt qui vérifie d'abord la source est sélectionné par défaut. Vous pouvez passer à une commande directe ou télécharger une copie locale.

Vérifiez les fichiers source

Lisez SKILL.md et les fichiers associés affichés par SkillsMP avant de décider de l'installer.

Affichage de SKILL.md

SKILL.md
Instructions source · Aperçu en lecture seule
name
elysia-api-routes
description
Create and update QuickStack Elysia REST API routes using the project's established /api/v1 route conventions. Use when adding or editing files under src/server/api/v1, defining Elysia query/params/body/response schemas, or handling REST API authorization and errors.
# Elysia API Routes ## Quick Start For QuickStack REST routes under `src/server/api/v1`, follow the current examples in `app/route.ts` and `project/route.ts`: ```ts export const resourceRoutes = new Elysia() .derive(ApiUtils.deriveFunc) .get('/resources/:id', async ({ params, identity }) => { if (!identity) throw new ApiUnauthorizedException() const resource = await resourceService.getByIdOrUndefined(params.id); if (!resource) throw new ApiNotFoundException(); ensureReadResource(identity, resource.id); return resource; }, { params: z.object({ id: z.string(), }), response: ApiUtils.mapResponseModel(ResourceModel), detail: { summary: 'Get resource by id', security: [{ bearerAuth: [] }] } }); ``` ## Required Route Shape - Start each route module with `new Elysia().derive(ApiUtils.deriveFunc)` so handlers receive `identity`. - Import `ApiUtils` from `src/server/utils/api-response.utils`. - Import `ApiUnauthorizedException`, `ApiNotFoundException`, and `ServiceException` from `src/shared/model/service.exception.model` as needed. - Declare `query`, `params`, and `body` directly in route options with Zod schemas. - Declare `response` with `ApiUtils.mapResponseModel(successSchema)`. - Keep OpenAPI metadata in `detail`, with a short `summary` and `security: [{ bearerAuth: [] }]` for protected routes. ## Handler Rules - If `identity` is missing, throw `new ApiUnauthorizedException()`. - If a requested resource does not exist, throw `new ApiNotFoundException()`. - Use shared authorization helpers such as `ensureReadApp`, `ensureWriteApp`, `ensureCreateAppInProject`, `ensureDeleteAppInProject`, `ensureReadProject`, and `ensureAdmin`. - Let shared authorization helpers throw; do not duplicate permission checks inline except for simple admin/read filtering already established in list routes. - Throw `ServiceException` for expected domain validation errors, such as immutable `projectId` violations. - Return success payloads directly; do not wrap them in `{ data }`, `{ status }`, or error envelopes. - Do not return `ApiUtils.problem(...)`, raw `Response`, or Elysia `status(...)` for expected route errors. ## Schema Rules - Use inline Zod objects for simple route params and query inputs. - Use existing write schemas, such as `AppExtendedWriteZodModel` or a local `projectWriteSchema`, for bodies. - Do not parse `query`, `params`, or `body` inside the handler if the route option already declares the schema. - Do not use nested `schema: { query, params, body }` in these route modules. - For delete routes, return `undefined` and declare `response: ApiUtils.mapResponseModel(z.undefined())`. - For deployment request routes, return `{ deploymentId }` and declare `response: ApiUtils.mapResponseModel(z.object({ deploymentId: z.string() }))`. ## Write Route Pattern Use POST upsert semantics: ```ts .post('/projects', async ({ body, identity }) => { if (!identity) throw new ApiUnauthorizedException() ensureAdmin(identity); let existing: Project | null = null; if (body.id) { existing = await projectService.getByIdOrUndefined(body.id); if (!existing) throw new ApiNotFoundException(); } return projectService.save({ id: existing?.id, name: body.name }); }, { body: projectWriteSchema, response: ApiUtils.mapResponseModel(ProjectModel), detail: { summary: 'Create or update project', security: [{ bearerAuth: [] }] } }) ``` ## Validation Checklist - Run `yarn tsc --noEmit` after route changes. - Check that every accepted input has a route-level Zod schema. - Check that every route has `response: ApiUtils.mapResponseModel(...)`. - Check that expected failures are thrown as exceptions; route mounting maps them centrally with `ApiUtils.mapError(...)`. - Check `CONTEXT.md` for REST API domain terms and write semantics before changing behavior.
Voir sur GitHub