Naming things is difficult...
Tags: architecture, computerscience, programming, discuss
Published: 2021-06-18 08:39:14

I was recently asked to write a section for our company's new developer handbook on API design...

Top to bottom.... here we go...

You might have seen in the wild, a request like this:

`/api/v2/customers/24/orders/1`

or 

`/products/56/variants`

Both of these examples are pretty sound design choices, and here's why:

## Prefixing

It's a good idea to start the API routes with a prefix signalling that this path is indeed an API. It instantly warns developers that the end points are unlikely to return a human readable response out of the box... 

So... `/api` all the way.

Unless you've got a subdomain, like `https://api.mydomain.com` where this becomes more redundant... 

## Versioning

If you're designing a *greenfield* API, that is, no existing legacy API to write over, or replace, then it's a good idea to start with the idea that your brand new API *might be replaced* some day

In order to do that, one approach is to 'version' or 'namespace' the API. In this way, clients consuming the API (front-ends, data-only clients) can easily configure themselves to work against any specified / working version of the API and know what to get...

- Need to deprecate a method? New version
- Need to make a breaking change to shape of data response? New version
- Need to modify the parameters that an API accepts? New Version

So

`/api/v1` or `/api/v2/` and so on...

## RESTful resources

REST APIs (aka representational state transfer) APIs are of course not the ONLY way of defining an API, we've got SOAP/XML, RPC, and many many other protocols...

REST is also more of a concept and protocol that an API should conform to, than a hard and fast set of rules, but they make a lot of sense and are very easy to reason about

### HTTP methods

The first thing to consider is to design our API in terms of the 5 most common HTTP methods: GET, POST, PUT, PATCH, DELETE

- GET for reading/viewing/listing
- POST for creating (*)
- PUT for creating /replacing (*)
- PATCH for updating
- DELETE well...

(* explained later)

The important thing to note is a `GET` request should invariably never have side effects -- that is it shouldn't change the state of a resource... talking of resources...


### Designing for resources / entities

The next big thing is that we're usually going to be designing the API against a bunch of entities that we've designed in our back-end... for example `Users` or `Customers` or `Orders` etc.

Some of these resources might be embedded in each other, and some might be stand-alone, but via convention we should be able to address this...

#### URL format

A note about entity naming in URLS: Every programming language is different, they use `CapitalCase`, `camelCase`, `kebab-case`, `snake_case`, etc. A URL is *not* a programming language, stick to `kebab-case` - URLS are case insensitive and you enhance readability by exposing the idiosyncrasies of your back-end language to your user!


#### Fetching multiple resources:

The entity should be *pluralised* and be the first item in the path

- `GET /api/v1/customers`
- `GET /api/v1/users`
- `GET /api/v1/orders`

Sometimes these resources required pagination and in almost all cases, the `GET` request should expect this to be done via **query strings** 

- `GET /api/v1/customers?page=1&page_size=20`

#### Fetching single resources:

The same path as before, with a unique ID appended in the path:

- `GET /api/v1/customers/12`
- `GET /api/v1/users/1`
- `GET /api/v1/orders/24`

It's almost always preferred to use integer IDs over string IDs in a SQL-based or RDBM system. (Don't get tied u over this, though, it's beyond the scope of this article)

You might want to allow (via parameters) restricting the information that comes back about a single entity... again, query strings (not a request body)

- `GET /api/v1/customers/1?fields=id,firstname,lastname`

#### Creating a resource:

POST/PUT are the two choices here. If we're being strict with REST definitions, then POST is for creating without regard to *idempotency* (idempotency is the idea that a repeat operation like create should only happen once even with repeated calls) and PUT should be used for *replacing* or *updating* a resource, or you're *creating* with an expected ID or unique identifier.

Obvioulsy parameters go in the BODY as `application/json` or `application/url-form-encoded` or whatever you require

Either way, they should be name with the *pluralised* endpoint:


- `POST /api/v1/customers` 
  - response: `201 { "id": 12, "name": ... }`
- `PUT /api/v1/customers/1` 
  - response: `200 { "id": 1, "name": ... }`

#### Updating a resource:

Updating can be done with `PUT` (see above) or `PATCH`. *PATCH* is usually reserved for *partial* updates of a resource. `DELETE` is well, for removing a resource

Naming: same as above - use the pluralised endpoint + a unique identifier. 

- `PUT /api/v1/customers/1` 
  - response: `200 { "id": 12, "name": ... }`
- `PATCH /api/v1/customers/1` 
  - response: `200 { "id": 1, "name": ... }`
- `DELETE /api/v1/customers/1` 
  - response: `200`

#### Nested resources:

Ok, gets a bit tricky, but in general the same rules are just re-used going on down the tree!

A `Customer` might have `Orders` or `Bussiness Units` or even a single one-to-one attribute like `Address`

- `GET /api/v1/customers/1/orders`
- `GET /api/v1/customers/1/orders/1`
- `POST /api/v1/customers/1/orders`
- `GET /api/v1/customers/1/business-units`
- `GET /api/v1/customers/1/address`

#### Authentication

Don't put your API keys in query strings, folks! It's just bad practice. An authentication request is full of side effects. `POST` it! And put it in the request body, these things can show up in browser histories and server logs and are a big no no!


- `POST /api/v1/auth/login`

```json
{
  "username": "...",
  "password": "..."
}
```


## Final thoughts

All in all, there's generally very little reason to name a resource in a URL in the singular unless it's an embedded entity as mentioned above (`Address`), or when the resource cant really be pluralised (hello `Advice` or `Evidence`)

Otherwise, it's a spelling mistake, and you should be ashamed of yourself. (Only joking...)