Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support API fencing #48

Open
antonagestam opened this issue Jan 20, 2021 · 1 comment
Open

Support API fencing #48

antonagestam opened this issue Jan 20, 2021 · 1 comment
Labels
enhancement New feature or request

Comments

@antonagestam
Copy link

antonagestam commented Jan 20, 2021

I've introduced API fencing into django-bananas to handle the "lost update problem", that is dealing with the issue of "simultaneous" edits from multiple admins overwriting each other's changes.

It would be nice to build automatic support for this into django-bananas.js. There are now two builtin fences in django-bananas: allow_if_unmodified_since rejects updates when the given If-Unmodified-Since header is less than the stored date_modified on the model, and allow_if_match rejects updates when the given If-Match header does not contain the version of the stored model (version can be a stored or a computed value). Fences are exposed as in-header arguments in the OpenAPI schema and should be discoverable.

I'm thinking we preferably want to build in support so that these work out of the box given the resource exposes the respective fields, but with support for overriding (or composing) the source of the tokens. In the case of allow_if_unmodified_since we want to use the exposed date_modified field by default and if it exists. For allow_if_match we want to use the exposed version field by default and if it exists.

It's also possible to compose arbitrary fences that are not shipped by default (e.g. for If-Match or whatever) and we should try and build in corresponding composable building blocks into the client.

In Python composing a fence looks like this:

allow_if_not_modified_since = Fence(
    # Function that takes a request and returns the If-Modified-Since header
    # as a parsed datetime object.
    get_token=header_date_parser("If-Modified-Since"),
    # Function for comparing the header value with the stored value to
    # determine whether to  allow or reject the request.
    compare=operator.gt,
    # function that takes a model instance and returns its date_modified
    get_version=parse_date_modified,
    openapi_parameter=openapi.Parameter(...),
    # Specifies status code of rejected requests
    rejection=NotModified("The resource is unmodified"),
)

What do you think? Is this feasible to build automatic support for? If we need to prioritize I think automatic discovery and support for the two builtin fences should be supported, but it'd be really nice to get composability for arbitrary fences from the get-go.

I'd be happy to write this if no-one else bites, but I'd probably need some pointers to understand where something like this could be plugged in.

@antonagestam antonagestam added the enhancement New feature or request label Jan 20, 2021
@antonagestam
Copy link
Author

Also, different fences have different status codes for rejection, e.g. If-Unmodified-Since and If-Match use 412 Precondition Failed but headers like If-Modified-Since use 304 Not Modified. So support for specifying the status code for rejection and showing a reasonable error should preferably be builtin too.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

1 participant