tas2826
tas2826

Reputation: 51

Defining a REST api

I was wondering what the most correct or best practice way to define a rest api would be. Lets say I have an application that deals with cars and their parts/components. Any api will always start first with the top level car. So, in defining my api should I go with:

[url]/{resourceName}/{carId}/{resouorceId}

so as an example, lets say I want to get an engine, so:

[url]/engine/123/456

where 123 is the car id and 456 is the engine id. Or, is it a better practice to place the resource after the top level container, in this case a car, so something like:

[url]/{carId}/{resourceName}/{resourceId}

so the same example would be:

[url]/123/engine/456

Or does it matter? Is there an "industry best practice" type of approach? As I understand it, most of what I read has said something to the effect of "make the api intuitive and easy to understand".

Also, does or should the api be fully expressive, for example, should all api's regardless of approach be something like below even though the api is always for a car for this particular application.

[url]/car/{carId}/{resourceName}/{resourceId}

so, examples being:

[url]/car/123/engine/456
[url]/car/123/wheel/1

I understand this could be interpreted as a post that will just create debate, but I am really looking for help in tracking down what might be most widely accepted.

Upvotes: 1

Views: 221

Answers (1)

Vivin Paliath
Vivin Paliath

Reputation: 95588

REST really has nothing to do with URIs or HTTP. It is not a standard; it's an architectural style or paradigm. In Roy Fielding's thesis, he identifies certain criteria for an architectural style to be "RESTful". It just so happens that HTTP satisfies these criteria, which makes it a good protocol to realize a RESTful architecture. But REST itself has nothing to do with HTTP.

In REST URI's are opaque, meaning they don't convey any other semantic other than uniquely identifying a resource. So for example, a URI like /dfjSuX7kx is perfectly valid. Of course, that doesn't mean we have to use URI's like that; it's better to use something you can make sense of.

You wanted to know whether you should go with:

[url]/{resourceName}/{carId}/{resourceId}

I would say that it is better to go with just:

[url]/{resourceName}/{resourceId}

And then make carId part of the representation. Why is that? We know that one of the requirements is that your URI must uniquely identify a resource. Right now we have an engine 456 that is part of car 123, which means that you are identifying that particular resource with the URI /engine/123/456. But let's say car 123 was totaled and the engine was moved to car 789. Now your URI for the same resource is /engine/789/456. Keep in mind here that nothing about engine 456 has changed; it is still the same engine. The only thing is that it is now attached to a different car. But that doesn't mean that the URI that uniquely identifies it has to change as well (because then it would no-longer uniquely identify it). What identifies an engine uniquely is its id, and not the car that it is attached to. Hence it's better to just have /engine/456 and return a representation like:

{
    "id": 456,
    "carId": 123,
    "cylinders": 6,
    "hp": 350,
    ...
}

You also asked if you could do this:

[url]/{carId}/{resourceName}/{resourceId}

I would not recommend that at all. Let's say you have hosted your API at http://my.car-api.com. What does http://my.car-api.com/123 actually mean? Of course, it's RESTful because URI's are opaque, but it's hard to understand what it means when looking at the URI, so it's better to use /car/{carId}.

For your final question, you asked if the following is acceptable:

[url]/car/{carId}/{resourceName}/{resourceId}

Subresources are ok, and I have seen people use it, and I have also used it in some REST API's I have created. But personally I'm moving towards giving every resource a top-level URI. This is because we can already convey hierarchical relationships or the concept of "ownership" via the representation we return from the URI, instead of encoding that into the URI itself (remember, the URI has no additional meaning other than the fact that it uniquely identifies a resource). I've also noticed issues with orthogonality in the way I implement my controllers, error-handlers and transformers (helper classes that convert DTO's to domain objects and vice-versa); supporting a nested URI-structure makes it hard for me to write general code (although some of this is due to the way the framework I'm using, Spring, does things).

You can decide how "RESTful" you want to be; the best metric I've seen for quantifying the RESTfulness of your API is the Richardson Maturity Model. I would suggest that you decide on a level that you're comfortable with. It's not necessary to be completely dogmatic and be completely RESTful; it depends on your situation. But I have found that getting to Level 3 (HATEOAS) has brought me a lot of benefits because my custom media-types (i.e. I use application/vnd.my.api.resource.v1+json instead of just application/json) are well-documented and convey their semantics very well. Also none of my clients have to construct URIs, since they can just follow links. The representations are self-documenting as well, since you can follow links to associated documentation, for instructions on processing resources.

The only thing I would strongly suggest is picking a style and sticking with it. I don't like to mix paradigms; so if you are aiming to have something RESTful, don't let anything RPC-ish sneak into your API. This can be a little difficult because REST is noun-based and RPC is verb-based (i.e. behavior), and some concepts just map quite easily over to RPC. An example is if you had a Bank API where you wanted to provide the ability to transfer money from one account to another. A "REST" implementation that is really RPC-ish may expose a URI like /account/{accountId}/transfer?to={toAccountId}&amount={amount} (which directly maps to a method call on an Account object: account.transfer(amount, toAccountId); hence RPC). The RESTful way would be to expose a transaction resource at /transaction, where you would post something like:

{
    "from_account_id": 123,
    "to_account_id": 456,
    "amount": "100.00"
}

and the /transaction could respond with:

{
    "id": 789,
    "source_account_id": 123,
    "destination_account_id": 456,
    "amount": "100.00",
    "_links": {
        "self": { "href": "/transaction/789" }
    }
}

A lot of times people end up duplicating what HTTP already provides through RPC calls. For example, HTTP already gives you methods that translate to CRUD operations (quick note: the methods themselves have nothing to do with CRUD semantics; they just happen to map over conveniently), and also has response codes that convey information about the endresult of the operation (Was it successful? Did it fail? Why did it fail? etc.). The idea with REST is that you can concentrate on modeling your resources, their representations, and their relationships with each other and use what HTTP already provides you (hypermedia, response codes, methods) instead of duplicating all of that.

Upvotes: 3

Related Questions