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

Handling of entity tags "etag" #21

Open
Leemur89 opened this issue May 7, 2024 · 3 comments
Open

Handling of entity tags "etag" #21

Leemur89 opened this issue May 7, 2024 · 3 comments

Comments

@Leemur89
Copy link

Leemur89 commented May 7, 2024

Hello,

Some endpoints require an "If-Match" header, for which value comes from a previous request "Etag" header
This is mostly to to avoid concurrent update of a resource
This is used on the updating methods (UPDATE/PUT), and the Etag comes from a GET method
I suggest the algorithm as follow:

If PUT/UPDATE and if If-Match in headers
  Then
    perform a GET on the same endpoint
    From the response get the ETAG header
    Use that value in the If-Match

Also to be even cleaner there should be some consistency check on the OAS to ensure that the endpoint well has a matching GET, and that it contains an ETAG header, and a check on the response in case it does not contain that ETAG
There could also be a test to validate the 412 response as this is what is being replied in case the If-Match does not match the ETAG

@robinmackaij
Copy link
Collaborator

Can you share the OAS you're using with me? I haven't encountered the If-Match header before so there's currently no support for it. From the looks of it, this could be generically supported, but I'd need an actual OAS to see the structure.

I can't really give you a timeline for this at the moment, but it'd be nice to add the support. I'm not sure if this could also be supported using the mappings file; I'd have to dig into the details to see if the headers could be dynamically updated by performing the required pre-request within a Dto.

@Leemur89
Copy link
Author

here is an OAS:

{
  "paths": {
    "/api/v1/items/{item_id}": {
      "delete": {
        "description": "Delete a specific item",
        "operationId": "deleteItem",
        "parameters": [
          {
            "description": "Current ETag of a resource.",
            "in": "header",
            "name": "If-Match",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "No content"
          },
          "412": {
            "description": "Precondition Failed: The provided etag did not match with the current resource"
          }
        },
        "summary": "Delete item",
      },
      "get": {
        "description": "Get an item by ID",
        "operationId": "getItemById",
        "responses": {
          "200": {
            "description": "successful operation",
            "headers": {
              "ETag": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "created_at": {
                      "format": "date-time",
                      "type": "string"
                    },
                    "id": {
                      "example": "72a8048c-35d2-4745-8af1-7670ef438105",
                      "format": "uuid",
                      "readOnly": true,
                      "type": "string"
                    },
                    "itemname": {
                      "minLength": 1,
                      "type": "string"
                    }
                  },
                  "type": "object"
                }
              }
            }
          },
          "404": {
            "description": "The resource does not exist"
          }
        },
        "summary": "Get item by id",
      },
      "parameters": [
        {
          "description": "the uuid of the item",
          "in": "path",
          "name": "item_id",
          "required": true,
          "schema": {
            "type": "string",
            "format": "uuid"
          }
        }
      ]
    }
  }
}

The GET returns a string in the ETAG, and when doing the delete the if-match should match that ETAG otherwise a 412 is returned

@Leemur89
Copy link
Author

Note that it can also happen for POST requests

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

No branches or pull requests

2 participants