This seems like an elementary question, but after a lot of searching around I can't seem to find a straightforward explanation:
If I'm building a web application that is going to be accessed largely through a web browser, but that will also support some API requests in a RESTful way, should there be a large degree of separation between the two?
On one hand, it seems a large amount of the functionality is the same, with identical data presented in different views (HTML vs. XML/JSON). But on the other hand, there are certain things I need to present to the browser that doesn't quite fit a RESTful approach: how to get an empty form to create a new instance of a resource and how to get a pre-populated form to edit an existing resource.
Should these two different methods of accessing the system by funneled through different controllers? Different methods in the same controller? The exact same methods with a switch for view type?
Your core controllers don't have to change, but that doesn't mean you can't have some extra ones solely to support you UI. For example, both of the Form examples you have can be unique to the Web API. Your entry URIs can certainly have links to those pages for both the machine and user interface, just don't expect the machine users to actually use them.
Also, if your machine clients are simply XML/JSON, then those representations don't need those links at all to the forms, since they'll not use them, and they don't "work" in JSON/XML anyway. You can manage that through Content negotiation.
Related
Let's imagine a web service X that has a single purpose - help to integrate two existing services (A and B) having different domain models. Some sort of adapter pattern.
There are cases when A wants to call B, and cases when B wants to call A.
How should endpoints of X be named to make clear for which direction each endpoint is meant?
For example, let's assume that the service A manages "apples". And the service B wants to get updates on "apples".
The adapter service X would have two endpoints:
PUT /apples - when A wants to push updated "apples" to B
GET /apples - when B wants read "apples" from A
(without awaiting a push from A)
Such endpoint structure as above is quite misleading. The endpoints are quite different and use different domain models: PUT-endpoint awaits model of A, and GET-endpoint return model of B.
I would appreciate any advice on designing the API in such a case.
I don't like my own variant:
PUT /gateway-for-A/apples
GET /gateway-for-B/apples
In my view, it is fine, but can be improved:
PUT /gateway-for-A/apples
GET /gateway-for-B/apples
Because
forward slashes are conventionally used to show the hierarchy between individual resources and collections: /gateway-for-A/apples
What can be improved:
it is better to use lowercase
remove unnecessary words
So I would stick with the foloowing URI:
PUT /a/apples
GET /b/apples
Read more here about Restful API naming conventions
First things first: REST has no endpoints, but resources
Next, in terms of HTTP you should use the same URI for updating the state of a resource and retrieving updates done to it as caching, which basically uses the effective URI of a resource, will automatically invalidate any stored responses for an URI if a non-safe operation is performed on it and forward the request to the actual server. If you split concerns onto different URIs you basically bypass that cache management performed for you under the hood completely.
Note further, HTTP/0.9, HTTP/1.0 and HTTP/1.1 itself don't have a "push" option. It is a request-response protocol and as such if a client is interested in getting updates done to a resource it should poll the respective resource whenever it needs updates. If you need above-mentioned push though you basically need to switch to Web Sockets or the like. While HTTP/2 introduced server push functionality, this effectively just populates your local 2nd level cache preventing the client from effectively requesting the resource and instead using the previously received and cached one.
Such endpoint structure as above is quite misleading. The endpoints are quite different and use different domain models: PUT-endpoint awaits model of A, and GET-endpoint return model of B.
A resource shouldn't map your domain model 1:1. Usually in a REST architecture there can be way more resources than there are entities in your domain model. Just think of form-like resources that explain a client on how to request the creation or update of a resource or the like.
On the Web and therefore also in REST architectures the representation format exchanged should be based on well-defined media-types. These media types should define the syntax and semantics of elements that can be found within an exchanged document of that kind. The elements in particular provide the affordance that tell a client in particular what certain elements can be used for. I.e. a button wants to be pressed while a slider can be dragged left or right to change some numeric values or the like. You never have to frequent any external documentation once support for that media type is added to your client and/or server. A rule of thumb in regards to REST is to design the system as if you'd interact with a traditional Web page and then apply the same concepts you used for interacting with that Web page and translate it onto the REST application domain.
Client and server should furthermore use content-type negotiation to negotiate which representation format the server should generate for responses so that clients can process them. REST is all about indirections that ultimately allow a server to change its internals without affecting clients that behave well negatively. Staying interoperable whilst changing is an inherent design decision of REST. If that is not important to you, REST is probably overkill for your needs and you probably should use something more (Web-) RPC based.
In regards to you actual question, IMO a messaging queue could be a better fit to your problem than trying to force your design onto a REST architecture.
I was hoping that there is a well-known pattern for adapter service (when two different services are being integrated without knowing each other formats)
I'd compare that case with communication attempts among humans stemming from different countries. I.e. imagine a Chines who speaks Mandarin trying to communicate with a Frech. Either the Chinese needs to be able to talk French, the French being able to talk in Mandarin, they both use an intermediary language such as English or they make use of a translator. In terms of trust and cost, the latter option might be the most expansive one of all of these. As learning laguages though is a time-consuming, ongoing process this usually won't happen quickly unless special support is added, by hiring people with that language skills or using external translators.
The beauty of REST is, servers and clients aren't limited to one particular representation format (a.k.a. language). In contrast to traditional RPC services, which limit themselves to one syntax, in REST servers and clients can support a multitude of media types. I.e. your browser knows how to process HTML pages, how to render JPG, PNG, GIF, ... images, how to embed Microsoft Word, Excel, ... documents and so forth. This support was added over the years and allows a browser to basically render a plethora of documents.
So, one option is to either create a translation service that is able to translate one representation to an other and then act as middleman in the process or you directly add support for the non yet understood media types to the service/client directly. The more media-types your client/servers are able to process, the more likely they will be to interoperate with other peers in the network.
The former approach clearly requires that the middleman service is able to at least support the two representation formats issued by A and B but on the other hand allows you to use services not directly under your control. If at least one of the services though is under your control, directly adding the not-yet-supported media type could be potentially less work in the end. Especially when certain library support for the media type is already available or can be obtained easily.
In a REST architecture clients and servers aren't build with the purpose of knowing the other one by heart. This is already a hint that there is a strong coupling between these two. They shouldn't be aware of the others "API" other than that they use HTTP as transport layer and URIs as their addressing scheme. All other stuff are negotiated and discovered on the fly. If they don't share the same language capabilities the server will responde with a 406 Not Accepttable response that informs a client that they don't speak the same languages and thus won't be able to communicate meaningfully.
As mentioned before, REST is all about introducing indirections to aid in the decoupling intent which allows servers to evolve freely in future without those changes breaking clients as these will just coop with the change. Therefore, eventual change in future is an inherent design concept. If at least one participant in a REST architecture doesn't respect these design concepts they are a potential candidate for introducing the problems traditional RPC services did in the past, like breaking clients on a required change, maintaining v2/3/4/.../n of various different APIs and scaling issues due to the direct coupling of client and servers.
Not sure why you need to distinguish it in the path and why the domain or subdomain is not enough for it:
A: PUT x.example.com/apples -> X: PUT b.example.com/apples
B: GET x.example.com/apples -> X: GET a.example.com/apples
As of the model, you want to do PUSH-PULL in a system which is designed for REQ-REP. Let's translate the upper: pushApples(apples) and pullApples() -> apples if this is all they do, then PUT and GET are just fine with the /apples URI if you ask me. Maybe /apples/new is somewhat more expressive if you need only the updates, but I would rather use if-modified-since header instead and maybe push with if-unmodified-since.
Though I think you should describe what the two service does, not what you do with the apples, which appear to be a collection of database entities instead of a web resource, which is several layers above the database. Currently your URIs describe the communication, not the services. For example why is X necessary, why don't they call each other directly? If you can answer that question, then you will understand what X does with the apples and how to name its operations and how to design the URIs and methods which describe them.
Suppose I have two models, Order and Customer. I've implemented an API that lets you filter on both:
/orders?status=fulfilled
/customers?city=Atlanta
But what if I want to search for orders in a fulfilled status, whose associated customer also lives in Atlanta? Is it RESTful to do something like /orders?status=fulfilled&customer.city=Atlanta? Or is there a canonical format for doing this sort of thing?
Is it RESTful to do something like /orders?status=fulfilled&customer.city=Atlanta?
Yes.
is there a canonical format for doing this sort of thing?
No.
You will normally want to choose a resource identifier that is compatible with a standardized URI Template because that lets you leverage pre-existing libraries.
But there are a lot of different ways you can expand variables into a template.
A query part composed of application/x-www-form-urlencoded key value pairs is a common choice; it gives you compatibility with HTML forms "for free". But if you aren't expecting clients to interact with your API via web pages, maybe that's not too important.
URI spellings are a lot like spellings of variable names; the machines don't care. You, therefore, have extra degrees of freedom that you can use to make life easier for some people: your clients looking at identifiers in their browsing history, your operations people looking in logs, your technical writers trying to document the API....
You'll probably want to choose something that is convenient for yourself -- so make sure that your design fits well with your routing framework.
Choosing identifier spellings that direct these requests to the same controllers that you are already using vs. a new controller -- that's entirely up to you. Part of the point of the API is that the implementation details are hidden from the client and can be changed without breaking the interface.
I'm currently redesigning an application where we have a single API (.NET Core 3.1) and two frontend (React) applications. In our current solution we share the same endpoints for both clients, meaning that there is an overhead of data sent from the API because both clients need different information.
I'm looking for a convenient way to split the API so we end up having two different responses, depending on which client is sending the request. I see a few options but I'm quite unfamiliar with pros and cons (besides the obvious ones) of these approaches since I never planned an application for multiple clients.
Single endpoint, different data returned depending on a header/query param
Split the API into two APIs (but where should common endpoints land? creating the third API is an overhead for us)
Split controllers into two when necessary (perhaps using partial classes?) and just implement GET api/resourceX/client1 separately from GET api/resourceX/client2
But maybe there already is a build-in solution for this in .NET Core that I'm not aware of? I tried looking for solutions but ended up getting nowhere near the answer - perhaps my keywords failed me.
This question is somewhat opinion based and you did not give us much details about how different the needs of the two clients are, but I try to answer it.
I have the assumption that you do a CRUD API and you just serve data from database without much transformation or processing in your code. This is ok, but keep in mind that REST should be built around operations and not around data types and CRUD if we use the WSDL terms. This is somewhat related to anemic domain model (defined by Martin Fowler).
If the users of the two clients are the same, then I would add more endpoints to cover the different types of queries. You can use URI templates for this e.g. /stuff?filter=xyz&view=verbose. If you want to support arbitrary queries, then it is better to use a standard solution for URI queries e.g. odata instead of building your own query language. You can use headers too, but as far as I know standard HTTP headers are a lot less flexible than URI queries.
If you have different user groups for different clients based on the privileges e.g. staff and customers, then you can serve different data for the same endpoint based on the privileges. Be aware that if you handle both regular users and admins with a single client, then the code of the client can contain hints about what is accessible for an admin. If this is an issue, then you need to split up the code of the client into multiple files and serve the admin files only for people with admin privileges. Setting the proper cache header is important in this case too. Another possible solution to have different clients for different user groups.
Be aware that in the case of real REST your server gives the URIs or URI templates to the clients just like a webserver gives the links and forms to the browser. This is because the URIs can change in time and it is a lot easier to keep backward compatibility this way. The clients know what a link does based on the metadata you send with the link e.g. IANA link relations, RDF vocabularies, etc. So the only URI you need to hardcode into your clients should be the root URI of the API. Most of the people don't try to meet with this REST constraint, because it requires somewhat different than the usual mindset to do it.
I am trying to follow RESTful principles and a little confused on how "Eager" or "Lazy" endpoints would be set up.
For example, a
Shop has many Products
Products have many Ingredients.
Products have many Packging
Of course a "bad" endpoint that would fetch eagerly would be:
api/shop/1
Would return shop id 1's details but also with:
ALL the Products
ALL the Product's Ingredients
ALL the Product's Packging
This of course is a crazy model...so I can only guess RESTful is "always lazy" by default?
But with "lazy be default" say you want to get 10 different products AND their ingredients...
api/shop/1/product/1/ingredients
api/shop/1/product/2/ingredients
api/shop/1/product/3/ingredients
The number of requests is getting a little high...10 seperate HTTP requests for the 10 products.
So lastly, do you instead tend to design the RESTful endpoints based on what the front-end/consumer may want as opposed to modelling the business/database?
api/shop/1/product-details?productId=1,2,3,4,5,6,7,8,9,10
Is the above strictly "RESTful"?
So I guess the real underlying question is sort of:
Is RESTful API design a model of the Data or a model of the Views?
Is RESTful API design a model of the Data or a model of the Views?
Views is closer -- it's a model of resources
Your data model is not your object model is not your resource model is not your affordance model. -- Amundsen
The simplest analogy is to look at java script in an HTML page
we can embed the java script in the HTML page
we can link to the java script from the HTML page.
Both approaches work - they have different trade offs, primarily in how caching works.
Coarse grained resources are somewhat analogous to data transfer objects; exchange a large representation in a single request/response, and then the client can do lots of different things with that one representation.
Fine grained resources give you more control of caching strategies (the different parts can expire at different times), and perhaps respond better to scenarios where we expect the client to be sending back edited representations of those resources.
One issue that fine grained resources have had is the extra burden of round trips. HTTP/2 improves that story, as server push can be used to chain representations of multiple resources onto a single response -- all of the fine grained resources can be sent in a single burst.
But even so, we're talking about identifying resources, not database entities.
https://stackoverflow.com/questions/57420131/restful-syntax-is-it-eager-lazy-or-both
That's an identifier for a web page about a question
https://api.stackexchange.com/2.2/questions/57420131?site=stackoverflow
That's a different resource describing the same question.
REST API's aren't about exposing your data model via HTTP, they are about exchanging documents so that a client can navigate a protocol that gets useful work done. See Webber 2011.
I've searched for this answer in many places, but I just can't seem to understand the purpose of these services.
What exactly are web APIs meant to do? I've used Spring Boot quite extensively over the past few months, though without touching its REST services portion. I was recommended to check out ASP, and specifically use its web-API items, but I have to say I'm just baffled.
How exactly is the returning of just plain data useful? In Spring, I've used models and views, which are great and useful for directing users around. But that doesn't seem to be the goal of REST APIs. So is the main idea to separate the API from the server? But why do that, when I can just as easily separate the model from the controller anyways, following the MVC pattern? As far as I can tell, there's no real way to return a view with the JSON (or whatever format the data is), so that would necessitate another server, just to deal with providing the views, no?
I'm assuming it's faulty, per-existing information that I have that's getting me stuck up here, but I just don't understand what's the point of a service that only spits out data, yet is far more removed than the model in MVC.
What exactly are web APIs meant to do?
The best summary that I know of comes from Roy Fielding
REST is intended for long-lived network-based applications that span multiple organizations.
The reference application for the REST architectural style is the World Wide Web.
The point being that, if your API is "of the web", then you get to take full advantage of the work that has already been done for you: browsers, caches, servers, well understood media-types, code-on-demand, and so on.
is the main idea to separate the API from the server?
Really, the main idea is to separate the implementation from the messaging. As far as the outside world is concerned, your service is just a web site.
Web Services are used to fetch the data from some other application, only data is fetched and view is prepared by consuming application.
Example if you pass the customer number to web service then only data is received and its your responsibly to display the data in proper asp/jsp or any other view technology