| package oasmiddleware |
|
|
| import ( |
| "bytes" |
| "io" |
| "net/http" |
|
|
| "github.com/getkin/kin-openapi/openapi3filter" |
| "github.com/getkin/kin-openapi/routers" |
| ) |
|
|
| type ( |
| RequestNotFoundHookFunc = func(error, http.ResponseWriter, *http.Request) bool |
| RequestValidationErrorFunc = func(error, http.ResponseWriter, *http.Request) bool |
| ResponseValidationFunc = func(error, *http.Request) |
| ) |
|
|
| |
| |
| type ValidateRequestOption struct { |
| |
| |
| RouteNotFoundHook RequestNotFoundHookFunc |
| |
| |
| RouteValidationErrorHook RequestValidationErrorFunc |
| |
| FilterOptions *openapi3filter.Options |
| } |
|
|
| |
| |
| func ValidateRequest(validationRouter routers.Router, opts ValidateRequestOption) func(h http.Handler) http.Handler { |
| return func(h http.Handler) http.Handler { |
| fn := func(w http.ResponseWriter, r *http.Request) { |
| ctx := r.Context() |
| skipServe := false |
| route, pathParams, err := validationRouter.FindRoute(r.WithContext(ctx)) |
| if err != nil { |
| if opts.RouteNotFoundHook != nil { |
| skipServe = opts.RouteNotFoundHook(err, w, r) |
| } |
| } else { |
| requestValidationInput := &openapi3filter.RequestValidationInput{ |
| Request: r, |
| PathParams: pathParams, |
| Route: route, |
| Options: opts.FilterOptions, |
| } |
| if err := openapi3filter.ValidateRequest(ctx, requestValidationInput); err != nil { |
| if opts.RouteValidationErrorHook != nil { |
| skipServe = opts.RouteValidationErrorHook(err, w, r) |
| } |
| } |
| } |
| if !skipServe { |
| h.ServeHTTP(w, r) |
| } |
| } |
| return http.HandlerFunc(fn) |
| } |
| } |
|
|
| |
| |
| type ValidateResponseOption struct { |
| |
| ResponseValidationErrorHook ResponseValidationFunc |
| |
| |
| RouteFilterHook func(*routers.Route) bool |
| |
| FilterOptions *openapi3filter.Options |
| } |
|
|
| |
| |
| func ValidateResponse(validationRouter routers.Router, opts ValidateResponseOption) func(h http.Handler) http.Handler { |
| return func(h http.Handler) http.Handler { |
| fn := func(w http.ResponseWriter, r *http.Request) { |
| route, pathParams, err := validationRouter.FindRoute(r) |
|
|
| if err != nil { |
| h.ServeHTTP(w, r) |
| if opts.ResponseValidationErrorHook != nil { |
| opts.ResponseValidationErrorHook(err, r) |
| } |
| } else { |
| if opts.RouteFilterHook != nil && !opts.RouteFilterHook(route) { |
| h.ServeHTTP(w, r) |
| return |
| } |
|
|
| |
| rww := NewResponseWriterWrapper(w) |
|
|
| h.ServeHTTP(rww, r) |
|
|
| b := new(bytes.Buffer) |
| _, err := b.ReadFrom(rww.Body()) |
| if err != nil { |
| return |
| } |
| bodyReader := bytes.NewReader(b.Bytes()) |
|
|
| responseValidationInput := &openapi3filter.ResponseValidationInput{ |
| RequestValidationInput: &openapi3filter.RequestValidationInput{ |
| Request: r, |
| PathParams: pathParams, |
| Route: route, |
| Options: opts.FilterOptions, |
| }, |
| Header: rww.Header(), |
| Body: io.NopCloser(bodyReader), |
| Status: *rww.StatusCode(), |
| } |
|
|
| if err := openapi3filter.ValidateResponse(r.Context(), responseValidationInput); err != nil { |
| if opts.ResponseValidationErrorHook != nil { |
| opts.ResponseValidationErrorHook(err, r) |
| } |
| } |
| } |
| } |
| return http.HandlerFunc(fn) |
| } |
| } |
|
|