Fullstack CourseLearn by building
Back to week 3

Topic

Core API vertical-slice checklist

Definition

A core API vertical-slice checklist confirms that a single endpoint has a validated request contract, deliberate access control, a stable response and error shape, and accurate documentation, before it is considered done.

In simpler words

Before you call an endpoint finished, check that it validates input, guards access correctly, returns a predictable shape, and matches what /docs says it does.

Use a tickets-style endpoint set as the example: when every route satisfies this checklist, it makes a good template for a new one.

After this you can

  • Map one endpoint to every checklist item
  • Apply the checklist in order when adding a new endpoint
  • Explain why this checklist is the bridge into the Week 4 vertical slice

Reading one endpoint against the checklist

Definition

A finished endpoint pairs a DTO or query DTO with global ValidationPipe enforcement, a guard decision appropriate to its sensitivity — public, authenticated, or role-restricted — a response shape consistent with related endpoints, and Swagger decorators that describe the same contract.

In simpler words

Nothing here is new — each item is a topic already covered; the checklist is about applying all of them to one route at once.

DELETE /tickets/:id: ParseUUIDPipe validates the id, @Roles("admin") restricts access, 204 with no body signals success without inventing a response shape, and NotFoundException from the service becomes a consistent 404 if the ticket does not exist.

GET /tickets: ListTicketsQueryDto validates and coerces page/limit/status/q, no @Roles restricts it beyond authentication, and the { data, meta } shape matches every other list endpoint.

DELETE /tickets/:id against the checklist

@Delete(':id')
@Roles('admin')
@HttpCode(HttpStatus.NO_CONTENT)
async remove(@Param('id', ParseUUIDPipe) id: string) {
  await this.ticketsService.remove(id);
}

Validated param, explicit role guard, explicit status code, and a service that throws a mapped exception on failure — every checklist item is visible in five lines.

Applying the checklist to a new endpoint

Definition

Adding a new endpoint should follow the same order every time: define the DTO and its validation, decide the guard and role requirement, decide the response and error shape relative to existing endpoints, and update the DTO’s Swagger decorators alongside the code.

In simpler words

Write the checklist items in that order and the endpoint mostly writes itself; skipping one item is how endpoints drift from the rest of the API.

A new PATCH /tickets/:id/assign restricted to admin needs: an AssignTicketDto with a validated assigneeId, @Roles("admin"), a response matching the existing ticket shape, and ApiProperty on the new field.

This checklist is the bridge into Week 4’s vertical slice — the same list applies whether you are adding one field or one whole resource.

PR checklist for one endpoint

- [ ] DTO validates every accepted field
- [ ] Guard/role matches the endpoint's sensitivity
- [ ] Response shape matches sibling endpoints ({ data, meta } for lists)
- [ ] Thrown exceptions map to the right status (404/400/401/403)
- [ ] Swagger decorators match the DTO and guard
- [ ] Verified via /docs or curl with real auth

If any box is unchecked, the endpoint is not done — regardless of whether it compiles.

Keep in mind

  • Apply DTO → guard → response shape → Swagger in that order for every new endpoint.
  • Match a new endpoint’s response shape to its siblings before inventing a new one.
  • Verify through /docs or curl with real auth, not just a type check.

Test

Check your understanding

At least 10 questions — mix of concept, syntax, practical, and logic. Score ≥80% (enforced by the API) to save progress.

Checking your session…

15 questions · concept 5 · syntax 3 · practical 4 · logic 3

1. What makes a vertical-slice endpoint ready?
Concept
2. Why is compile success not enough?
Syntax
3. Why match sibling response shapes?
Practical
4. What should match the route sensitivity?
Logic
5. Why keep Swagger accurate when adding endpoints?
Concept
6. What does the tickets API teach?
Practical
7. Should error shape differ per tickets route?
Syntax
8. What belongs in a PR checklist for a new endpoint?
Logic
9. Can Swagger alone enforce validation?
Concept
10. Is a guard alone enough without validation?
Practical
11. Which readiness aspect is NOT guaranteed by this code alone?
Conceptintermediate
@Post()
@ApiCreatedResponse({ type: TicketDto })
create(@Body() dto: CreateTicketDto) {
  return this.svc.create(dto);
}
12. This compiles. What runtime contract bug remains?
Syntaxadvanced
@Get(':id')
findOne(@Param('id') id: string) {
  return this.repo.findOneBy({ id });
}
13. Why align endpoint B with endpoint A?
Practicalintermediate
// endpoint A returns { data, meta }
// new endpoint B returns [ ...rows ]
14. Auth is enforced here. What is still unsafe?
Logicadvanced
@Roles('admin')
@Post()
create(@Body() dto: any) {
  return this.svc.create(dto);
}
15. What status does this create return on success by default?
Conceptintermediate
@Post()
create(@Body() dto: CreateTicketDto) {
  return this.svc.create(dto);
}

Checking your session…