Fullstack CourseLearn by building
Back to week 1

Topic

REST API + Postman / curl

Definition

Exercising a REST API with a tool such as curl or Postman means issuing HTTP requests with an explicit method, URL, headers, and body, and inspecting the returned status code and JSON — independent of any frontend UI.

In simpler words

Before relying on React, you should be able to call Nest routes yourself with curl or Postman and predict exactly what comes back.

Hands-on API practice for the week: hit /health, walk authenticated CRUD routes, and read ValidationPipe / filter errors.

After this you can

  • Call GET /health with curl and read the JSON
  • Call authenticated list/create routes with the correct headers and body
  • Carry a login cookie across curl requests (or via Postman’s cookie jar)
  • Interpret errors returned by ValidationPipe and AllExceptionsFilter
  • Find and use the Swagger UI at /docs instead of guessing routes

Start with the public route: /health

Definition

A public route is a Nest handler marked to bypass the global authentication guard, making it reachable without any credentials — a natural first target for verifying an API is running.

In simpler words

/health needs no login, so it is the fastest way to confirm the API is up before testing anything that requires a cookie.

HealthController marks its single route @Public(), so JwtAuthGuard (global via APP_GUARD) skips authentication for it entirely.

A quick curl to /health with no headers should return { "status": "ok" } with a 200 — if that fails, nothing else in the API will work either, so always check it first.

Calling health

curl -i http://localhost:3000/health
# HTTP/1.1 200 OK
# { "status": "ok" }

No -H Cookie needed — @Public() skipped the auth guard.

Tickets CRUD with curl — including the cookie

Definition

Because JwtAuthGuard is registered globally, every tickets route requires a valid access_token cookie obtained by first authenticating, which curl must forward explicitly using its cookie-jar flags.

In simpler words

Log in first to get a cookie, save it to a file, then pass that file back on every tickets request — otherwise you will get a 401 before your request even reaches the controller.

curl does not keep cookies between separate invocations by default — use -c cookies.txt to save the Set-Cookie response from login, then -b cookies.txt on every later request to send it back.

The list/get/create/update routes are open to any authenticated user; only DELETE :id requires the admin role via @Roles("admin") — expect a 403 if you try it as a non-admin seed user.

Login, then call tickets (curl)

# 1. Log in and save the cookie
curl -i -c cookies.txt -X POST http://localhost:3000/auth/login \
  -H "Content-Type: application/json" \
  -d '{"email":"admin@course.local","password":"password123"}'

# 2. List tickets using the saved cookie
curl -b cookies.txt "http://localhost:3000/tickets?page=1&limit=20"

# 3. Create a ticket
curl -b cookies.txt -X POST http://localhost:3000/tickets \
  -H "Content-Type: application/json" \
  -d '{"title":"Wire cookies"}'

# 4. Delete as admin (member gets 403)
curl -b cookies.txt -X DELETE http://localhost:3000/tickets/<id>

The same cookie file authenticates every subsequent request, exactly like a browser would.

Mistake: forgetting the cookie jar

// Wrong — no cookie flags, guard rejects every call
curl -X POST http://localhost:3000/tickets -d '{"title":"x"}'
# 401 Unauthorized

// Right
curl -b cookies.txt -X POST http://localhost:3000/tickets \
  -H "Content-Type: application/json" -d '{"title":"x"}'

Without -b cookies.txt, curl sends no cookie at all — the global JwtAuthGuard rejects the request before TicketsController runs.

Postman, Swagger, and reading errors

Definition

Postman offers a persistent cookie jar and saved collections as an alternative to curl, while Nest’s Swagger UI (served from SwaggerModule.setup) documents and lets you try every route from the running application’s own metadata.

In simpler words

Postman remembers cookies for you across requests in a collection; Swagger at /docs shows every real route with an "Authorize" button so you rarely have to guess a path or body shape.

In Postman, cookies persist automatically for requests inside the same collection/workspace, unlike separate curl invocations that each need explicit -b/-c flags.

A Nest API can serve Swagger at /docs (SwaggerModule.setup("docs", app, ...)) with addCookieAuth("access_token") configured — after logging in via a route, Authorize with the cookie so "Try it out" sends it automatically.

A validation failure returns 400 with a message array (from class-validator) listing each broken field; any other unhandled error returns the same shape from AllExceptionsFilter with a correlationId you can grep in server logs.

A validation error body

{
  "statusCode": 400,
  "error": "Bad Request",
  "message": ["title must be longer than or equal to 1 characters"],
  "details": [{ "field": "request", "message": "..." }],
  "correlationId": "..."
}

Same shape for every endpoint — that is the point of one global ValidationPipe + one global filter.

Keep in mind

  • Always test /health first — it rules out "the API isn’t even running".
  • Save curl cookie jars per role (admin vs member) to quickly demonstrate 403 vs success.
  • Swagger is generated from real decorators — if a route is missing there, check @ApiTags/@ApiCookieAuth and that its module is imported by AppModule.
  • Check the message array in error responses before guessing which DTO field is wrong.

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. How do you call protected tickets routes with curl?
Concept
2. Can Postman test cookie auth?
Syntax
3. What does Swagger at /docs list?
Practical
4. What status do you expect without a cookie on a guarded route?
Logic
5. Why prefer curl -c/-b while learning?
Concept
6. What should you inspect on a failed request?
Practical
7. How do you send JSON with curl?
Syntax
8. Is logging in once enough for a Postman collection?
Logic
9. What is a good first smoke test after boot?
Concept
10. Why might Swagger Try it out fail on protected routes?
Practical
11. After this login, the next curl still returns 401. What is missing?
Conceptintermediate
curl -c cookies.txt -X POST localhost:3000/auth/login -H 'Content-Type: application/json' -d '{"email":"a@b.co","password":"pw"}'
curl localhost:3000/tickets   # 401
12. This POST is rejected with an empty or invalid body. Why?
Syntaxintermediate
curl -X POST localhost:3000/tickets -b cookies.txt -d '{"title":"Bug"}'
13. What status do you expect from this request?
Practicaladvanced
curl localhost:3000/tickets   # no cookie sent
14. Why does the second request succeed?
Logicintermediate
curl -c jar.txt -X POST .../auth/login -H 'Content-Type: application/json' -d '{"email":"a@b.co","password":"pw"}'
curl -b jar.txt localhost:3000/tickets
15. What is a sensible first smoke-test step before login?
Conceptadvanced
# 1) ???  2) login  3) GET /tickets

Checking your session…