Idempotent Requests
0. Introduction - Idempotency Idea
Idempotency is a key principle in web API design. It ensures that performing the same operation multiple times results in the same outcome as if the operation was performed only once. This is especially important in scenarios where a request fails (e.g., due to a network error or timeout), and the client retries the request. By enabling idempotency, APIs provide a reliable way to handle such retries without risking unintended side effects like duplicate operations.
1. Idempotency in Mobilitybox API
Basics
The Mobilitybox idempotency works by saving the resulting status code and body of the first request made for any given Idempotency-Key
, regardless of whether it succeeds or fails. Subsequent requests with the same key return the same result, including 500 errors.
GETRequests
The Mobilitybox API guarantees the idempotency of GET requests. This means it is always safe to retry these operations, as they do not cause side effects or change the server's state.
PUT and DELETERequests
According to HTTP semantics, the PUT and DELETE verbs are idempotent, and the PUT verb in particular signifies that a target resource should be created or replaced entirely with the contents of a request’s payload. So PUT and DELETE requests are idempotent inside the Mobilitybox API as well.
POSTRequests
For POST requests, idempotency can be achieved by including an Idempotency-Key
in the request header. This header ensures that the API tracks the operation and prevents it from being executed more than once, even if the client retries the request.
Example Scenario: If a network error prevents a response from being received while creating an Order, the client can safely retry the operation by including the same Idempotency-Key
, ensuring that no duplicate order object is created.
Validity of the Idempotency-Key
The Idempotency-Key
is valid for at least 24 hours. During this time, retrying the same request with the same key guarantees the operation will not be repeated. After this time has elapsed, there is no certainty that the key and the response are still stored in the cache.
We generate a new request if a key is reused after the original is pruned.
The idempotency layer compares incoming parameters to those of the original request and errors if they’re the same to prevent accidental misuse.
We save results only after the execution of an endpoint begins. If incoming parameters fail validation, or the request conflicts with another request that’s executing concurrently, we don’t save the idempotent result because no API endpoint initiates the execution.
Status Codes and Error Messages
Using idempotency of the Mobilitybox can cause new status codes or error messages:
Accepted: If an request timeouts on clientside, the Mobilitybox still execute the operation. When the client sending the same request again and the operation is still being processed it will return 202 - Accepted.
Conflict: When used the same Idempotency-Key
for two different requests (for example having a different request body or using a different Api-Key) the API will return a Conflict Error.
Internal Server Error: If an internal error occurs (like dropping internal connection caused by restarting of an internal component) the result would be an Internal Server Error.
HTTP Status Code References:
Code | Tag | Description/Message |
---|---|---|
200 | OK | Everything worked as expected. |
201 | Created | Everything worked as expected and a resource was created or changed. |
202 | Accepted | The request is already being processed. Please retry again in a few seconds. |
400 | Bad Request | The request was unacceptable, often due to missing a required parameter. |
401 | Unauthorized | No valid API key provided. |
403 | Forbidden | The API key doesn’t have permissions to perform the request. |
404 | Not Found | The resource was not found. |
409 | Conflict | The request conflicts with another request (perhaps due to using the same idempotent key). |
422 | Unprocessible Entity | Validation Error |
500 | Internal Server Error | Internal Server Error |
2. How to make your request Idempotent
Sending Idempotency Keys
Idempotency keys are sent in the Idempotency-Key
header. Use them for all POST requests to the Mobilitybox Ticketing API.
All POST requests accept idempotency keys. Don’t send idempotency keys in GET, PUT and DELETE requests because it has no effect. These requests are idempotent by definition.
When you don't send an Idempotency-Key
the result will not be cached and it has to be assumed that the same operation will be performed twice.
Requirements for Idempotency Keys
A client generates an Idempotency-Key
, which is a unique key that the server uses to recognize subsequent retries of the same request.
How you create unique keys is up to you, but we require and suggest the following things:
- Ensure that the key is unique enough to identify a specific operation within your account
- Keys must not repeat during their validity window to avoid accidental request duplication.
- The
Idempotency-Key
must be at least 36 and no more than 255 characters long.
Best Practices for Generating Idempotency Keys
We recommend using a well-established algorithm, such as UUID v4, to generate sufficiently random and unique tokens. This minimizes the risk of collisions and ensures reliable operation tracking.
Example:
Idempotency-Key: "10adfcd5-f490-490f-a384-4f4a17831f42"
Best Practices for Handling long running Requests
Certain requests to the Mobilitybox API may take longer to process, particularly during periods of high server load. This can result in client timeouts even though the operation is still being executed on the server.
To address such scenarios, the provided Idempotence option allows clients to retrieve the potential response of a previously submitted request. This ensures that clients can obtain results even if the initial request was interrupted due to a timeout.
Additionally, for requests that are still being processed, the server will respond with a 202 Accepted status code. This indicates that the operation is in progress and not yet completed.
We recommend that clients implement an exponential backoff algorithm when retrying requests after encountering errors or delays. This approach helps manage retries efficiently while avoiding excessive load on the server.
Identifying Replayed Responses
When the server replays a previously executed response due to a request retry, the response will include the following header:
Idempotent-Replayed: true
This header allows clients to distinguish between a fresh response and a replayed one, aiding in debugging and monitoring. This header will also be set if the return is an error like 4XX or 5XX.
3. Example Implementation
The following pseudo code example showing how to use the Idempotency for the order api.
FUNCTION CreateOrderInMobilitybox
SET product_id = "mobilitybox-product-uuid"
SET api_url = "https://api.mobilitybox.com/v7/ticketing/order.json"
# Generiere eine eindeutige ID für die Idempotenz
SET idempotency_key = GENERATE_UUID_V4()
# Erstelle den Header mit dem Idempotency-Key
SET headers = {
"Content-Type": "application/json",
"Idempotency-Key": idempotency_key
}
# Beispiel-Payload
SET payload = {
"product_ids": [product_id],
"optional_order_reference": "User ID: XXX"
}
order_response = MakeOrderRequestInMobilitybox(url, headers, payload)
SaveOrderIntoDatabase(order_response)
END FUNCTION
FUNCTION MakeOrderRequestInMobilitybox(url, headers, payload, attempt = 0)
WAIT 2^attempt seconds
SET timeout = 3 seconds
TRY
response = HttpPost(url, payload, timeout)
IF response.statuscode IS 202
MakeOrderRequestInMobilitybox(url, headers, payload, attempt + 1)
ELSE
return response
END IF
CATCH Timeout
MakeOrderRequestInMobilitybox(url, headers, payload, attempt + 1)
END TRY
END FUNCTION