-1

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.

3 Answers 3

1

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.

7
  • 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
    Commented Apr 12, 2020 at 21:46
  • 1
    @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. Commented Apr 13, 2020 at 0:09
  • 1
    @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. Commented Apr 13, 2020 at 0:10
  • 1
    @wired_in In your example of filtering a list using query params, the resource is the list, not the items in the list. If you change the filter, you get a different list. REST has no concept of a list of resources, or sub-resources, or child-resources. That's semantics that we add, but the system doesn't know. Again, think of an HTTP Cache layer. The cache doesn't know that it has a list of resources. It doesn't even know that what it has represents a list. Working with caches has driven this concept home for me. Commented Apr 13, 2020 at 15:44
  • 1
    @wired_in REST in Practice is my favorite book on REST :-), but it's been a few years since I've re-read it. As influential as it was, my experience and research on hypermedia systems have also influenced my understanding of these concepts. No, URLs are not defined to be unique, but they are effectively unique because generic components don't know your domain's semantics and thus can only treat them as unique. You'll avoid a lot of problems with intermediaries like caches if you think of them as unique. Consider it a rule of thumb if not a rule. Commented Apr 13, 2020 at 15:44
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.

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.

1
  • 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 Commented Feb 26, 2020 at 21:09

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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