An API is a promise to its callers
API versioning is how a team changes a web API while the apps that already use it keep working. Once other people build on your API, every change is a risk to them.
You will learn to document an API, to tell a safe change from a breaking one, and to retire something slowly.
By the end of this lesson
Note
I can document an API and change it without breaking its users.
Key words
| Word | What it means | Example |
|---|---|---|
| Documentation | a written description of what an API offers | |
| Version | a numbered state of the API that clients can name | /v2/books |
| Breaking change | a change that makes an existing client fail | |
| Backward compatible | old clients keep working after the change | |
| Deprecation | announcing that something will be removed later |
The cells students fill in are left blank in this preview.
Good documentation lets developers start alone
Documentation is written once and read many times. For every endpoint it gives the same parts.
It gives the address and method, what the request needs, what the answer holds, the errors it can give, and one example you can copy. A machine-readable description, such as an OpenAPI file, lets tools build the pages and test the API for you.
Worked example: one endpoint documented
| Part | What it says |
|---|---|
| Address and method | POST /books |
| Needs | A JSON body with title (text) and year (whole number) |
| Success | 201, and the new book |
| Errors | 400 for a bad field, 401 for no key, 409 for a duplicate id |
| Example | {"title": "Tide Tables", "year": 2019} |
The cells students fill in are left blank in this preview.
Change the catalogue and watch a client
Run the next two commands to make a books table. Then you will change its shape, the way a team changes an API, and watch what a client sees.
Give psql the password
export PGPASSWORD=shopShown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
Make the books table
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.
Add a new field, author
psql -h db -U shop -c "alter table books add column author text; 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 book 1 and see the new field
curl -s -w "\n" "http://api:3000/books?id=eq.1"Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
Adding is usually safe and removing is not
A change is backward compatible if old clients keep working. Adding an optional field is, because a client ignores what it does not know.
A breaking change makes an old client fail. Removing a field, renaming it, changing its type, or newly requiring an input are all breaking.
Worked example: safe or breaking
| Change | Breaks old clients? | Why |
|---|---|---|
| Add an optional field to an answer | No | Clients ignore the new field |
| Remove a field from an answer | Yes | Clients that read it fail |
| Rename a field | Yes | It is a removal and an addition |
| Change a number into text | Yes | Clients that add it up break |
| Make a new input required | Yes | Old requests lack it |
| Add a new endpoint | No | Nobody calls it yet |
The cells students fill in are left blank in this preview.
An old client asks for its fields
curl -s -o /dev/null -w "%{http_code}\n" "http://api:3000/books?select=id,title,year"Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
Rename year to published
psql -h db -U shop -c "alter table books rename column year to published; notify pgrst, 'reload schema'"Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
Run the old client again
curl -s -o /dev/null -w "%{http_code}\n" "http://api:3000/books?select=id,title,year"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 a bug fix cannot break anyone. It can. If a client relied on the old behaviour, such as an order of results, fixing it breaks that client. Treat any change to what an answer means as breaking, and say so before you ship it.
A version lets old and new coexist
When a breaking change is needed, publish it as a new version and keep the old one running. The version goes in the address, such as /v2/books, or in a header.
Deprecation is the slow exit. You announce the date, warn callers in the response, and only remove the old version after that date.