|
1 | | -# echo-openapi |
| 1 | +# echo-openapi [](https://goreportcard.com/report/github.com/alexferl/echo-openapi) [](https://codecov.io/gh/alexferl/echo-openapi) |
| 2 | + |
| 3 | +An [OpenAPI](https://www.openapis.org/) middleware for the [Echo](https://github.com/labstack/echo) framework using |
| 4 | +[getkin/kin-openapi](https://github.com/getkin/kin-openapi) to validate HTTP requests and responses. |
| 5 | + |
| 6 | +## Installing |
| 7 | +```shell |
| 8 | +go get github.com/alexferl/echo-openapi |
| 9 | +``` |
| 10 | + |
| 11 | +## Using |
| 12 | + |
| 13 | +### Code example |
| 14 | +```go |
| 15 | +package main |
| 16 | + |
| 17 | +import ( |
| 18 | + "net/http" |
| 19 | + |
| 20 | + mw "github.com/alexferl/echo-openapi" |
| 21 | + "github.com/labstack/echo/v4" |
| 22 | +) |
| 23 | + |
| 24 | +/* |
| 25 | +# openapi.yaml |
| 26 | +openapi: 3.0.4 |
| 27 | +info: |
| 28 | + version: 1.0.0 |
| 29 | + title: Test API |
| 30 | + description: A test API |
| 31 | +paths: |
| 32 | + /hello: |
| 33 | + post: |
| 34 | + description: Hello |
| 35 | + parameters: |
| 36 | + - name: message |
| 37 | + in: query |
| 38 | + required: true |
| 39 | + schema: |
| 40 | + type: string |
| 41 | + minLength: 1 |
| 42 | + maxLength: 100 |
| 43 | + responses: |
| 44 | + '200': |
| 45 | + description: Successful response |
| 46 | + content: |
| 47 | + application/json: |
| 48 | + schema: |
| 49 | + type: object |
| 50 | + additionalProperties: false |
| 51 | + required: |
| 52 | + - message |
| 53 | + properties: |
| 54 | + message: |
| 55 | + type: string |
| 56 | + description: Welcome message |
| 57 | + minLength: 4 |
| 58 | +*/ |
| 59 | + |
| 60 | +type Handler struct { |
| 61 | + *mw.Handler |
| 62 | +} |
| 63 | + |
| 64 | +func (h *Handler) Hello(c echo.Context) error { |
| 65 | + msg := c.QueryParam("message") |
| 66 | + return h.Validate(c, http.StatusOK, echo.Map{"message": msg}) |
| 67 | +} |
| 68 | + |
| 69 | +func main() { |
| 70 | + e := echo.New() |
| 71 | + |
| 72 | + h := &Handler{mw.NewHandler()} |
| 73 | + e.Add(http.MethodPost, "/hello", h.Hello) |
| 74 | + |
| 75 | + e.Use(mw.OpenAPI("./path/to/openapi.yaml")) |
| 76 | + |
| 77 | + e.Logger.Fatal(e.Start("localhost:1323")) |
| 78 | +} |
| 79 | +``` |
| 80 | +Send an invalid request to test request validation: |
| 81 | +```shell |
| 82 | +curl -i -X POST http://localhost:1323/hello |
| 83 | +HTTP/1.1 422 Unprocessable Entity |
| 84 | +Content-Type: application/json; charset=UTF-8 |
| 85 | +Date: Mon, 07 Nov 2022 01:13:40 GMT |
| 86 | +Content-Length: 117 |
| 87 | + |
| 88 | +{"message":"Validation error","errors":["parameter 'message' in query has an error: value is required but missing"]} |
| 89 | +``` |
| 90 | + |
| 91 | +Send a valid request: |
| 92 | +```shell |
| 93 | +curl -i -X POST http://localhost:1323/hello\?message\=hello |
| 94 | +HTTP/1.1 200 OK |
| 95 | +Content-Type: application/json |
| 96 | +Date: Mon, 07 Nov 2022 01:22:59 GMT |
| 97 | +Content-Length: 19 |
| 98 | + |
| 99 | +{"message":"hello"} |
| 100 | +``` |
| 101 | + |
| 102 | +Send a valid request with an invalid response: |
| 103 | +```shell |
| 104 | +curl -i -X POST http://localhost:1323/hello\?message\=a |
| 105 | +HTTP/1.1 500 Internal Server Error |
| 106 | +Content-Type: application/json |
| 107 | +Date: Mon, 07 Nov 2022 01:16:43 GMT |
| 108 | +Content-Length: 36 |
| 109 | + |
| 110 | +{"message":"Internal Server Error"} |
| 111 | +``` |
| 112 | +You should also have the following in the server's log to help you debug your schema: |
| 113 | +```shell |
| 114 | +{"time":"2022-11-06T20:16:43.914629-05:00","level":"ERROR","prefix":"echo","file":"handler.go","line":"133","message":"response body doesn't match the schema: Error at \"/message\": minimum string length is 4\nSchema:\n {\n \"description\": \"Welcome message\",\n \"minLength\": 4,\n \"type\": \"string\"\n }\n\nValue:\n \"hi\"\n"} |
| 115 | +``` |
| 116 | + |
| 117 | +### Configuration |
| 118 | +```go |
| 119 | +type Config struct { |
| 120 | + // Skipper defines a function to skip middleware. |
| 121 | + Skipper middleware.Skipper |
| 122 | + |
| 123 | + // Schema defines the OpenAPI that will be loaded and |
| 124 | + // that the request and responses will be validated against. |
| 125 | + // Required. |
| 126 | + Schema string |
| 127 | + |
| 128 | + // ContextKey defines the key that will be used to store the validator |
| 129 | + // on the echo.Context when the request is successfully validated. |
| 130 | + // Optional. Defaults to "validator". |
| 131 | + ContextKey string |
| 132 | + |
| 133 | + // ExemptRoutes defines routes and methods that don't require tokens. |
| 134 | + // Optional. |
| 135 | + ExemptRoutes map[string][]string |
| 136 | +} |
| 137 | + |
| 138 | +type HandlerConfig struct { |
| 139 | + // ContentType sets the Content-Type header of the response. |
| 140 | + // Optional. Defaults to "application/json". |
| 141 | + ContentType string |
| 142 | + |
| 143 | + // ValidatorKey defines the key that will be used to read the |
| 144 | + // *openapi3filter.RequestValidationInput from the echo.Context |
| 145 | + // set by the middleware. |
| 146 | + // Optional. Defaults to "validator". |
| 147 | + ValidatorKey string |
| 148 | + |
| 149 | + // ExcludeRequestBody makes Validate skips request body validation. |
| 150 | + // Optional. Defaults to false. |
| 151 | + ExcludeRequestBody bool |
| 152 | + |
| 153 | + // ExcludeResponseBody makes Validate skips response body validation. |
| 154 | + // Optional. Defaults to false. |
| 155 | + ExcludeResponseBody bool |
| 156 | + |
| 157 | + // IncludeResponseStatus so ValidateResponse fails on response |
| 158 | + // statuses not defined in the OpenAPI spec. |
| 159 | + // Optional. Defaults to true. |
| 160 | + IncludeResponseStatus bool |
| 161 | +} |
| 162 | +``` |
0 commit comments