Home > Software engineering >  API Design: Making data human readable vs forcing more API calls
API Design: Making data human readable vs forcing more API calls

Time:11-24

Let's say we have a Product table in our database. This represents products that exist:

productId brandId (FK) name description capacity pricePerNight
1 2 Tent This is a tent 4 20

Let's say we also have a Brand table in our database. This represents brands and is linked to the Product table via an FK:

id name
1 Vango
2 Quechua

Now let's say I was making a public API which allows clients to query all products. I want the client to (conveniently) be able to see the name of the brand for each product.

My options are: (a) When they GET /product return an edited version of the Product object with a new human-readable field (brand) in addition to/in replacement of the FK:

{
        "productId": 1,
        "brand": "Quechua",
        "name": "Tent",
        "description": "This is a tent",
        "capacity": 4,
}

(b) Return the Product object as it exists in the database, thus compelling clients to make two calls if they want to access the brand name (e.g. one call to GET /product and one to GET /brand):

{
        "productId": 1,
        "brandId": 2,
        "name": "Tent",
        "description": "This is a tent",
        "capacity": 4,
}

I am confronted by this situation quite regularly and I'm wondering what best practice is for a RESTful API. Any opinions very welcome.

EDIT: IRL I am building a public API which needs to be as intuitive and easy to use as possible for our company's integrating partners.

CodePudding user response:

Table has the relationships with each other so you don't need to call two APIs. What I normally practice in the above mentioned case is I call one api i.e. /product and returns the product object and inside the product object contains brand object as well. This approach is also widely used internally by well renowned frameworks like springboot(Java) and Laravel(PHP).

{
        "productId": 1,
        "name": "Tent",
        "description": "This is a tent",
        "capacity": 4
         "brand":{
           "id":1,
           "name":"brandName"
        }
}

CodePudding user response:

I am confronted by this situation quite regularly and I'm wondering what best practice is for a RESTful API. Any opinions very welcome.

Heuristic: how would you do it on the web?

With web pages, it is common to have one page that combines all of the information that you need, even though that data is distributed across multiple tables.

The spelling of the URI normally comes not from the tables, but instead by thinking about what the name of this report is, and choosing an identifier that has similar semantics while remaining consistent with your local spelling conventions.

Here, it looks like we've got some form of "product catalog" or "stock list", so that concept would likely be what we are expressing in the URI.

(Note: part of the point of a REST API is that it acts as a facade, hiding the underlying implementation details. You should not feel obligated to expose your table names in your identifiers.)

CodePudding user response:

Starting from the DB layer, you could use a Read-Only View for reading data. This view could combine fields spanned across different tables (like that foreign key relationship in the example).

Also, as already mentioned, your response could include the objects the entity you query refers to.

At the end of the day, almost no one consumes data straight from an API; usually, there's some front-end infrastructure in between. As such you need to strike a balance between having a lean enough response payload whilst trying to make the client make as few requests as possible.

PS: This Stack Exchange thread may be relevant.

CodePudding user response:

The best answer I can give is "let the client specify what data it wants", e.g. by using GraphQL.

The problem is similar to the challenges ORM frameworks face - do I load the entire dependency graph (e.g. "brand" belongs to a category and a category has a manager and a manager has a department and a department has a...).

GraphQL changes this dynamic - it lets the API client specify which data it wants.

Alternatives are "load one level of dependency" (similar to Danish's answer), though that very quickly means a client has to build an understanding of your database schema - which creates tight coupling between client and API server.

  • Related