Skip to content
This repository has been archived by the owner on Nov 1, 2023. It is now read-only.

Commit

Permalink
Provide a echo middleware
Browse files Browse the repository at this point in the history
The Echo Middleware assert the request using the openapi-assert
package.

Changed the travis file to build using the latest version of go.
  • Loading branch information
faabiosr committed Aug 26, 2019
1 parent c1d848a commit 20b2da6
Show file tree
Hide file tree
Showing 5 changed files with 215 additions and 2 deletions.
3 changes: 2 additions & 1 deletion .travis.yml
@@ -1,7 +1,8 @@
language: go

go:
- "1.11"
- "1.11.x"
- "1.12.x"
- master
env:
- GO111MODULE=on
Expand Down
4 changes: 3 additions & 1 deletion go.mod
Expand Up @@ -4,8 +4,10 @@ require (
github.com/go-openapi/jsonpointer v0.17.0
github.com/go-openapi/loads v0.17.0
github.com/go-openapi/spec v0.17.0
github.com/labstack/echo v3.3.10+incompatible
github.com/labstack/echo/v4 v4.1.10
github.com/pkg/errors v0.8.0
github.com/stretchr/testify v1.2.2
github.com/stretchr/testify v1.4.0
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f // indirect
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
github.com/xeipuuv/gojsonschema v0.0.0-20181016150526-f3a9dae5b194
Expand Down
32 changes: 32 additions & 0 deletions go.sum
Expand Up @@ -4,8 +4,11 @@ github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf h1:eg0MeVzsP1G42dRafH3vf+al2vQIJU0YHX+1Tw87oco=
github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb h1:D4uzjWwKYQ5XnAvUbuvHW93esHg7F8N/OYeBBcJoTr0=
github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
github.com/go-openapi/analysis v0.0.0-20180825180245-b006789cd277 h1:Cjl5yf/RidkszNOmV0+rf35yjOocQ1UTTVwEmxnr6Ls=
Expand All @@ -26,8 +29,19 @@ github.com/go-openapi/swag v0.17.0 h1:iqrgMg7Q7SvtbWLlltPrkMs0UBJI6oTSs79JFRUi88
github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg=
github.com/google/uuid v1.0.0 h1:b4Gk+7WdP/d3HZH8EJsZpvV7EtDOgaZLtnaNGIu1adA=
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/labstack/echo v3.3.10+incompatible h1:pGRcYk231ExFAyoAjAfD85kQzRJCRI8bbnE7CX5OEgg=
github.com/labstack/echo v3.3.10+incompatible/go.mod h1:0INS7j/VjnFxD4E2wkz67b8cVwCLbBmJyDaka6Cmk1s=
github.com/labstack/echo/v4 v4.1.10 h1:/yhIpO50CBInUbE/nHJtGIyhBv0dJe2cDAYxc3V3uMo=
github.com/labstack/echo/v4 v4.1.10/go.mod h1:i541M3Fj6f76NZtHSj7TXnyM8n2gaodfvfxNnFqi74g=
github.com/labstack/gommon v0.3.0 h1:JEeO0bvc78PKdyHxloTKiF8BD5iGrH8T6MSeGvSgob0=
github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k=
github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329 h1:2gxZ0XQIU/5z3Z3bUBu+FXuk2pFbkN6tcwi/pjyaDic=
github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mattn/go-colorable v0.1.2 h1:/bC9yWikZXAL9uJdulbSfyVNIR3n3trXl+v8+1sx8mU=
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.9 h1:d5US/mDsogSGW37IV293h//ZFaeajb69h+EHFsv2xGg=
github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/pborman/uuid v1.2.0 h1:J7Q5mO4ysT1dv8hyrUGHb9+ooztCXu1D8MY8DZYsu3g=
Expand All @@ -36,8 +50,15 @@ github.com/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fasttemplate v1.0.1 h1:tY9CJiPnMXf1ERmG2EyK7gNUd+c6RKGD0IfU8WdUSz8=
github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c=
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0=
Expand All @@ -46,11 +67,22 @@ github.com/xeipuuv/gojsonschema v0.0.0-20181016150526-f3a9dae5b194 h1:va8F6ctiwx
github.com/xeipuuv/gojsonschema v0.0.0-20181016150526-f3a9dae5b194/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs=
github.com/yosida95/uritemplate v0.0.0-20170413134207-5c22f358020b h1:Lz1ji+ezbzsAY9OFYZxa+Tzao42+DMJIR6jn3N+H87I=
github.com/yosida95/uritemplate v0.0.0-20170413134207-5c22f358020b/go.mod h1:mksJanHNnLsh6wYgt/AbBRZ4ogsHsO2uiZlm/UURY5c=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 h1:HuIa8hRrWRSrqYzx1qI49NNxhdi2PrY7gxVSq1JjLDc=
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/net v0.0.0-20181005035420-146acd28ed58 h1:otZG8yDCO4LVps5+9bxOeNiCvgmOyt96J3roHTYs7oE=
golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3 h1:0GoQqolDA55aaLxZyTzK/Y2ePZzZTUrRacwib7cNsYQ=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
64 changes: 64 additions & 0 deletions middleware/echo/assert.go
@@ -0,0 +1,64 @@
package echo

import (
"net/http"

assert "github.com/faabiosr/openapi-assert"
"github.com/labstack/echo/v4"
mw "github.com/labstack/echo/v4/middleware"
)

// AssertConfig defines the config for Assert Assert.
type AssertConfig struct {
// Skipper defines a function to skip middleware.
Skipper mw.Skipper

// OpenAPI Document
Document assert.Document
}

// DefaultAssertConfig is the default Assert middleware config.
var DefaultAssertConfig = AssertConfig{
Skipper: mw.DefaultSkipper,
}

// Assert returns middleware that uses the openapi-assert
// package to assert echo HTTP requests.
func Assert(doc assert.Document) echo.MiddlewareFunc {
c := DefaultAssertConfig
c.Document = doc

return AssertWithConfig(c)
}

// AssertWithConfig returns an Assert middleware with config.
func AssertWithConfig(cfg AssertConfig) echo.MiddlewareFunc {
// Defaults
if cfg.Skipper == nil {
cfg.Skipper = DefaultAssertConfig.Skipper
}

if cfg.Document == nil {
panic("echo: assert middleware requires an openapi-assert document")
}

assert := assert.New(cfg.Document)

return func(next echo.HandlerFunc) echo.HandlerFunc {
return func(ctx echo.Context) error {
if cfg.Skipper(ctx) {
return next(ctx)
}

if err := assert.Request(ctx.Request()); err != nil {
return &echo.HTTPError{
Code: http.StatusBadRequest,
Message: err.Error(),
Internal: err,
}
}

return next(ctx)
}
}
}
114 changes: 114 additions & 0 deletions middleware/echo/assert_test.go
@@ -0,0 +1,114 @@
package echo

import (
"net/http"
"net/http/httptest"
"strings"
"testing"

oapi "github.com/faabiosr/openapi-assert"
ec "github.com/labstack/echo/v4"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/suite"
)

type (
AssertTestSuite struct {
suite.Suite
assert *assert.Assertions

doc oapi.Document

srv *ec.Echo
}
)

func (s *AssertTestSuite) SetupTest() {
s.assert = assert.New(s.T())
s.doc, _ = oapi.LoadFromURI("../../fixtures/docs.json")
s.srv = ec.New()
}

func (s *AssertTestSuite) TestMiddlewareWithConfig() {
req := httptest.NewRequest(ec.PATCH, "/api/pets/1", nil)
req.Header.Add(ec.HeaderContentType, ec.MIMEApplicationJSON)

rec := httptest.NewRecorder()

c := s.srv.NewContext(req, rec)

cfg := AssertConfig{Document: s.doc}

err := AssertWithConfig(cfg)(func(ctx ec.Context) error {
return ctx.String(http.StatusOK, "test")
})(c)

s.assert.Error(err)
}

func (s *AssertTestSuite) TestMiddleware() {
req := httptest.NewRequest(
ec.POST,
"/api/pets",
strings.NewReader(`{"id": 1, "name": "doggo"}`),
)

req.Header.Add(ec.HeaderContentType, ec.MIMEApplicationJSON)

rec := httptest.NewRecorder()

c := s.srv.NewContext(req, rec)

err := Assert(s.doc)(func(ctx ec.Context) error {
return ctx.String(http.StatusOK, "test")
})(c)

s.assert.NoError(err)
}

func (s *AssertTestSuite) TestMiddlewareWithSkipper() {
req := httptest.NewRequest(ec.PATCH, "/api/pets/1", nil)
req.Header.Add(ec.HeaderContentType, ec.MIMEApplicationJSON)

rec := httptest.NewRecorder()

c := s.srv.NewContext(req, rec)

cfg := AssertConfig{
Document: s.doc,
Skipper: func(c ec.Context) bool {
return true
},
}

err := AssertWithConfig(cfg)(func(ctx ec.Context) error {
return ctx.String(http.StatusOK, "test")
})(c)

s.assert.NoError(err)
}

func (s *AssertTestSuite) TestMiddlewareWithoutDocument() {
req := httptest.NewRequest(ec.PATCH, "/api/pets/1", nil)
rec := httptest.NewRecorder()

c := s.srv.NewContext(req, rec)

cfg := AssertConfig{
Skipper: func(c ec.Context) bool {
return true
},
}

caller := func() {
AssertWithConfig(cfg)(func(ctx ec.Context) error {
return ctx.String(http.StatusOK, "test")
})(c)
}

s.assert.Panics(caller)
}

func TestAssertTestSuite(t *testing.T) {
suite.Run(t, new(AssertTestSuite))
}

0 comments on commit 20b2da6

Please sign in to comment.