API foundations

Inspect requests and responses

Use curl to see methods, URLs, headers, bodies, and status codes instead of debugging an API from rendered JSON alone.

A browser tab shows you a body and nothing else. The method, the request headers, the status code and the response headers are all hidden. When an API misbehaves, that hidden part is where the answer is. So the first debugging habit I want you to build is: look at the whole exchange.

curl is the tool for that. Two flags do most of the work. -i prints the response headers above the body. -v prints everything, including the request curl sent and the connection details.

Here is a read and a create:

curl -i http://localhost:3000/books
curl -i --json '{"title":"Dune","author":"Frank Herbert"}' http://localhost:3000/books

Notice there’s no -X POST on the second line. --json already switches the method to POST, sets Content-Type: application/json and sets Accept: application/json. Adding -X on top is harmless here but it’s a habit that bites later: -X POST combined with a redirect makes curl re-send a POST where a browser would switch to GET. Use -X only when nothing else picks the method for you.

Read the exchange in order

Run the first command with -v and read the output top to bottom:

* Connected to localhost (::1) port 3000
> GET /books HTTP/1.1
> Host: localhost:3000
> User-Agent: curl/8.7.1
> Accept: */*
>
< HTTP/1.1 200 OK
< content-type: application/json
<
{"books":[{"id":"1","title":"Dune","author":"Frank Herbert"}]}

Lines starting with > are the request. Lines starting with < are the response. The order to check is always the same: the resolved URL, the request method and headers, the response status, the response headers, and only then the body.

Why the body last? Because a JSON-looking body proves nothing. A proxy can answer with an HTML error page. A cache can return a stale response with a surprising status. A redirect can hand you the body of a different URL. The status line and the headers tell you what happened. The body tells you what the server wanted to say.

The browser adds its own layer

The browser network panel is still worth opening, because the browser adds behavior curl doesn’t have. It sends preflight OPTIONS requests. It refuses to let JavaScript read a response when CORS headers are missing.

That second point trips up everyone once. Your fetch() call reports a CORS error, so you assume the server rejected the request. Often the server processed it fine and even wrote to the database. The browser just blocked your script from reading the answer.

The way out is to reproduce the same request with curl. If curl gets a 200, the server is fine and the problem is the Origin header and the CORS response. We fix that properly in the fourth module.

Try it now: send one request to /books and one to /nothing-here. Write down the status, the content-type and the body for each. In the next module we make that 404 body a lot more useful.

Lesson completed