Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

REST resource path design

Tags:

rest

uri

I'm developing a REST service, and I'm trying to adhere to Doctor Roy Fielding's conventions and guidelines.

I picture my service as an endpoint that exposes a set of resources. A resource is identified by an URI, and api clients can manipulate resources by using using HTTP semantics (i.e., different HTTP verbs map to the corresponding operations over URIs).

Guidelines state that these URIs should be defined in an hierarchical way, reflecting object hierarchy. This renders useful in resource creating, because on the backend we need the data to perform the create operation. However, on further manipulations, a lot of the information included in the URI is not even going to be used by the service, because generally the resource Id alone is enough to uniquely identify the operation target.

An example: Consider an Api that exposes the creation and management of products. Consider also that a product is associated with a brand. On creation it makes sense that the following action is performed: HTTP POST /Brand/{brand_id}/Product [Body containing the input necessary to the creation of the product]

The creation returns an HTTP 201 created with a location header that exposes the newly created product's location.

On further manipulations, clients could access the product by doing: HTTP PUT /Brand/{brand_id}/Product/{product_id} HTTP DELETE /Brand/{brand_id}/Product/{product_id} etc

However, since the product Id is universal in the product scope, the following manipulations could be performed like this: /Product/{product_id} I am only keeping the /Brand/{brand_id} prefix for coherence reasons. In fact, the brand id is being ignored by the service. Do you thing that this is a good practice, and is reasonable for the sake of maintaining a clear, unambiguous ServiceInterface definition? What are the benefits of doing this, and is this the way to go at all?

Also any pointers on URI definition best practices would be appreciated.

Thanks in advance

like image 939
Cristóvão Avatar asked Jan 11 '14 21:01

Cristóvão


People also ask

What is resource path in REST API?

Resource Path (request target) The path to the resource (object) to be acted upon. The ID of the resource must be provided in the path. For example, the following resource path identifies a specific transaction (resource) in our database: https://apitest.cybersource.com/pts/v2/payments/

What is a resource in API design?

Resources. A resource-oriented API is generally modeled as a resource hierarchy, where each node is either a simple resource or a collection resource. For convenience, they are often called a resource and a collection, respectively. A collection contains a list of resources of the same type.

What are resources in a REST architecture?

REST architecture treats every content as a resource. These resources can be Text Files, Html Pages, Images, Videos or Dynamic Business Data. REST Server simply provides access to resources and REST client accesses and modifies the resources. Here each resource is identified by URIs/ Global IDs.

What makes a good REST API design?

REST API designers should create URIs that convey a REST API’s resource model to the potential clients of the API. When resources are named well, an API is intuitive and easy to use. If done poorly, that same API can be challenging to use and understand.

What is a rest resource?

What is a Resource? In REST, the primary data representation is called resource. Having a consistent and robust REST resource naming strategy – will prove one of the best design decisions in the long term. The key abstraction of information in REST is a resource.

How do you address resources in a REST API?

REST APIs use Uniform Resource Identifiers(URIs) to address resources. REST API designers should create URIs that convey a REST API’s resource model to the potential clients of the API. When resources are named well, an API is intuitive and easy to use.

What is a rest resource naming strategy?

In REST, having a strong and consistent REST resource naming strategy – will prove one of the best design decisions in the long term. Skip to content REST API Tutorial Menu Menu REST JSON Dark Mode REST Resource Naming Guide Last Updated : November 23, 2021 1. What is a Resource? In REST, the primary data representation is called resource.


2 Answers

You are saying:

Guidelines state that these URIs should be defined in an hierarchical way, reflecting object hierarchy.

While it is often done this way it is not really relevant for a RESTful API design. Roy Fielding has a nice article addressing common misconceptions about REST. There he even says:

A REST API must not define fixed resource names or hierarchies (an obvious coupling of client and server).

and

A REST API should be entered with no prior knowledge beyond the initial URI …

So don't encode information in your URL that should be passed inside the resource. A RESTful API should work even if you replace all your URLs with artificial and non-sensical URIs. (I like understandable URIs as anybody but as an mental exercise to check your "RESTfullness" it's quite good.)

