Service Management¶
Our api.get_status implementation always returns 200 OK,
but real world APIs return different kinds of errors.
An interoperable API should:
- fail fast, avoiding that application errors result in stuck connections;
- implement a clean error semantic.
A Service Management framework should set the following expectations:
- if the Service is unavailable, we must return
503 Service Unavailablehttp status - we must return the
Retry-Afterheader specifying the number of seconds when to retry.
title: Circuit Breaker pattern
graph LR
A[Client] --> B[API] B --> C{Is the service available?} C -- Yes --> D[Process request] C -- No --> E[Return 503 with Retry-After header]
To implement this we must:
- add the returned headers in the OAS3 interface;
- pass the headers to the flask Response
Exercise¶
Modify the OAS3 spec in ex-04-01-headers.yaml and:
- add a
503response to the/statuspath; - when a
503is returned, theretry-afterheader is returned.
Hint: you can define a header in components/headers like that:
components:
headers:
Retry-After:
description: |
schema: type: integer format: int32 example: 30Retry contacting the endpoint *at least* after seconds. See https://tools.ietf.org/html/rfc7231#section-7.1.3
Or just $ref the Retry-After defined in <components.oas3.yaml#/components/headers/Retry-After>
Modify api.py:get_status such that:
- returns a
503on 20% of the requests; - when a
503is returned, theretry-afterheader is returned; - on each response, return the
Cache-Control: no-storeheader to avoid caching on service status.
Bonus track: Google post on HTTP caching
from random import randint
from connexion import problem
def get_status():
headers = {"Cache-Control": "no-store"}
p = randint(1, 5)
if p == 5:
return problem(
status=503,
title="Service Temporarily Unavailable",
detail="Retry after the number of seconds specified in the the Retry-After header.",
headers=dict(**headers, **{'Retry-After': str(p)})
)
return problem(
status=200,
title="OK",
detail="So far so good.",
headers=headers
)
--
Reusing default responses¶
As 503 is a quite recurring response, it's worth to define it in a reusable yaml file,
so that every path can reuse it.
Exercise: reusable responses¶
In the following exercise you should edit ex-04-01-headers.yaml and:
- move the
503response from the/statuspath definition to thecomponents/responsesone, eg.
components:
responses:
503ServiceUnavailable:
...
- reference
#/components/responses/503ServiceUnavailablein the/statuspath
Your new file is semantically equivalent to the previous one: check that you can
connexion run your file in terminal!
connexion run /code/notebooks/oas3/ex-04-01-headers.yaml