How is possible to handle timeouts in time consuming operations in a REST API. Let's say we have the following scenario as example:
A client service sends a request to insert a resource through a REST API.
Timeout elapses. The client thinks the insertion failed.
REST API keep working and finishes the insertion.
Client do not notify the resource insertion and it status is "Failed".
I can think I a solution with a message broker to send orders to a queue and wait until they are solved.
Any other workaround?
EDIT 1:
POST-PUT Pattern as has been suggested in this thread.
A Message Broker (add more complexity to the system)
Callback or webhook. Pass in the request a return url that the server API can call to let the client know that the work is completed.
HTTP offers a set of properties for invoking certain methods. These are primarily safetiness, idempotency and cacheability. While the first one guarantees a client that no data is modified, the 2nd one gives a promise whether a request can be reissued in regards to connection issues and the client not knowing whether the initial request succeeded or not and only the response got lost mid way. PUT i.e. does provide such a property, i.e.
A simple POST request to "insert" some data does not have any of these properties. A server receiving a POST request furthermore processes the payload according to its own semantics. The client does not know beforehand whether a resource will be created or if the server just ignores the request. In case the server created a resource the server will inform the client via the Location HTTP response header pointing to the actual location the client can retrieve information from.
PUT is usually used only to "update" a resource, though according to the spec it can also be used in order to create a new resource if it does not yet exist. As with POST on a successful resource creation the PUT response should include such a Location HTTP response header to inform the client that a resource was created.
The POST-PUT-Creation pattern separates the creation of the URI from the actual persistence of the representation by first firing off POST requests to the server until a response is received containing a Location HTTP response header. This header is used in a PUT request to actually send the payload to the server. As PUT is idempotent the server simply can reissue the request until it receives a valid response from the server.
On sending the initial POST request to the server, a client can't be sure whether the request reached the server and only the response got lost, or the initial request didn't make it to the server. As the request is only used to create a new URI (without any content yet) the client may simply reissue the request and in worst case just create a new URI that points to nothing. The server may have a cleanup routine that frees unused URIs after a certain amount of time.
Once the client receives the URI, it simply can use PUT to reliably send data to the server. As long as the client didn't receive a valid response, it can just reissue the request over and over until it receives a response.
I therefore do not see the need to use a message-oriented middleware (MOM) using brokers and queues in order to guarantee reliable messaging.
You could also cache the data after a successful insertion with a previously exchanged request_id or something of that sort. But I believe message broker with some asynchronous task runner is a much better way to deal with the problem especially if your request thread is a scarce resource. What I mean by that is. If you are receiving a good amount of requests all the time. Then it is a good idea to keep your responses as quickly as possible so the workers will be available for any requests to come.
Related
I am a bit confused by the terminology of REST APIs being stateless. For example, if we had a To-Do list API, and one of the endpoints was used to update or delete entries, then each request does not happen in isolation.
If I create an entry before someone else queries the total entries, then their response will depend on my response.
But, PUT is seen as a verb of REST APIs. Can someone help me clear my confusion?
Stateless means that you store the client state on the client and send it with each request instead of storing it on the server. The latter is the classical server side sessions, where you have a session cookie with the session id and the server stores the session data in the database or file system. This does not scale well for Facebook size applications, that's why they rather send the session data with each request. You can ensure that the session data is not modified by the client if you sign it with a private key stored on the server. So there is signature verification by each request, but still it is less expensive than maintaining session data for more than 1M users in a database and syncing it around the globe with multiple servers to solve the single point of failure problem too. They rather send the session data with each request and if it passes the verification, then the request is handled by any node chosen by the load balancer without touching the database to get session data.
As of the part of the question related to concurrent calls, it can be solved with resource versioning. You can send the actual ETag of the resource and use the if-match header with your PUT request so the server will be able to figure out which version you request is based on. If there is a newer version, then the ETag won't match and the server will reject the request. There can be other ways to solve concurrency, it always depends on your application how you handle it.
In REST using HTTP, are status codes relevant to the request, or the resource?
In non-REST HTTP request/response calls, the status code refers to the success/failure/etc of the request being made. Did the request fail because the client sent an invalid request? Then return 400, and so on.
But with REST, the URI is stated to refer to a "resource", and the status code often appears to be used to refer to the resource (i.e. it's metadata about the resource). But if the request to retrieve the resource fails, how does the client know if there's a problem with the resource, or just a problem with the request to GET the resource?
My question is - have I understood that correctly? And if so, what happens if the request fails server-side?
Example:
Client calls POST /api/order/ with a payload.
Server validates the request and enqueues it before immediately returning 202 Accepted with Location: /api/order/43573/status and Retry-After: 60.
Client waits the requisite 60 seconds before polling GET /api/order/43573/status.
Server returns 202 Accepted, including a payload with more information and Retry-After: 60.
(The waiting and polling continues until processing completes.)
One of two things happens:
Success
Background processing succeeds.
Client polls GET /api/order/43573/status.
Server returns 303 See Other, with Location: /api/order/43573.
Client calls GET /api/order/43573.
Server returns 200 OK with appropriate payload.
Failure
Background processing fails for some reason.
Client polls GET /api/order/43573/status.
Server returns 200 See Other, with payload indicating failure.
My problem is that last request - returning 200 OK seems right for the web request, but the only body it'll ever contain is information about failure.
TL;DR
a HTTP response code belongs to the response issued for a request and not the resource itself
Unfortunately there is a widespread misunderstanding of what REST is and what it isn't.
As Jim Webber correctly pointed out, HTTP is an application protocol whose domain is the transfer of documents over a network and any business activities we deduce are just side effect of the actual document management. It is therefore our task to narrow down these side-effects to something useful.
REST or more precisely the REST architecture is a set of constraints that mainly deal with the decoupling of clients from servers by relying on standardized document types / representation formats and on an interaction model that is similar to the one used on the Web. The main goal here is to allow server to evolve freely in future without having to fear that introduced changes will break clients, as they only operate on standardized document formats they'll understand and are able to process. Through careful design and focus on above mentioned standardized formats the interoperability between different systems should be guaranteed.
In example, REST puts a strong focus on how server teach clients on what they can do next. Jim Webber compared it to a text based computer game where you are given options on what to do next. He later on gave also the example of a typical Web based Amazon-like checkout where you play along a given predefined checkout protocol until you reached the end of that state-machine in some way or the other.
A strong hint that a HTTP response code belongs to the response issued for a request and not the resource itself is, when you i.e. have resource hidden behind some authentication. In the first request you do not include an Authorization HTTP request header which then results in a 401 Unauthorized status code. Your browser will now ask you for a username and password and upon entering it the same reuqest will be reissued but this time with the Authorization header set which then might succeed, depending on your input and/or the server implementation.
what happens if the request fails server-side?
HTTP is based upon a request-response model meaning that for each request a response must be issued. As mentioned before, the HTTP status code returned here acts as coordination metadata that allows a client to act upon. I.e. with the above example with the 401 Unauthorized status code the browser (client) asked for credentials to send along and reissued the request.
Further, each of the HTTP operations used contain some defined properties a client can assume to hold true. Whether a server sticks to these is a different story, but a well-behaved server should. Such properties are safety and idempotency. The primer one does guarantee that a resource state wont be change when a request issued with such an operation is processed. Prominent examples here are GET and HEAD which are used to retrieve docuements. Itempotency is a property that is useful in case of a network connection issue and the client can't be sure whether the request reached the server at all or just the response got lost mid-way. It basically allows a server to resend the request without further thinking as the outcome here should be the same regardless if the initial request was processed at the server or not. PUT and DELETE are often used as example here.
Other HTTP operations such as POST or PATCH don't have such properties, unfortunately. So in case of a network issue the client can't be sure whether a request can be issued automatically. I.e. in case of a network issue while performing an order and later on resending the request, a server might have taken the order twice. As such, if something cruicial should be performed, such a payment, an expansive order or the like it is probably better to use an idempotent operation i.e. by using a POST-PUT creation pattern.
A further solution to prevent processing of certain requests my be to send them as conditional requests containing either ETag, If-Modified-Since or similar request headers. This though usually is used if certain unsafe operations should be performed on very specific resource states. I.e. a patch is usually dependent on the current, checkout version. If some changes are done to the remote state in the meantime, we usually don't want the patch to be applied to the altered version and as such want the request to fail which forces us to download the new state and modify the request in a way so that the desired outcome will be as desired.
According to your question:
While it seems natural to combine 202 Accepted with a Location response header, unfortunately RFC 7231 does not mention the location header as requirement for a 202 Accepted response nor does the definition of the Location header state that it can be used in a 202 Accepted response and as such, according to a response from Roy Fielding, a Location header outside of 201 Created and 3xx repsonses the Location header has no defined meaning. Instead of returning a 202 Accepted initially, you could have returned a 303 See Other response code containing a Location header for the status of the resource, which then could have returned a 202 Accepted status and later on perform a redirect to the final state as you did.
My problem is that last request - returning 200 OK seems right for the web request, but the only body it'll ever contain is information about failure.
According to RFC 7231
The representation sent with this response ought to describe the request's current status and point to (or embed) a status monitor that can provide the user with an estimate of when the request will be fulfilled.
So, in case the processing of a long-running process (partially) failed, the payload itself could indicate a failed processing to start with. You might also perform a redirect to a resource that then returns a 4xx status code containing i.e. a application/problem+json response payload giving hints on the reason why processing failed and so on.
I feel like 202 isn't appropriate for GET requests, so I would return 200 with a status payload until such time that returning a redirect makes sense?
The actual definition of 202 Accepted is
The 202 (Accepted) status code indicates that the request has been
accepted for processing, but the processing has not been completed.
The request might or might not eventually be acted upon, as it might
be disallowed when processing actually takes place. There is no
facility in HTTP for re-sending a status code from an asynchronous
operation.
The 202 response is intentionally noncommittal. Its purpose is to
allow a server to accept a request for some other process (perhaps a
batch-oriented process that is only run once per day) without
requiring that the user agent's connection to the server persist
until the process is completed. The representation sent with this
response ought to describe the request's current status and point to
(or embed) a status monitor that can provide the user with an
estimate of when the request will be fulfilled.
So, depending on how you interpret the request has been accepted for processing part you can return a 202 Accepted for a GET request, as the actual process might still not have been finished, or return a 200 OK response. I think the important part here is though the usage of a media type (a.k.a. representation format) a client understands and knows how to process and interpret. Based on that response a client should know whether the actual process completed with or without failures or is still pending. I have to admit though that I am currently unaware of any suitable media types that can be used to express such knowledge.
The status-code element is a 3-digit integer code describing the result of the server's attempt to understand and satisfy the client's corresponding request. The rest of the response message is to be interpreted in light of the semantics defined for that status code. -- RFC 7230
That's always true. It's part of the uniform interface constraint that we all use the same self descriptive messages, regardless of the target resource.
But with REST, the URI is stated to refer to a "resource", and the status code often appears to be used to refer to the resource (i.e. it's metadata about the resource).
I think you've been mislead here. The motivation for the uniform interface is that we can use general purpose components (browsers, caches) in our web applications because all servers use the same messages the same way. That would go right out the window if "REST" resources had different message semantics than the "non-REST" sort.
My problem is that last request - returning 200 OK seems right for the web request, but the only body it'll ever contain is information about failure.
You should probably review Jim Webber's 2011 talk. In summary: HTTP is an application protocol, the domain of that application is the transfer of documents over a network. The status line and headers are metadata for the "transfer of documents over a network" domain.
On the web, we transfer documents ("web pages") for the human beings to read. The audience for the metadata is the browser, not the human. Uniform interface means that you can use the same browser to do your banking, book shopping, track your sales funnel, and ask programming questions . It's the metadata that allows the components of the HTTP application to do useful work (ex: cache-invalidation).
So in your case, you are returning a document (technically: a representation of a resource) that describes the progress of a side effect of an earlier request, presumably with headers that describe how caches can re-use the response.
Suppose I have an API that calls a downstream service's API called /charge (POST). Suppose while doing charge, a timeout happened at the reverse-proxy and I got a 5xx. But the charge actually happened.
In this case, I would respond with a 5xx to my consumer. Now, if the consumer calls with the same idempotent key, then his request can succeed as the downstream service would return a cached copy of the response. But if he uses a different idempotent key while calling my API, he would keep getting 409s as the payment was already charged.
Here's my two questions:
How does the client know when to retry with the same idempotentId or initiate a new request altogether?
(Augmenting the previous question) How does the UI make the decision to use different idempotent Ids? Does each new request contain a new Id and only the retry logic reuses the same Id?
Basically, I am trying to understand idempotent keys from the client
's perspective.
A timeout should be retried automatically a few times before returning a failure response to the user. Thus if the error is transient, the user wouldn't notice any issue (except possibly a negligible delay in response).
The request originating system should maintain a log of all requests with their status. Thus if the glitch persists for a longer duration, the system can retry failed requests periodically as well as provide a detailed UI view of the submitted requests to the user. This eliminates the need for the user to ever retry a request. The system will do that on user's behalf.
Lately, I have started adding status codes to my responses instead of returning them directly.
Let's assume /person/1 returns a person with id 1 from the DB. If the person does not exist, should I return 404 status? How am I supposed to differentiate if the endpoint does not exist on the server or the resource does not exist?
Now, let's assume I have a POST endpoint for inserting users. What if that endpoint checks if the email is formed correctly and I return 400? How should I know if the request was not formed correctly and did not route to any servlets or if it indeed reached the servlet which decided that email is badly formed?
Is it a good practice to always return a 200 OK response from all of my servlets indicating that the application has done its job regardless of the outcome and write the status in a json field status or is this an overkill and an anti-pattern?
I do not have a lot of experience nor knowledge of HTTP servers so I am not sure I am explaining this (nor using it) right, so I apologize for the broad descriptions.
Let's assume /person/1 returns a person with id 1 from the DB. If the person does not exist, should I return 404 status? How am I supposed to differentiate if the endpoint does not exist on the server or the resource does not exist?
To a client it doesn't matter whether the resource or the endpoint did not exist. All it is told by the server is that for the given URI there is no representation available.
As inf3rno already mentioned a client is usually served all of the URIs a client will need by the server directly in a response. Through bookmarking or including links in some external resource certain links might get invalid over time and as such a 404 Not Found response just informs the client that no representation is available for the given URI.
A client typically is also not interested in the internals of an API but just to send or receive data it can work upon.
A further misconception many users have, unfortunately, is, that they already assume certain resources to return certain types. Such types may lead to failures on the client side if the expected representation format ever changes. In addition to that the URI structure itself, including any path, matrix and query parameters, should not be used to deduce any logical structure of the API, its exposed endpoints or the logical structure of the resources to other resources of that API. A URI as a whole is a pointer to a resource. A resource may have a dozens of links pointing to it. You might think of a URI as cache-key for representations returned that, on consecutive invocations are further served by the cache instead of the actual server. This is actually one of the constraints REST imposes and is widely used on the Web.
Now, let's assume I have a POST endpoint for inserting users. What if that endpoint checks if the email is formed correctly and I return 400? How should I know if the request was not formed correctly and did not route to any servlets or if it indeed reached the servlet which decided that email is badly formed?
RFC 7231 defines POST as an all-purpose tool that should be used if other methods aren't fitting for the task at hand. It explicitely states that the payload provided by that method will be processed according to the resource's own specific semantics. So, if you need to validate an email-address of a user before persisting it or before starting a calculation, background process or whatever, fine, do that :) Even PUT, which is often said to only replace the current representatin with the given one in the request, is not only allowed but also encouraged to perform verifications regarding any constraints the server has for the target resource and therefore it should refuse payloads that do not fit its expectations.
The quintesence here is, that a server should provide a client always with as much information as possible to let a client determine what to do next. Think of a Web based application which you access through your browser. If you receive a 400 Bad Request the browser will usually tell what the server didn't like about your request, i.e. incomplete syntax or missing value of a required field. The same holds true for REST APIs as they are basically just a generalization of the interaction model used on the Web. So the same concepts that apply to the Web also apply to REST :)
By that, each HTTP status code has its own semantics and should help the client to determine what the client should do next. A 400 Bad Request i.e. states that the server either cannot or will not process the request due to something that the server considers to be a client based error and it's up to the client to correct that failure and resend the request.
A 405 Method Not Allowed on the other hand indicates that the client used a HTTP method not supported by the targeted endpoint. An error response not only indicates that to the client but also which methods are allowed on the targeted endpoint within an Alllow response header.
Each of the HTTP status codes specified in RFC 7231 has their own semantics and its probably advisable to at least skim over these. You can also lookup all available status codes at IANA that provides links to the specificaton describing those status codes.
Is it a good practice to always return a 200 OK response from all of my servlets indicating that the application has done its job regardless of the outcome and write the status in a json field status or is this an overkill and an anti-pattern?
As with error codes also the success codes (in the 200 range) have their own semantics. If a new resource is created as outcome of processing a request (via PUT or POST) a client should be notified with a 201 Created status response that furthremore contains a HTTP Location header containing a URI targeting at the newly created resource.
If a server may take some time in order to calculate a response it is probably advisable to return a 202 Accepted response in order to inform a client about the pending request. A client can later on poll for the request either after some threshold period or after getting notified by the server through callback mechanisms such as email-notification or similar stuff. Due to German law restrictions i.e. German companies have to maintain archives of their messages exchanged via EDI. We, as an EDI provider, offer our clients to perform an archive of their exchanged messages via triggering one of our HTTP endpoints. Depending on the number of messages exchange by that company and the time period selected the archive should be generated for, this process may take some time (a couple of hours to be more concrete) and instead of letting the client wait for that period we simply return 202 Accepted and start the archiving process in the back. Depending on the configuration they either poll for the finished archive, get an information about the final result or directly get the archive sent through email if the file isn't to large.
204 No Content is also quite useful if a client performs an update onto a resource. As PUT is generally defined as replace the current representation with the one provided in the payload, upon receiving a 204 No Content response the client knows that the server applied the update and the current representation does look like the requested one by the client. Thus the server does not need to inform the client further how the current representation looks like, as the client already knows how it should look like. However, in case the server had to convert the payload to a different representation that maybe lead to an other outcome, it is probably benefitial to inform a client about the new state of the resource within a 200 OK response including the a representation of the outcome of the update process.
Returning 200 OK for a failure including a JSON payload with fields indicating about the error is for sure a bad way to proceed. Not only does it give clients a wrong hint but the response might also be cached by intermediaries and returned to other clients requesting the same even when the failure might only be of temporary nature (DB crash or the like). In additon to that is such a JSON payload proabably using a non-standardized format and thus requires out-of-band knowledge to actually process the message. While we humans are quite capable of figuring out what's going on, computers aren't yet that smart on their own.
I hope you can see that HTTP offers a lot of semantics on when to use what method or response code. They are there for a reason and therefore also should be used if the circumstances are right.
In GET request, 404 status is just a response code. You have to provide error message in body of the response in case when record is not found for the id provided.
For POST request, you can return 400 error code with specifying in the body which fields are missing/failing validation.
For url not found, User will always get the 404 error code.
For succcessful GET or POST request, you can return the response with 200 status
How am I supposed to differentiate if the endpoint does not exist on
the server or the resource does not exist?
The endpoint is the IRI (URI) of the web resource in this case. If the endpoint does not exist, then there is a good chance that the web resource does not exist either. It is an unlikely scenario, since you got your URIs from the server (HATEOAS), but it can happen if something changes between two requests, e.g. the URI template changes or somebody deletes the resource. In all of these cases the 404 is a fine HTTP status code. You can elaborate in the error message or use an additional error code, but for me it does not make sense, because the URI template change is a rare event. It would make the client more flexible though, since it could clear the cache and retry with a new link.
I have a running system that process short and long running operations with a Request-Response interface based on Agatha-RRSL.
Now we want to change a little in order to be able to send requests via website in Json format so i'm trying many REST server implementation that support Json.
REST server will be one module or "shelve" handled by Topshelf, another module will be the processing module and the last the NoSQL database runner module.
To talk between REST and processing module i'm thinking about a servicebus but we have two types of request: short requests that perform work in 1-2 seconds and long requests that do work in 1 minute..
Is servicebus the right choice for this work? I'm thinking about returning a "response" for long running op with a token that can be used to request operation status and results with a new request. The problem is that big part of the requests must be used like sync request in order to complete http response.
I think I have also problems with response size (on MSMQ message transport) when I have to return huge list of objects
Any hint?
NServiceBus is not really suitable for request-response messaging patterns. It's more suited to asynchronous publish-subscribe.
Edit: In order to implement a kind of request response, you would need to message in both directions, but consisting of three logical steps:
So your client sends a message requesting the data.
The server would receive the message, process it, construct a return message with the data, and send it to the client.
The client can then process the data.
Because each of these steps takes place in isolation and in an asynchronous manner there can be no meaningful SLA or timeout enforced between when a client sends a request and receives a response. But this works nicely for large processing job which may take several minutes to complete.
Additionally a common value which can be used to tie the request to the response will need to be present in both messages. Otherwise a client could send more than one request, and receive multiple responses and not know which response was for which request.
So you can do this with NServiceBus but it takes a little more thought.
Also NServiceBus uses MSMQ as the underlying transport, not http.