I'm having a problem to solve in an application. I'll show an example about it.
I have a rabbitmq queue on a system that is responsable to return Orders, called by another systems (the communication among these systems is only throught message). Until then, the only possible Order search was by the order code.
It works well. When I search by order code, I also filter by the order with contracts and deleted (logically). So, if the order has no contracts or it was deleted, the query doesn't return registers.
Now, one of that systems needs to find Orders without contracts and/or deleted.
Basically, I believe I need to build the same logic used in an API rest like this one, but using a queue message:
/api/orders?id=123455?deleted=true&hasContracts=true
Do that it's easy with message. I just need send a message with this format.
{
"code": 123,
"deleted": true,
"hasContract": true
}
Mapping the values for Long and Boolean classes. If the information was null, this filter will be ignored by the query, except the code that's mandatory.
The doubt is: is this makes sense? I didn't find anything about this subject on the Internet. Create a queue for each case is not an option, because it will be hard for us to implement many queues.
It makes sense to me; using RPC with RabbitMQ is like RPC with HTTP/gRPC/..., so you have many options here:
if you need a great flexibility, you can
create your own query language (like in the example above)
use something like GraphQL
if your use cases are limited, you can choose to segregate the API endpoints with several routing keys (REST-over-AMQP).
Hope this helps.
Related
I've spent more time than I'd like to admit trying to understand the differences between RPC and restful endpoints. In fact, after going down this rabbit hole, I'm not even sure I fully understand what RPC is anymore. And I'm not alone. I see countless messages repeatedly asking for clarification.
Here's my understanding so far:
RPC and restful endpoints are largely conceptual in nature only. There are no standards.
Both are ways of invoking a function on a remote server.
In the case of restful endpoints, we map HTTP methods to CRUD operations on a resource.
In the case of RPC, we're concerned w/actions on an object.
However, in both cases, we're addressing remote method invocation.
I've read some folks say restful shouldn't be stateful and if it is, it's not restful. But aren't most restful endpoints using state via sessions? I mean, I'm not going to let just anyone delete data w/o being logged in.
And I've also read that functions like domain(.)com/login isn't restful b/c it's an action. This seems to make sense, but since I'm not writing my functions any differently on my server than I would a simple restful function, does it really matter what we call them -- restful vs. RPC.
I truly just don't understand what I'm missing and no posts thus far on StackOverflow appear to address this confusion.
Hoping someone can provide some insight using the above as a guide for understanding. Thanks in advance.
It's an amazing question. There is a huge difference between REST and RPC approaches, I'll try to explain it.
RPC just lets you call some remote computer to make some job. It can be any job, and it can have any inputs and outputs. When you design API, you just define how to name this job operation and which inputs and outputs it will have.
Step 1. Just RPC
For example, you could have operation foo with one input and two outputs like that (I will use JSight API notation because it supports both RPC and REST API types):
JSIGHT 0.3
URL /rpc-api
Protocol json-rpc-2.0
Method foo
Params
{
"input-1": 123 // some integer
}
Result
{
"output-1": 123, // some other integer
"output-2": "some string"
}
When you design your RPC API you can use as many such operations as you want.
So, what's the problem with this? Why do we need REST, if we already have RPC?
The problems are the following:
When you look at the method foo definition you do not have the slightest idea, what it does.
When you design RPC APIs you have absolute freedom, but freedom often can be a bad thing. Because people think in different fashions. You could think, that your API is easy and elegant, but other people would not think so.
Step 2. Standardized RPC
If you are an experienced API designer and you use the RPC style, you will try to follow some pattern to avoid the two faults mentioned above. For example, let's imagine, that your foo method returns a customer entity. Then you will never call it like foo, you will call it getCustomer, like this:
JSIGHT 0.3
URL /rpc-api
Protocol json-rpc-2.0
Method getCustomer
Params
{
"input-1": 123 // some integer
}
Result
{
"output-1": 123, // some other integer
"output-2": "some string"
}
Ok! Now when you just look at this description, you can say, that this method returns a customer; that parameter input-1 is some filter, most possibly, ID; and output-1 and output-2 are some customer properties.
Look, just using the standard way of naming the method, we made our API much more easy-to-understand.
Still, why do we need REST? What's the problem here?
The problem is, that when you have dozens of such RPC methods, your API looks messy. E. g.:
JSIGHT 0.3
URL /rpc-api
Protocol json-rpc-2.0
Method getCustomer
Method updateCustomer
Method getCustomerFriends
Method getCustomerFather
Method askCustomerConfirmation
# etc...
Why it is not easy to understand this bunch of methods? Because it is not the way our brain works. Our brain always groups actions by entity. You naturally think about an entity, and then about actions, you can do with it. E. g. what you can do with a cup? Take, hide, break, wash, turn over. And brain rarely thinks firstly about actions and then about entities. What can I take? Cup, ball, ice cream, ticket, wife. Not very natural.
So, what is REST about?
Step 3. REST
REST is about grouping entities and defining the most standard actions with these entities.
In IT we usually create, read, write, or delete entities. That's why we have POST, GET, PUT, and DELETE methods in HTTP, which is de facto the only implementation of the REST style.
When we group our methods by entities, our API becomes much clearer. Look:
JSIGHT 0.3
GET /customer/{id}
PUT /customer/{id}
GET /customer/{id}/friends
GET /customer/{id}/father
POST /customer/{id}/ask-confirmation
It is much easier to perceive now than in the RPC-style example above.
Conclusion
There are a lot of other issues, concerning differences between RPC and REST. REST has its faults as well as RPC. But I wanted to explain to you the main idea:
REST is a standard, that helps you to organize your API in a user-friendly fashion, that is comfortable for the human brain, so any developer can quickly capture your API structure.
RPC is just a way of calling remote operations.
All the examples above are gathered here: https://editor.jsight.io/r/g6XJwjV/1
I truly just don't understand what I'm missing
Not your fault, the literature sucks.
I think you may find Jim Webber's 2011 guidance enlightening.
Embrace HTTP as an application protocol. HTTP is not a transport protocol which happens to go conveniently through port 80. HTTP is an application protocol whose application domain is the transfer of documents over a network.
HTTP, like remote procedure calls, is a request/response protocol. The client sends a message to the server, the server sends a message back. Big deal.
But in the REST architectural style, we're also following the uniform interface constraint. That means (among other things) that everybody understands requests the same way, and everybody interprets responses the same way.
And that in turn means that general purpose components (browsers, web crawlers, proxies) can understand the request and response messages, and react intelligently to those messages, without needing to know anything at all about the specialization of a particular resource.
In the case of HTTP, we're passing messages about the domain of documents; if I want information from you, I ask for the latest copy of your document. If I want to send information to you, I send you a proposed modification to your document. Maybe you respond to my modification by creating a new document and you tell me to go look at that. And so on.
Useful business activity, then, becomes a side effect of manipulating these documents. Or, expressed another way, the document metaphor is the facade we present to the world.
And I've also read that functions like domain(.)com/login isn't restful b/c it's an action.
See above: the literature sucks.
Consider this resource identifier: https://www.merriam-webster.com/dictionary/login
Does it work like every other resource identifier on the web? Yes. The browser knows how to make a request to GET this resource, and when Merriam-Webster answers that the browser should instead look at https://www.merriam-webster.com/dictionary/log%20on then it fetches that resource as well.
The fact that "login"/"log on" are intransitive English verbs does not matter; it's an identifier, and that's all the browser needs to know.
Alternatively, consider this: URL shorteners work.
Resource identifiers are a lot like variable names in a computer program; so long as the identifier satisfies the production rules of your language, you can use anything you want. The machines don't care.
The key idea is that resources are not actions, they are "information that can be named". https://www.merriam-webster.com/dictionary/log%20on is the name of the document that describes Merriam-Webster's definition of the verb "log on".
Since the machines don't care what names we use, we can use the extra freedom that offers us to choose names that make life easier for people we care about.
I've read some folks say restful shouldn't be stateful and if it is, it's not restful. But aren't most restful endpoints using state via sessions?
Stateless communication is a REST architectural constraint.
each request from client to server must contain all of the information necessary to understand the request, and cannot take advantage of any stored context on the server.
Cookies are one of the corners where HTTP failed to satisfy the stateless communication constraint.
I'm not going to let just anyone delete data w/o being logged in.
Not a problem: every HTTP request carries its own Authorization metadata; you aren't supposed to "remember" previous messages in the conversation. Instead, you verify the provided credentials every time.
I'm thinking about a REST API design. There are several tables in my database. For example Customer and Order.
Of course - each Order has its Customer (and every customer can have many Orders).
I've decided to provide such an interface
/api/v1/Customers/ -- get list of Customers, add new Customer
/api/v1/Customers/:id: -- get Customer with id=:id:
/api/v1/Orders/ -- get list of Orders, add new Order
/api/v1/Orders/:id: -- get Order with id=:id:
It works flawlessly. But my frontend has to display a list of orders with customer names. With this interface, I will have to make a single call to /api/v1/Orders/ and then another call to /api/v1/Customer/:id: for each record from the previous call. Or perform two calls to /api/v1/Orders/ and /api/v1/Customers/ and combine them on the frontend side.
It looks like overkill, this kind of operation should be done at the database level. But how can/should I provide an appropriate interface?
/api/v1/OrdersWithCustomers
/api/v1/OrdersWithCustomers/:id:
Seems weir. Is it a right way to go
There's no rule that says you cannot "extend" the data being returned from a REST API call. So instead of returning "just" the Order entity (as stored in the backend), you could of course return an OrderResponseDTO which includes all (revelant) fields of the Order entity - plus some from the Customer entity that might are relevant in your use case.
The data model for your REST API does not have to be an exact 1:1 match to your underlying database schema - it does give you the freedom to leave out some fields, or add some additional information that the consumers of your API will find helpful.
Great question, and any API design will tend to hit pragmatic reality at some point like this.
One option is to include a larger object graph for each resource (ie include the customer linked to each order) but use filter query parameters to allow users to specify what properties they require or don't require.
Personally I think that request parameters on a restful GET are fine for either search semantics when retrieving a list of resources, or filtering what is presented for each resource as in this case
Another option for your use case might be to look into a GraphQL approach.
How would you do it on the web?
You've got a web site, and that website serves documents about Customers, and documents about Orders. But your clients aren't happy, because its too much boring, mistake-prone work to aggregate information in the two kinds of documents.
Can we please have a document, they ask, with the boring work already done?
And so you generate a bunch of these new reports, and stick them on your web server, and create links to make it easier to navigate between related documents. TA-DA.
A "REST-API" is a facade that makes your information look and act like a web site. The fact that you are generating your representations from a database is an implementation details, deliberately hidden behind the "uniform interface".
Variety of REST practises suggest (i.e. 1, 2, 3) to use plurals in your endpoints and the result is always a list of objects, unless it's filtered by a specific value, such as /users/123 Query parameters are used to filter the list, but still result in a list, nevertheless. I want to know if my case should 'abandon' those best practices.
Let's use cars for my example below.
I've got a database full of cars and each one has a BuildNumber ("Id"), but also a model and build year which combination is unique. If I then query for /cars/ and search for a specific model and year, for example /cars?model=golf&year=2018 I know, according to my previous sentence, my retrieve will always contain a single object, never multiple. My result, however, will still be a list, containing just one object, nevertheless.
In such case, what will be the best practise as the above would mean the object have to be extracted from the list, even though a single object could've been returned instead.
Stick to best practises and export a list
Make a second endpoind /car/ and use the query parameters ?model=golf&year=2018, which are primarily used for filtering in a list, and have the result be a single object, as the singular endpoint states
The reason that I'm asking this is simply for the cleanness of the action: I'm 100% sure my GET request will result in single object, but still have to perform actions to extract it from the list. These steps should've been unnecessary. Aside of that, In my case I don't know the unique identifier, so cars/123 for retrieving a specific car isn't an option. I know, however, filters that will result in one object and one specific object altogether. The additional steps simply feel redundant.
1: https://learn.microsoft.com/en-us/azure/architecture/best-practices/api-design
2: https://blog.mwaysolutions.com/2014/06/05/10-best-practices-for-better-restful-api/
3: https://medium.com/hashmapinc/rest-good-practices-for-api-design-881439796dc9
As you've specifically asked for best practices in regards to REST:
REST doesn't care how you specify your URIs or that semantically meaningful tokens are used inside the URI at all. Further, a client should never expect a certain URI to return a certain type but instead rely on content-type negotiation to tell the server all of the capabilities the client supports.
You should furthermore not think of REST in terms of object orientation but more in terms of affordance and statemachines where a client get served every information needed in order to make an educated decision on what to do next.
The best sample to give here is probably to take a close look at the Web and how it's done for HTML pages. How can you filter for a specific car and how it will be presented to you? The same concepts that are used in the Web also apply to REST as both use the same interaction model. In regards to your car sample, the API should initially return some control-structures that teach a client how a request needs to be formed and what options could be filtered for. In HTML this is done via forms. For non-HTML based REST APIs dedicated media-types should be defined that translate the same approach to non-HTML structures. On sending the request to the server, your client would include all of the supported media-types it supports in an Accept HTTP header, which informs the server about the capabilities of the client. Media-types are just human-readable specification on how to process payloads of such types. Such specifications may include hints on type information a link relation might return. In order to gain wide-usage of media-types they should be defined as generic as possible. Instead of defining a media-type specific for a car, which is possible, it probably would be more convenient to use an existing or define a new general data-container format (similar to HTML).
All of the steps mentioned here should help you to design and implement an API that is free to evolve without having to risk to break clients, that furthermore is also scalable and minimizes interoperability concerns.
Unfortunately your question targets something totally different IMO, something more related to RPC. You basically invoke a generic method via HTTP on an endpoint, similar like SOAP, RMI or CORBA work. Whether you respect the semantics of HTTP operations or not is only of sub-interest here. Even if you'd reached level 3 of the Richardson Maturity Model (RMM) it does not mean that you are compliant to REST. Your client might still break if the server changes anything within the response. The RMM further doesn't even consider media-types at all, hence I consider it as rather useless.
However, regardless if you use a (true) REST or RPC/CRUD client, if retrieving single items is your preference instead of feeding them into a collection you should consider to include the URI of the items of interest instead of its data directly into the collection, as Evert also has suggested. While most people seem to be concerned on server performance and round-trip-times, it actually is very elegant in terms of caching. Further certain link-relation names such as prefetch may inform the client that it may fetch the targets payload early as it is highly possible that it's content will be requested next. Through caching a request might not even have to be triggered or sent to the server for processing, which is probably the best performance gain you can achieve.
1) If you use query like cars/where... - use CARS
2) If you whant CAR - make method GetCarById
You might not get a perfect answer to this, because all are going to be a bit subjective and often in a different way.
My general thought about this is that every item in my system will have its own unique url, for example /cars/1234. That case is always singular.
But this specific item might appear as a member in collections and search results. When /cars/1234 apears in these, they will always appear as a list with 1 item (or 0 or more depending on the query).
I feel that this is ultimately the most predictable.
In my case though, if a car appears as a member of a search or colletion, it's 'true url' will still be displayed.
my REST API format:
http://example.com/api/v1.0/products - get all products
http://example.com/api/v1.0/products/3 - get product with id=3
Also, the products can be orginized into a product groups.
What is a proper way to get all product groups according to REST best practices:
http://example.com/api/v1.0/products/groups
or
http://example.com/api/v1.0/productgroups
...
another option ?
I can't agree with Rishabh Soni because http://example.com/api/v1.0/products/groups may lead to ambiguity.
I would put my money on http://example.com/api/v1.0/productgroups or even better http://example.com/api/v1.0/product_groups (better readability).
I've had similar discussion here: Updating RESTful resources against aggregate roots only
Question: About the thing of /products/features or /product-features,
is there any consensus on this? Do you know any good source to ensure
that it's not just a matter of taste?
Answer: I think this is misleading. I would expect to get all features
in all products rather than get all possible features. But, to be
honest, it’s hard to find any source talking directly about this
problem, but there is a bunch of articles where people don’t try to
create nested resources like /products/features, but do this
separately.
So, we can't be sure http://example.com/api/v1.0/products/groups will return all possible groups or just all groups that are connected with all existing products (what about a group that has not been connected with the product yet?).
To avoid this ambiguity, you can add some annotation in documentation. But you can just prepare http://example.com/api/v1.0/product_groups and all is clear.
If you are developing Rest API for your clients than you should not rely on id's. Instead build a meaningful abbreviation and map them to actual id on server side.
If that is not possible, instead of using
http://example.com/api/v1.0/products/3 you can use http://example.com/api/v1.0/products?product_id=3 and then you can provide "product_id" description in the documentation. basically telling the client ways to use product_id.
In short a url must be meaningful and follow a pattern.The variable part must be send by in the url query(part after ? or POST payload)
With this, method to querying the server is also important. If client is trying to get something to the server he should use "GET" http request, similar POST http request if it is uploading new info and "PUT" request if it is updating or creating a new resource.
So by this analogy http://example.com/api/v1.0/products/groups is more appropriate as it is following a pattern(groups in product) while productgroups is more like a keyword with no pattern.
A directory like pattern is more easier to understand. Like in file systems(C:\Program Files\WinRAR), every part gets us to more generalized target.
You can also customize this for specific group- http://example.com/api/v1.0/products/groups?id=3
Let's say that there are two microservices representing the resources orders(/orders) and customers(/customers). My requirement is to get all the orders made by a customer.
Had it been a monolithic application, I would have modeled my uri as /customers/{id}/orders. This would have hit the customers resource and made an in-memory service call to get the corresponding orders.
Now, in case of microservices, this isn't possible. So, is the only way to get the orders is to make a remote service call or is there a better way of doing it?
Can we create another resource with the representation /ordersByCustomers/{customerid}?
You can pass some query parameters as filters (this is the most common way I've seen). For example
/orders?customerId=123
I think that's quite clear, that you want to retrieve all customer orders filtered by customer id. In the same way you can add pagination or other filters.
The important thing to remember is that you want the order resource, so the URL should remain the same. I'm mentioning this, because this has been the most difficult thing for me to change... to think about resources rather than remote calls.
In general you should beware of using endpoint that are more or less similar to the one you suggested:
/ordersByCustomers/{customerid}
Why? Because this is not RESTful in general (even in microservices environment) and make the API difficult to understand and you by the consumers. What if you need orderByWhatever? Will you be introducing new endpoint every single time you need a new set of data? Try to avoid so opinionated endpoints.
What #Augutsto suggested is fully correct. If you're afraid of having a complicated logic in GET request this is the situation where you can break REST rules. I mean introducing:
POST /orders/filter/
Where all the filtering logic will be passed in requests body - so it's easier to carry complicated logic as well.