Closed9

kin-openapiのopenapi3filterの使い方を把握する

podhmopodhmo

自分でopenapiを利用したvalidationをしたかった。

  • request validation
  • response validation

の2種類があるがそれぞれについて調べたい

podhmopodhmo

いろいろ調べてみると deepmap/oapi-codegen自体ではvalidationをしておらず、getkin/kin-openapi/openapi3filterでvalidationをしているようだった。

とりあえず、この辺を観る必要がある(routersの方を観る必要がある理由は後述する)。

https://pkg.go.dev/github.com/getkin/kin-openapi@v0.97.0/openapi3filter
https://pkg.go.dev/github.com/getkin/kin-openapi@v0.97.0/routers/gorillamux

利用方法自体はexamplesを見れば良い

podhmopodhmo

基本的には以下のような形になる。

  1. yamlを読み込んで、swagger objectの生成 ( openapi3.T)
  2. swagger objectを利用して、routes.Router objectを生成 (ここで gorillamux パッケージを利用することになる)
  3. (request毎に)routes.RouterのFindRoute()を使ってRoute objectを取得する
  4. (request毎に) Route objectを使って openapi3filter.RequestValidationInputを作り、ValidationRequest()を呼ぶ
  5. (request毎にresponseに対して) openapi3filter.ResponseValidationInput を作り、ValidationResponse()を呼ぶ

大まかにはこういうイメージここで routes.Router は以下のようなinterface

type Router interface {
	// FindRoute matches an HTTP request with the operation it resolves to.
	// Hosts are matched from the OpenAPIv3 servers key.
	//
	// If you experience ErrPathNotFound and have localhost hosts specified as your servers,
	// turning these server URLs as relative (leaving only the path) should resolve this.
	//
	// See openapi3filter for example uses with request and response validation.
	FindRoute(req *http.Request) (route *Route, pathParams map[string]string, err error)
}
podhmopodhmo

errorになったときのresponseの形状など知りたい事はあるけれど、一旦はこの辺で大丈夫そう。

podhmopodhmo

自分で、利用するコードが書けた。

https://gist.github.com/podhmo/a2e492c2ed576ff3233e8524bf65a38b#file-main-go

実行例

ng request ----------------------------------------
find route: /pets POST map[]
validate request is failed: *openapi3filter.RequestError
validate request: request body has an error: doesn't match the schema: Error at "/name": property "name" is missing
Schema:
  {
    "additionalProperties": false,
    "properties": {
      "name": {
        "type": "string"
      },
      "tag": {
        "type": "string"
      }
    },
    "required": [
      "name"
    ],
    "type": "object"
  }

Value:
  {}

ng response ----------------------------------------
find route: /pets POST map[]
request is ok
valicate response is failed: *openapi3filter.ResponseError
validate response: response body doesn't match the schema: Error at "/id": property "id" is missing
Schema:
  {
    "additionalProperties": false,
    "properties": {
      "id": {
        "type": "string"
      },
      "name": {
        "type": "string"
      },
      "tag": {
        "type": "string"
      }
    },
    "required": [
      "id",
      "name"
    ],
    "type": "object"
  }

Value:
  {}
podhmopodhmo

こちらのほうが見やすいかも
https://gist.github.com/podhmo/9cbbb08aa7133ea2ae544d6fd71700d5

ng request ----------------------------------------
find route is ok
	POST /pets HTTP/1.1
	Host: localhost:8080
	Content-Type: application/json
	
	{}
validate request is failed: *openapi3filter.RequestError
validate request: request body has an error: doesn't match the schema: Error at "/name": property "name" is missing
	Schema:
	  {
	    "additionalProperties": false,
	    "properties": {
	      "name": {
	        "type": "string"
	      },
	      "tag": {
	        "type": "string"
	      }
	    },
	    "required": [
	      "name"
	    ],
	    "type": "object"
	  }
	
	Value:
	  {}
	


ng response ----------------------------------------
find route is ok
	POST /pets HTTP/1.1
	Host: localhost:8080
	Content-Type: application/json
	
	{"name": "foo"}
request is ok
	HTTP/1.1 200 OK
	Connection: close
	Content-Type: application/json
	
	{}
	
valicate response is failed: *openapi3filter.ResponseError
validate response: response body doesn't match the schema: Error at "/id": property "id" is missing
	Schema:
	  {
	    "additionalProperties": false,
	    "properties": {
	      "id": {
	        "type": "string"
	      },
	      "name": {
	        "type": "string"
	      },
	      "tag": {
	        "type": "string"
	      }
	    },
	    "required": [
	      "id",
	      "name"
	    ],
	    "type": "object"
	  }
	
	Value:
	  {}
	


ok ----------------------------------------
find route is ok
	POST /pets?ok=true HTTP/1.1
	Host: localhost:8080
	Content-Type: application/json
	
	{"name": "foo"}
request is ok
	HTTP/1.1 200 OK
	Connection: close
	Content-Type: application/json
	
	{"id":"1","name":"foo"}
	
response is ok

このスクラップは2023/07/03にクローズされました