When creating API's, I'm often unsure as to the treatment of referenced values in my database as well as different representations of the same resource.
Let's say I have an order table with, among other, these fields: id, product_id(fk) status_id(fk).
Now, a GET request is made to this order:
GET /api/order/{order_id}.
Two questions now arise, out of my inexperience:
1. What to return for the fields referencing either another resource (product) or a lookup table (status)?
The options I am considering are:
a) Provide only the fk id, and leave it to the client to then request the corresponding resource.
GET /api/order/1
{
id: 1,
status_id: 1,
}
b) Provide both the id, as well as the value that is likely relevant in the response. E.g. the response would include:
GET /api/order/1
{
id: 1,
status_id: 1,
status_title: 'pending,
}
c) Do two queries in the back end, and nest them in the response:
GET /api/order/1
{
id: 1,
status: {
id: 1,
title: 'pending',
},
}
2. How do you handle requests to this resource from different stakeholders?
E.g. surely a customer GETting an order shouldn't have access (nor probably wants it) to the same representation of that resource as a store administrator using his interface to fulfill the order.
Let's say, theoretical, the order table contains a field commission_rate stating the relevant commission internally negotiated on that order.
How do you now go about handling the aforementioned GET to indicate that you are trying to retrieve it from a certain perspective?
Perhaps
GET /api/order/{id}/customer
or
GET /api/order/{1}?view=customer
APIs tend to work at the domain level:
Order {
id: "123",
customerId: "456"
...
}
databases work at the implementation level:
rows with FK etc. No client ever needs to know what FK means or even see one.
So it would be an idea to start designing the API from a domain perspective and then grouping endpoints into authorisation contexts, e.g. only sales reps can request commission_rate
for an order.
The domain objects themselves are "first class citizens", Order
, Product
, Sales
etc and the authorisation context determines who/what can request each domain object (REST resource).
e.g. a Customer
may want to know when their Order
will be Deliver
ed while a SalesRep
may want to know when the Order
for that Customer
was delivered so they can get their CommissionRate
.
GET /order/{id} -> Order accessed by (Custmer, SalesRep, Admin)
GET /order/{id}/status -> OrderStatus accessed by (Custmer, SalesRep, Admin)
GET /order/{id}/commission -> CommissionRate accessed by (SalesRep, Admin)
in each call, the client wants to know a specific aspect of an Order
. In terms of including other content, they may not want it but you could include relevant links as HATEOS extensions in the response, giving relevant API endpoints related to that Order
such as the Product
ordered, or even the API endpoint to get the Status
etc.