The problem to model an URI for an object "hierarchy" is that the hierarchy isn't very often as obvious as it seems. (What is the object hierarchy between teacher, course, and student?). Often objects are in a web of relations and belong not clearly beneath another object. A product might belong to a brand but you might have multiple supplier (covering a subset of products for multiple brands). And REST is wonderful to express complex nets of relations. The whole internet/web works this way.

Instead of encoding the relationship in the hierarchy just define a hyperlink in your resource pointing to the related objects.

For your specific example I would use POST /product/ to create a new product and have a link to your /brand/xzy in the resource representation when creating the product.

If you want to know which products are defined for a specific brand, just include a list of links in the returned representation for GET /brand/xzy. If you want to have an explicit resource representing for this relationship you still could define GET /brand/{id}/products as an URL (or /brandproducts/xzy or /34143453453) and return it as a link in your brand resource.

Don't think so much about the design of your URIs, think more about the information you provide in your resources. Make sure it provides links to all the resource representations your client might want to view or manipulate after receiving it from your API.

like image 79
xwoker Avatar answered Nov 08 '22 13:11

xwoker


I think this is the key comment:

a product is associated with a brand.

The word associated tells me you need to link resources together. So, let's say that there is an association between brands and products. Each resource has would have their own set of methods (GET, PUT, etc) as you described, but the representations should have links to other resources that describe their associations. Where the links are depends on the type of association (one-to-one, one-to-many, many-to-one, many-to-many) and direction.

For example, let's say there is a canonical request for this product to api.example.com:

GET /product/12345

It returns some representation of that product. For simplicity, I am going to use XML for the representation, but it can be XHTML, JSON or whatever you need. So, a simple representation of product 12345:

HTTP/1.1 200 OK
Content-Type: application/xml; charset=utf-8
Content-Length: ...

<?xml version="1.0"?>
<Product href="http://api.example.com/product/12345" rel="self" type="application/xml"/>
  <Name>Macaroni and Cheese</Name>
  <Brand href="http://api.example.com/brand/7329" type="application/xml"/>
  <Manufacturer href="http://api.example.com/manufacturer/kraft" rel="parent" type="application/xml"/>
</Product>

As you can see, I am embedding links into the representation of product 12345 describing each relationship. Whenever possible, I try to follow HATEOAS constraint as much as I can:

  • There is explicit linking between the current resource and associated resources.
  • An optional relationship description ("rel"). "self" and "parent" are descriptions about the relationship the current resource and the resource the link references.
  • An optional preferred MIME type that should be requested. This describes the type of document that the client should expect if a followup request is made.
  • Opaque URLs instead of raw identifiers. Clients can just "navigate" to the URL without building them using some convention. Note that URLs do not always need to contain a unique database identifier or key (like "/brands/kraft").

To expand on some advance concepts, let's say that products have other relationships. Maybe products have hierarchical relationships or products supersedes other products. All of these complex relationships can represented by links. So, an advanced representation of product 12345:

HTTP/1.1 200 OK
Content-Type: application/xml; charset=utf-8
Content-Length: ...

<?xml version="1.0"?>
<Product href="http://api.example.com/product/12345" rel="self" type="application/xml"/>
  <Name>Macaroni and Cheese</Name>
  <Brand href="http://api.example.com/brand/7329" rel="parent" type="application/xml"/>
  <Manufacturer href="http://api.example.com/manufacturer/kraft" type="application/xml"/>
  <!-- Other product data -->
  <Related>
    <Product href="http://api.example.com/product/29180" rel="prev" type="application/xml"/>
    <Product href="http://api.example.com/product/39201" rel="next" type="application/xml"/>
  </Related>      
</Product>

In this example, I am using "prev" and "next" to represent a chain of products. The "prev" can be interpreted as "superseded" and "next" be interpreted as "superseded-by". You can use "superseded" and "superseded-by" as rel values, but "prev" and "next" are commonly used. It is really up to you.

like image 20
Ralph Allan Rice Avatar answered Nov 08 '22 11:11

Ralph Allan Rice