Easier to read with cream paper, a tint, more contrast or larger text? Choose your colours and text, once, for every page.

Free lesson

HTTP status codes and error messages

After this lesson: I can choose the right status code and report an error clearly.

55 min lesson9 commandsPostgreSQL and PostgREST lab: a database and a REST API in the browser

A number that says how it went

An HTTP status code is a three-digit number a server puts at the top of every response to say how the request went. It tells a program, before it reads anything else, whether to carry on or to stop.

You will learn the five groups of codes, pick the right one, and write an error message a developer can act on.

By the end of this lesson

Note

I can choose the right status code and report an error clearly.

Key words

WordWhat it meansExample
Status codea three-digit number saying how a request went201
Successa code starting with 2: the request worked200
Client errora code starting with 4: the request was wrong404
Server errora code starting with 5: the server failed500
Error bodythe part of the response that explains what went wrong

The cells students fill in are left blank in this preview.

The first digit gives the group

Codes come in five groups. The first digit says who is responsible.

2xx means it worked. 4xx means the client sent something wrong, so the client must change the request. 5xx means the server failed, so the same request may work later. 3xx means look elsewhere, and 1xx is rare.

Worked example: the five groups

GroupMeaningWho actsExample
1xxInformation, carry onNobody100 Continue
2xxIt workedNobody200 OK
3xxGo to another addressThe client follows it301 Moved Permanently
4xxThe request was wrongThe client fixes it404 Not Found
5xxThe server failedThe server owner fixes it500 Internal Server Error

The cells students fill in are left blank in this preview.

See the success codes first

Run the next two commands to make a books table. Then each Run prints only the status code of one request.

Give psql the password

Command
export PGPASSWORD=shop

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

Make the books table

Command
psql -h db -U shop -c "drop table if exists books; create table books (id serial primary key, title text not null, year int not null, available boolean not null default true); insert into books (title, year, available) values ('Maps of the Sea', 1998, true), ('Rivers of Europe', 2004, false), ('Night Trains', 2011, true); notify pgrst, 'reload schema'"

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

Read the books

Command
curl -s -o /dev/null -w "%{http_code}\n" "http://api:3000/books"

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

Add a book

Command
curl -s -o /dev/null -w "%{http_code}\n" -X POST -H "Content-Type: application/json" -d '{"title":"Tide Tables","year":2019}' "http://api:3000/books"

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

Delete book 3

Command
curl -s -o /dev/null -w "%{http_code}\n" -X DELETE "http://api:3000/books?id=eq.3"

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

Pick the 4xx code that fits

A vague error wastes the developer's time. Pick the most exact code.

400 means the request is malformed. 401 means the caller has not proved who they are. 403 means they are known and not allowed. 404 means there is nothing at that address. 409 means the request clashes with the current state, such as a duplicate. 429 means too many requests.

Worked example: which code for which problem

ProblemCode
The JSON body is broken400
No key or token was sent401
A valid user may not delete this403
Book 999 does not exist404
A book with this id is already there409
Too many requests this minute429

The cells students fill in are left blank in this preview.

Send a book with no title

Command
curl -s -o /dev/null -w "%{http_code}\n" -X POST -H "Content-Type: application/json" -d '{"year":2019}' "http://api:3000/books"

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

Ask for a table that is not there

Command
curl -s -o /dev/null -w "%{http_code}\n" "http://api:3000/nothing"

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

Add a book with a used id

Command
curl -s -o /dev/null -w "%{http_code}\n" -X POST -H "Content-Type: application/json" -d '{"id":1,"title":"Copy","year":2000}' "http://api:3000/books"

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

A common mistake

Warning

Many people think an API can answer 200 every time and put the error in the body. Then every client must open every body to learn whether it worked, and tools that watch for failures see none. Use the status code for how it went and the body for why.

A good error body says what and where

The code is for programs. The error body is for the developer. Give every error the same shape.

Say what went wrong, which field it was about, and how to fix it. Never include a stack trace, a file path or a password. Those help an attacker and nobody else.

An error body worth sending (our own design)

Code: bash
HTTP/1.1 400 Bad Request
Content-Type: application/json

{
  "error": "invalid_book",
  "message": "year must be a whole number",
  "field": "year"
}

# This is the lesson's own example, not the lab's output.
# The code says 400. The body says why, and where.

Read the lab's own error body

Command
curl -s -w "\n" -X POST -H "Content-Type: application/json" -d '{"title":"Tide Tables","year":"soon"}' "http://api:3000/books"

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

About this lab and its source: PostgreSQL and PostgREST lab: a database and a REST API in the browser

Teaching a class? Set this module for your students with a teacher guide, marked assignments and a lab for every student.