Last active
April 29, 2024 12:55
-
-
Save bojanz/00187fd502b75001953d200c11dbbd97 to your computer and use it in GitHub Desktop.
OpenAPI assert helper
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package responsetest | |
import ( | |
"context" | |
"net/http" | |
"net/http/httptest" | |
"testing" | |
"github.com/getkin/kin-openapi/openapi3" | |
"github.com/getkin/kin-openapi/openapi3filter" | |
oarouters "github.com/getkin/kin-openapi/routers" | |
legacyrouter "github.com/getkin/kin-openapi/routers/legacy" | |
"github.com/stretchr/testify/assert" | |
"github.com/stretchr/testify/require" | |
) | |
// oaRouter is the OpenAPI router used to validate requests and responses. | |
var oaRouter oarouters.Router | |
func init() { | |
openapi3.DefineStringFormat("uuid", openapi3.FormatOfStringForUUIDOfRFC4122) | |
openapi3.DefineStringFormat("ulid", `^[0-7]{1}[0-9A-HJKMNP-TV-Z]{25}$`) | |
loader := &openapi3.Loader{Context: context.Background()} | |
doc, err := loader.LoadFromFile("../../openapi.combined.yaml") | |
if err != nil { | |
panic(err) | |
} | |
// Our test requests are relative, so the server URL doesn't get found. | |
doc.Servers = nil | |
oaRouter, err = legacyrouter.NewRouter(doc) | |
if err != nil { | |
panic(err) | |
} | |
} | |
// AssertOpenAPI verifies that the given request and response match their OpenAPI schema. | |
func AssertOpenAPI(t *testing.T, rr *httptest.ResponseRecorder, req *http.Request) { | |
t.Helper() | |
// The request body exists and was already read once when the request | |
// was sent. Replay it to allow ValidateRequest() to read it again. | |
if req.Body != nil && req.Body != http.NoBody { | |
req.Body, _ = req.GetBody() | |
} | |
// Validate request. | |
route, pathParams, err := oaRouter.FindRoute(req) | |
require.NoError(t, err, "could not find route") | |
requestValidationInput := &openapi3filter.RequestValidationInput{ | |
Request: req, | |
PathParams: pathParams, | |
Route: route, | |
Options: &openapi3filter.Options{ | |
MultiError: true, | |
}, | |
} | |
// Don't validate the request body if the response indicates an error, | |
// to allow testing server-side validation using known bad values. | |
if rr.Result().StatusCode >= http.StatusBadRequest { | |
requestValidationInput.Options.ExcludeRequestBody = true | |
} | |
err = openapi3filter.ValidateRequest(context.Background(), requestValidationInput) | |
assert.NoError(t, err, "http request is not valid") | |
// Validate response. | |
responseValidationInput := &openapi3filter.ResponseValidationInput{ | |
RequestValidationInput: requestValidationInput, | |
Status: rr.Result().StatusCode, | |
Header: http.Header{"Content-Type": []string{rr.Header().Get("Content-Type")}}, | |
} | |
responseValidationInput.SetBodyBytes(rr.Body.Bytes()) | |
err = openapi3filter.ValidateResponse(context.Background(), responseValidationInput) | |
assert.NoError(t, err, "http response is not valid") | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Usage: