MarketSquare / robotframework-openapitools

Apache License 2.0
6 stars 1 forks source link

Handling of entity tags "etag" #21

Open Leemur89 opened 5 months ago

Leemur89 commented 5 months ago

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 commented 4 months ago

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 commented 4 months ago

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 commented 4 months ago

Note that it can also happen for POST requests