Fullstack CourseLearn by building
Back to roadmap

Week 3 — Auth, contracts & API craft

Secure Nest APIs with JWT/RBAC, shape contracts, and craft list endpoints — then ship Notes P3 as this week’s mini-project.

End-of-week mini-project · practice only

Community Blog API (auth, RBAC & API craft)

A secured blog/forum API: cookie JWT login, roles, validated posts, paginated feeds, soft deletes, and image uploads.

Definition

A production-shaped Nest API where authenticated users publish posts and comments, guarded by RBAC and hardened with validation, rate limiting, CORS, stable errors, and Swagger docs.

In simpler words

Build the backend of a small blog where people log in, write posts with cover images, and browse a paged feed — with admins able to moderate.

Concepts covered this week

JSON Web Tokens (JWT)
Login issues an httpOnly access-token cookie verified by a JwtAuthGuard.
Refresh tokens & session revocation
A rotating refresh endpoint; logout revokes the session.
RBAC & guards
reader/author/admin roles; a RolesGuard lets admins moderate any post.
Middleware vs guards vs pipes
Correlation-id middleware, auth/roles guards, and a validation pipe each do one job.
Rate limiting & throttling
Throttle login and comment creation to blunt abuse (429 + Retry-After).
CORS & credentialed requests
enableCors({ credentials: true }) for the web origin so the cookie flows.
DTOs & validation
CreatePostDto/CreateCommentDto with class-validator + whitelist.
Error contracts
A global exception filter returns a stable JSON error shape.
Swagger / OpenAPI
Decorate endpoints and expose /docs with cookie auth.
Pagination & filtering
GET /posts?page&limit&tag&author returns { data, meta }.
Soft deletes
Deleting a post hides it from feeds and counts without dropping the row.
N+1 & loading strategy
Load post authors and comment counts with joins, not per-row queries.
File handling: Node fs & Nest uploads
A FileInterceptor accepts a cover image and stores it via fs.
Project planning & ERD
Plan users/posts/comments/tags relations before coding.
Core API vertical-slice checklist
Apply the vertical-slice checklist to the posts resource end to end.

Deliverables

  • Cookie JWT login + refresh rotation + logout (revocation)
  • RBAC: authors edit their own posts; admins moderate any
  • Validated CRUD for posts/comments with a global error filter + Swagger docs
  • Paginated, filterable, soft-delete-safe feed with cover-image uploads (no N+1)

Build guide

  1. Plan the ERDModel users, posts, comments, tags (posts↔tags N:N) and note ownership rules before writing code.
  2. Stand up authLogin sets an httpOnly access cookie; add a refresh endpoint that rotates tokens and a logout that revokes the session.
  3. Add RBACJwtAuthGuard + RolesGuard with reader/author/admin; enforce owner-or-admin on edit/delete.
  4. Validate + standardize errorsAdd DTOs with class-validator and a global exception filter that returns a consistent error JSON.
  5. Build the feedGET /posts with page/limit/tag/author filters returning { data, meta }; exclude soft-deleted rows from data and total.
  6. Kill N+1Load authors and comment counts via joins/relations so the feed runs a fixed number of queries.
  7. Accept uploadsUse FileInterceptor for a cover image, validate type/size, and store it with a sanitized filename.
  8. Harden + documentAdd throttling to login/comments, enable credentialed CORS, and expose Swagger /docs.

Acceptance checklist

- [ ] httpOnly cookie login + refresh rotation + logout revokes session
- [ ] Owner-or-admin enforced by RolesGuard (401 vs 403 correct)
- [ ] DTO validation + global error filter return stable JSON
- [ ] GET /posts paginates, filters, and hides soft-deleted rows in data AND total
- [ ] Cover-image upload validates type/size; feed has no N+1
- [ ] Throttling, credentialed CORS, and Swagger /docs in place

Stretch goals

  • Add reactions (like/bookmark) as an N:N relation.
  • Add full-text search on post titles/bodies.
  • Add an audit log of moderation actions.

Tips

  • 401 = not authenticated; 403 = authenticated but wrong role.
  • Reuse the same query filters for the page and the count so totals never drift.