How does one define which resource is a top level Rest resource (URI not nested inside any parent)?
My question comes from the fact that, if I take literally the concept of resource hierarchy, I end up getting very long URIs, like 5 or 6 levels deep.
This goes against the REST simplicity principle, and moreover, all of the ids along the chain are unique, so it is possible to simplify/shorten. Also, big REST apis like twitter or facebook, do not follow the hierarchy rule literally.
There is no heirarchy rule in REST.
Indeed quite the opposite: It's a principle of REST that URIs are opaque, and as such the URI <http://example.net/careers/technical/it/computing/programming/webProgramming/asp.net> conveys no more information from a REST perspective than <http://example.net/fasd12>.
Note that both these URIs are equally opaque from a REST perspective. A given process (digital or human thought) might interpret the former a particular way, but until the server says otherwise, that interpretation is not going to be correct (there's no way of knowing from looking at the URIs alone that they both identify a web service to help predict the milk yield of a herd of goats).
Where hierarchies come in is:
If the server has told the client how to construct a URI (e.g. html-forms, javascript to be executed on the client, or some other format that describes how URIs are built).
If the server has used relative URIs to describe links, as part of the HATEOAS principle.
In the latter in particular, hierarchies can be very useful.
And in this case, having URIs are that are 5, 6 or 14 levels deep are useful if you are modelling a set of resources which have a hierarchical relationship to each other that is 5, 6 or 14 levels deep. And not otherwise.
In this case it doesn't violate any principle of simplicity:
.. as a relative URI reference is very simple, whether it is going from 1 level deep to 0, or 43 levels deep to 42.
./programming/ as a relative URI reference is very simple, whether it is going from 0 levels deep to 1, or 42 levels deep to 43.
Outside of a given context such as that relative references use, all URIs are equally opaque and hence equally simple: They're all strings that can be compared for equality with each other, and nothing else.
Edit:
Conversely, while there's no reason to fear deep hierarchies, there's no reason to feel beholden to them either. If it's more useful to you to have a resource at /a/b/c include as a composite resource one at /d then fine. One can also do both, with /a/b/c/d and /e both identifying the same resource (having one 301 to the other would result in better cache behaviour and make the relationship explicit).
Related
I'm having a debate with a senior of mine at work and i want to know if what he says is true. Imagine I have a path /users/bucket-list that gets the currently logged in user bucket list. Now my question is, since i get the ID of the logged in user from the context do i still need to name my path like this /users/:user_id/bucket-list. I don't use the path param but my senior thinks that it should still be there and I think that since i don't use it i need to omit it. I want to hear your thoughts about this.
TL; DR
You are "doing it wrong"
Most of the time, you'll get away with it
Getting away with it is the wrong goal
Any information that can be named can be a resource -- Fielding, 2000
In most cases, I find that the easiest way to reason about "resources" is to substitute "documents", and then once the basic ideas are in place to then generalize if necessary.
One of the design problems that we face in creating our API is figuring out our resources; should "Alice's bucket-list" be presented separately from "Bob's bucket-list", or do they belong together? Do we have one resource for the entire list, or one resource for each entry in the list, and so on.
A related problem we need to consider in our design is how many representations a resource should support. This might include choosing to support multiple file formats (csv vs plain-text vs json, etc), and different languages (EN vs FR), and so on.
Your senior's proposed design is analogous to having two different resources. And having done that, everything will Just Work[tm]. There's no confusion about which resource is being identified, authorization is completely separate from identification, and so on.
Your design, however, is analogous to having a single resource with multiple representations, where a representation is chosen based on who is looking at it. And that's kind of a mess -- certainly your server can interpret the HTTP request, but general purpose components are not going to know that your resource has different identification semantics than every other resource on the internet.
We normally discriminate different representations using the Vary header; but the Authorization field is sort of out of bounds there, see RFC 7231.
In practice, you are likely to get away with your design because we have special rules about how shared-caches interact with authenticated requests, see RFC 7234.
But "likely to get away with it" is pretty weak. The point of having common standards is to get interop. If you are going to risk interop, you had better be getting something very valuable back in exchange. Nothing you have presented here suggests a compensating advantage.
This is more of a question regarding design rather than implementation. I have been working on a personal application with Python Flask backend and Vue.js SPA frontend for quite some time now and am now a bit puzzled on how to design the actual REST API.
My backend heavily depends on inheritance, e.g. there's the broad notion of an Account and then there is the ManagedAccount, exhibiting all properties of the former but also additional ones. Then there are Transactions, PredictedTransactions, RecurringTransactions etc., I guess you get the gist.
I read up on REST API design beforehand, e.g. on the Overflow blog and before I was working with IDs, I had the following design:
/accounts/ [GET] - returns all Accounts including ManagedAccounts with Account-specific properties
/accounts/managed/ [GET] - returns all ManagedAccounts with ManagedAccount-specific properties
/accounts/ [POST] - creates a new Account
/accounts/managed/ [POST] - creates a new ManagedAccount
Now, this worked quite well until I introduced ID-dependent functions, e.g.
/accounts/<:id> [PATCH] - modifies the received data in Account with given ID, can also be used to alter Account-specific properties in ManagedAccounts
/accounts/managed/<:id> [PATCH] - modifies the received data in ManagedAccount with given ID
/accounts/<:id> [DELETE] - deletes an Account, can also be used for ManagedAccount
For all IDs I am using RFC4122-compliant UUIDs in version 4, so there definitely will never be a collision within the route. Still, this behavior triggers an assertion error with Flask, which can be circumvented, but got me to rather double-check whether this design approach has any pitfalls I have not yet considered.
Two alternatives came to my mind:
Segregating the parent classes under a separate path, e.g. using /accounts/all/ for Account. This requires knowing the inheritance depth beforehand (e.g. would need breaking changes if I were to introduce a class inheriting from ManagedAccount).
Not incorporating inheritance in the routes, e.g. using /managed_accounts/ or /accounts_managed/. This would be the easiest method implementation-wise, but would - in my opinion - fail to give an accurate representation of the data model.
From the beginning on I want to give this API consistent guarantees as defined in the backend data model, e.g. for the Transaction I can currently assure that /transactions/executed/ and /transactions/predicted/ return mutually exclusive sets that, when joined, equal that returned by /transactions/.
Right now I am able to effectively utilize this on front-end side, e.g. poll data from Account in general and get specifics for ManagedAccount when required. Is the design I am currently pursuing a 'good' REST API design or am I clinging to concepts that are not applicable in this domain? If so, which design approach would make more sense and especially, why and in what situations would it be beneficial to the current one?
REST doesn't care what spellings you use for your URI, so long as your identifiers are consistent with the production rules defined in RFC 3986.
/d501c2c2-5729-469c-8eed-3643e1b06504
That UUID, of itself, is a perfectly satisfactory identifier for REST purposes.
This is more of a question regarding design
Yes, exactly -- the machines don't care what spellings you use for your resource identifiers, which gives you some freedom to address other concerns. The usual choice here is to make them easier for humans (easier for people to implement, easier for people to document, easier for operators to recognize in a log... lots of possibilities).
"No ambiguities in our automated routing" is a perfectly reasonable design constraint.
Path segments are used for the hierarchical parts of an identifier. There's no particular reason, however, that your identifier hierarchy needs to be aligned with "inheritance" hierarchy.
One long standing design principle on the web is that Cool URI Don't Change; so before introducing inheritance cues in your identifiers, be sure to consider how stable your inheritance design is.
We are implementing a REST API over our CQRS services. We of course don't want to expose any of our domain to users of the REST APIs.
However, a key tenant of CQRS is that the read models generally correspond to a specific view or screen.
With that being the case, it seems logical that the resources in our REST API, will map virtually 1:1 with the read / view models from our queries (where the queries return a DTO containing all the data for the view). Technically this is exposing a part of our domain (the read models - although returned as DTOs). In this case, this seems to be what we want. Any potential downsides to being so closely coupled?
In terms of commands, I have been considering an approach like:
https://www.slideshare.net/fatmuemoo/cqrs-api-v2. There is a slide that indicates that commands are not first class citizens. (See slide 26). By extension, am I correct in assuming that the DTOs returned from my queries will always be the first class citizens, which will then expose the commands that can be executed for that screen?
Thanks
Any potential downsides to being so closely coupled?
You need to be a little bit careful in terms of understanding the direction of your dependencies.
Specifically, if you are trying to integrate with clients that you don't control, then you are going to want to agree upon a contract -- message semantics and schema -- that you cannot change unilaterally.
Which means that the representations are relatively fixed, but you have a lot of freedom about about how you implement the production of that representation. You make a promise to the client that they can get a representation of report 12345, and it will have some convenient layout of the information. But whether that representation is something you produce on demand, or something that you cache, and how you build it is entirely up to you.
At this level, you aren't really coupling your clients to your domain model; you are coupling them to your views/reports, which is to say to your data model. And, in the CQRS world, that coupling is to the read model, not the write model.
In terms of commands, I have been considering an approach like...
I'm going gently suggest that the author, in 2015, didn't have a particularly good understanding of REST by today's standards.
The basic problem here is that the author doesn't recognize that caching is a REST constraint; and the design of our HTTP protocols needs to consider how general purpose components understand cache invalidation.
Normally, for a command (meaning here "a message intended to change the representation of the resource"), you normally want the target-uri of the HTTP request to match the identifier of the primary resource that changes.
POST /foo/123/command
Isn't particularly useful, from the perspective of cache invalidation, if nobody ever sends a GET /foo/123/command request.
I am developing REST API and Frontend as a microservice. I know some basic principles of URL design, but there is a performance issue and I'm not sure how to deal with it.
For the convenience of displaying the webpage, I'd like to get certain information about more than 100 resources per page. (Actually, BFF exists as an orchestration layer)
Since the target resource includes the aggregation result from a large amount of database record, it takes about 3 seconds per request. However, the information I want on the webpage is only a part of it, and it doesn't require complex aggregation to get it, and that makes the response time much shorter.
Take a case as an example.
There is a resource of article, and return the resource data in articles/:id containing a complex aggregation. But in this case, all I need is a count of comments, which can be quickly obtained by issuing a SQL count statement without a counter cache.
However, when examining REST API design, I've never seen a case where a GET request that returns only a specific field.
And in microservices, API should only return resource state in loosely coupled situation, so I think it shouldn't be focused on specific fields.
What kind of URL design or performance optimization can be considered in the face of performance problems?
REST is the architectural style of the world wide web; the style and the web were developed in parallel in the 1990s. Given the usage patterns and technical constraints of the time, the attention of the style is focused more on the caching of large grained documents, rather than trying to reduce the latency of transport.
So you would be more likely to design your representation so that count is present somewhere in the representation, and addressable to that you can call attention to it. Thus: fragments.
So if you already had a resource with the identifier /articles, and having the comment count was important enough, then you might treat the representation like a DTO (Data Transfer Object), and simply include the comment count in the representation, accessible via some identifier like /articles#comment-count.
That's not necessarily a great fit for your use case.
An alternative is to just introduce a stand-alone comment count resource.
Any information that can be named can be a resource -- Fielding, 2000
If you are actually doing REST, then the spelling of the URI don't matter (consider - when is the last time you cared where the google search form actually submitted your query?). The identifiers are used as identifiers, general purpose clients don't try to extract semantics from the identifiers.
So using /d8a496c4-51c5-4eeb-8cbd-d5e777cbdee7 as your identifier for the comment-count should "just work".
It's not particularly friendly to the human reader, of course, so you might prefer something else. URI design is, in this sense, a lot like choosing a good variable name -- the machines don't care, so me make choices that are easier for the human beings to manage. That normally means choosing a spelling that is "consistent" with the other spellings in your API.
RFC 3986 introduces distinctions between the path, the query, and the fragment, that you can expect general-purpose components to understand; one of the potentially important distinctions is that reference resolution describes how a general purpose component can compute a new identifier from a base uri and a relative reference.
/articles/comment-count + ./1 -> /articles/1
I'm creating a restful web service. As JPA I use Hibernate.
I have such entities like Country, City, Store, Sale and others.
Is it a good idea to have URIs like this in terms of length and nesting: http://example.com/countries/{countryId}/cities/{cityId}/sales/{saleId}/article/{articleId} ?
Is there any rule of number of nestings? I mean the number of pairs "entity/{entityId}" ?
URIs are opaque. As far as HTTP and the RESTful principles behind it go, there's no difference between http://example.com/countries/{countryId}/cities/{cityId}/sales/{saleId}/article/{articleId}, http://example.net/sfdaikwjepfiaosnd and http://example.org/ followed by the URI-encoded contents of Finnegans Wake. Indeed it's perfectly possible for all three of those to be URIs for the same resource, perhaps with one permanently redirecting to the other.
So it's non-REST concerns that are most at work here.
One is that if you are at risk of going beyond practical size limits you will have problems.
Another is that entities containing lots of URIs will obviously be shorter if those URIs are small. It's not generally a big concern, but it does have a bit of an effect on network use if URIs are truly massive and every entity contains kilobyte upon kilobyte of such URIs.
Another is just how useful the modelling is: If calling code will never care about the country when it wants an article then your modelling isn't helping that calling code.
Related to that is the practicality of relative links in helping the HATEOS aspect of REST: If you are likely to often be able to just have article/2 as a relative link that is useful in the entity describing a sale, or a (potentially hard-coded) ../../ to get to the entity describing a sale from one describing an article then this is convenient. The question is are you making the most useful links the most convenient. For example, if it is far more common to go from country to city than country to anything else, then why have the /cities/ part to the path, and not just {countryid}/{cityid}?
This relative link matter can counter the question of large URIs causing large entities: If the majority of URIs in an entity are "close" to the resource the entity describes then the majority of URIs can be represented by very small relative URIs.
Another aspect is whether those IDs are human-reader-friendly. Is the ID for New York something like 193 or something like NewYork or New%20York or perhaps Nueva%20York? To a REST perspective those are all of equal value, but 193 gives shorter URIs with advantages noted above while the others are handier to deal with as a consuming developer or when debugging.
Nesting also affects this human-readable aspect. On the one hand lots of nesting can make each element within that simple to identify but on the other it can be confusing in itself to have too many sections in the path. For the most part though if the split is understandable then a human reader can filter out much of the URI and focus on the part they care about.
In all the only hard limit is that of the practical URI size limits, and beyond that there aren't so much strict rules as pros and cons to consider the trade-offs of in your design.