kin-openapi icon indicating copy to clipboard operation
kin-openapi copied to clipboard

Request validator checks ReadOnly Properties when using AllOf

Open neumantm opened this issue 1 year ago • 1 comments

This is a follow-up to #71

I have a very similar problem to #71, in that the request validator enforces the existence of a readOnly property. The difference is that the schema is split and then stitched together with a allOf:

components:
  schemas:
    Element:
      type: object
      properties:
        id:
          type: integer
          readOnly: true
        name:
          type: string
        description:
          type: string
    Element_full:
      allOf:
        - $ref: "#/components/schemas/Element"
        - required:
            - id
            - name

With this schema the request validator currently enforces the existence of id and name (but then dissallows id because of readOnly). However, the request validator should only enforce the the existence of name.

neumantm avatar Mar 18 '24 12:03 neumantm

Runnable example
package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"net/http"

	"github.com/getkin/kin-openapi/openapi3"
	"github.com/getkin/kin-openapi/openapi3filter"
	"github.com/getkin/kin-openapi/routers/gorillamux"
)

var schema = []byte(`{
    "openapi": "3.0.2",
    "info": {
        "version": "1.0.0",
        "title": "title",
        "description": "desc",
        "contact": {
            "email": "email"
        }
    },
    "components": {
        "schemas": {
            "Element": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "integer",
                        "readOnly": true
                    },
                    "name": {
                        "type": "string"
                    },
                    "description": {
                        "type": "string"
                    }
                }
            },
            "Element_full": {
                "allOf": [
                    {
                        "$ref": "#/components/schemas/Element"
                    },
                    {
                        "required": [
                            "id",
                            "name"
                        ]
                    }
                ]
            }
        }
    },
    "paths": {
        "/elements": {
            "post": {
                "description": "Create a new element",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/Element_full"
                            }
                        }
                    }
                }
            },
            "responses": {
                "201": {
                    "description": "ok"
                },
                "400": {
                    "description": "The server could not understand the request due to invalid syntax",
                }
            }
        }
    }
}
`)

type Request struct {
	Name string `json:"name"`
}

func main() {
	loader := openapi3.NewLoader()
	doc, _ := loader.LoadFromData(schema)
	_ = doc.Validate(loader.Context)

	router, _ := gorillamux.NewRouter(doc)

	b, _ := json.Marshal(Request{Name: "test"})

	httpReq, _ := http.NewRequest(http.MethodPost, "/elements", bytes.NewReader(b))
	httpReq.Header.Add("Content-Type", "application/json")

	route, pathParams, _ := router.FindRoute(httpReq)

	requestValidationInput := &openapi3filter.RequestValidationInput{
		Request:    httpReq,
		PathParams: pathParams,
		Route:      route,
	}
	if err := openapi3filter.ValidateRequest(loader.Context, requestValidationInput); err != nil {
		panic(err)
	}

	fmt.Println("Did not fail")
}

neumantm avatar Mar 18 '24 13:03 neumantm