0

We're designing and developing an enterprise application using Spring Boot for REST APIs and Angular 8 as the web client. It's been an year since we started.

When I started, I read multiple articles which cleared my understanding of why REST without HATEOAS is not actually REST. I went ahead with the then available Spring HATEOAS project which was on v0.25 (not stable) then but good enough to get us started.

Now, it has moved to a stable 1.x version and we have upgraded to it.

In our case, we have a collection of documents stored in MongoDB which is used for multiple APIs. Think of it as a collection which contains lot of information and it has more than 3 ways to represent. And 95% of our APIs are GET requests, only 5% are PUT, POST and DELETE. Its a monitoring application API, you get it.

Now, I believe that the relation between a Resource and a Controller should be one-to-one.

Question 1: Am I correct with this?

And,

Question 2: Am I correct with the premise that as soon as the URL is same, the resource structure must not change?

Like, every time I hit the URL https://example.com/status, I must get a consistent structure of Response, irrespective of the query params I give to the API i.e. the number of keys in the response will be the same, but the values could vary.

Question 3: How do we define parent-child relation in a resource. Or should we even care about it?

Moving on,

Question 4: If I want a subset of keys for a Resource, should I define a new Resource for it, or I can manipulate the structure by giving some query parameters?

Answer to even one of the question could help me a lot.

0

Resource and Controller should be one-to-one

There's no hard rule. That's the most common way to organize things, but other approaches might work as well or better depending on your system. As long as things are well organized in some way, it's fine.

As soon as the URL is the same, Resource structure must not change

URLs should uniquely identify a resource, but query parameters are part of the URL. /status?fields=foo is as much a separate resource from /status as /status/fields/foo is.

How do we define parent-child relation in a resource

That's what links are for. The "rel" in a link is short for "relation". So, make use of the tools Spring HATEOAS provides you to add links and include one for any related resource.

If I want a subset of keys for a Resource, should I define a new Resource for it, or I can manipulate the structure by giving some query parameters?

Remember that including query parameters makes it a separate resource. How you structure your URLs is an implementation detail that doesn't really matter. However, are you sure you need a trimmed down version of the resource? If your resource can be cached, getting the full version from the cache is going to be faster than making a request for the trimmed down version. If you have two different versions you might have to make two requests when one would have been sufficient.


One more bit of advice. To get the full value out of HATEOAS, you should be using a generic client to consume the API that understands the hypermedia your API responds with. If you're using Spring HATEOAS, you're probably using HAL. Here's an example of a HAL client https://github.com/badgateway/ketting.

| improve this answer | |
  • This is misleading. A URL is not a unique identifier for a resource. It's not even a unique identifier for a representation of a resource. There is a one to many relationship between resources and URLs, and a one to many relationship between representations of a resource and URLs. It is perfectly valid to have /orders and /clients/{id}/orders, both pointing not only to the same Orders collection resource, but to the exact same representation, just within a different context. You are only correct in saying one URL can't point to more than one resource. – wired_in Apr 12 at 21:46
  • In addition, saying that adding query parameters to a URL makes it a different resource also doesn't make sense. In your example, you are filtering based on fields, you are returning a different representation of the same resource, sure. But what if your filtering query parameter was on the value of a field. /clients?state=VA for instance doesn't change the structure (representation) of the resource, it simply filters which results are included. So you have two different URLs, but certainly not two different resources, or even two different representations – wired_in Apr 12 at 21:53
  • @wired_in URI stands for Uniform Resource Identifier. It's whole reason for being is to identify resources. Although it's possible to write a server that treats two URLs are the same resource, it's effectively two separate resources to the system. Consider an HTTP caching layer. It can't give you a cached version of /orders when you request /clients/{id}/orders. It doesn't know that you intended those to be the same resource. That's why there are multiple mechanisms to indicate that URL is not the canonical URL for the resource including status codes, headers, and link relations. – Jason Desrosiers Apr 13 at 0:09
  • @wired_in As for query params, RFC 3986 states "The query component contains non-hierarchical data that, along with data in the path component, serves to identify a resource". It's just an alternate pattern for identifying a resource. Any semantics that your server gives to any part of the URL is irrelevant to the system as a whole. If it's not identified by the same string of characters, the system will treat it like a different thing. – Jason Desrosiers Apr 13 at 0:10
  • The query parameters may help identify a resource, which is different from saying that each value of a query parameter constitutes a unique resource. My example above clearly demonstrates this. Notice that U in URI stands for "Uniform", not "Unique". It is an identifier, but that doesn't mean that you can't have multiple identifiers for a single resource. This comes straight from the book "Rest in Practice: Hypermedia and Systems Architecture" – wired_in Apr 13 at 6:46
3
  1. This seems like a purely implementation question, it makes no difference to the end result but might make it easier to debug

  2. How would you explain to a client that sometimes a call returns X and sometimes Y? How would the client know which type to deserialise to? how would an application using the client know the return type of its call? It wouldnt be impossible, but it just makes things harder.

  3. Don't. This is documentation and you don't want to resend documentation with every request.

  4. Sending list parameters in URLs doesn't work very well and GetWhereIdInThisList type functions are awkward, but POSTing to RPC style paths status/getAllByParameterX is considered 'non RESTfull' You decide whether that means REST is inherently flawed or whether you can think up a crazy workaround.

| improve this answer | |
2

Lots of good answers to other parts of this, but I think this important bit is misunderstood:

Question 2: Am I correct with the premise that as soon as the URL is same, the resource structure must not change?

Like, every time I hit the URL https://example.com/status, I must get a consistent structure of Response, irrespective of the query params I give to the API i.e. the number of keys in the response will be the same, but the values could vary.

No! The important part here is the request's Accept header.

The structure of the Response should certainly be different between Accept:image/png and Accept:application/json for reasons which I hope are not too obscure.

| improve this answer | |
  • 1
    That was my first thought too when I read the question, until I realized he was talking about modifying the fields he was returning using query params. But, I should have mentioned it anyway. Glad you did +1 – Jason Desrosiers Feb 26 at 21:09

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.