go.mod: Update oapi-codegen and kin-openapi

This commit is contained in:
sanne 2022-01-11 19:00:14 +01:00 committed by Sanne Raymaekers
parent add17bba45
commit a83cf95d5b
156 changed files with 29663 additions and 2248 deletions

4
go.mod
View file

@ -20,8 +20,8 @@ require (
github.com/cespare/xxhash/v2 v2.1.2 // indirect
github.com/coreos/go-semver v0.3.0
github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f
github.com/deepmap/oapi-codegen v1.3.12
github.com/getkin/kin-openapi v0.13.0
github.com/deepmap/oapi-codegen v1.8.2
github.com/getkin/kin-openapi v0.61.0
github.com/gobwas/glob v0.2.3
github.com/golang-jwt/jwt v3.2.2+incompatible
github.com/golang/glog v1.0.0 // indirect

33
go.sum
View file

@ -160,8 +160,8 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
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/davecgh/go-xdr v0.0.0-20161123171359-e6a2ba005892/go.mod h1:CTDl0pzVzE5DEzZhPfvhY/9sPFMQIxaJ9VAMs9AagrE=
github.com/deepmap/oapi-codegen v1.3.12 h1:HiWZO0qMhSmqZH9VdbtsBK7lOSYYJ7jsa26DpydbEEw=
github.com/deepmap/oapi-codegen v1.3.12/go.mod h1:suMvK7+rKlx3+tpa8ByptmvoXbAV70wERKTOGH3hLp0=
github.com/deepmap/oapi-codegen v1.8.2 h1:SegyeYGcdi0jLLrpbCMoJxnUUn8GBXHsvr4rbzjuhfU=
github.com/deepmap/oapi-codegen v1.8.2/go.mod h1:YLgSKSDv/bZQB7N4ws6luhozi3cEdRktEqrX88CvjIw=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/dimchansky/utfbom v1.1.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8=
github.com/dimchansky/utfbom v1.1.1 h1:vV6w1AhK4VMnhBno/TPVCoK9U/LP0PkLCS9tbxHdi/U=
@ -187,11 +187,11 @@ github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/getkin/kin-openapi v0.13.0 h1:03fqBEEgivp4MVK2ElB140B56hjO9ZFvFTHBsvFsSro=
github.com/getkin/kin-openapi v0.13.0/go.mod h1:WGRs2ZMM1Q8LR1QBEwUxC6RJEfaBcD0s+pcEVXFuAjw=
github.com/getkin/kin-openapi v0.61.0 h1:6awGqF5nG5zkVpMsAih1QH4VgzS8phTxECUWIFo7zko=
github.com/getkin/kin-openapi v0.61.0/go.mod h1:7Yn5whZr5kJi6t+kShccXS8ae1APpYTW6yheSwk8Yi4=
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/go-chi/chi v4.0.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ=
github.com/go-chi/chi/v5 v5.0.0/go.mod h1:BBug9lr0cqtdAhsu6R4AAdvufI0/XBzAQSsUqJpoZOs=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
@ -202,6 +202,10 @@ github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vb
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY=
github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
github.com/go-openapi/swag v0.19.5 h1:lTz6Ys4CmqqCQmZPBlbQENR1/GucA2bzYTE12Pw4tFY=
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
@ -314,6 +318,7 @@ github.com/gorilla/css v1.0.0 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY=
github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c=
github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
@ -446,7 +451,7 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/labstack/echo/v4 v4.1.11/go.mod h1:i541M3Fj6f76NZtHSj7TXnyM8n2gaodfvfxNnFqi74g=
github.com/labstack/echo/v4 v4.2.1/go.mod h1:AA49e0DZ8kk5jTOOCKNuPR6oTnBS0dYiM4FW1e6jwpg=
github.com/labstack/echo/v4 v4.6.1 h1:OMVsrnNFzYlGSdaiYGHbgWQnr+JM7NG+B9suCPie14M=
github.com/labstack/echo/v4 v4.6.1/go.mod h1:RnjgMWNDB9g/HucVWhQYNQP9PvbYf6adqftqryo7s9k=
github.com/labstack/gommon v0.3.0 h1:JEeO0bvc78PKdyHxloTKiF8BD5iGrH8T6MSeGvSgob0=
@ -460,12 +465,15 @@ github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM=
github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4=
github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ=
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e h1:hB2xlXdHp/pmPZq0y3QnmWAArdw9PqbmotexnWx/FU8=
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/matryer/moq v0.0.0-20190312154309-6cfb0558e1bd/go.mod h1:9ELz6aaclSIGnZBoaSLZ3NAl1VTufbOrXBPvtcy6WiQ=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8=
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-ieproxy v0.0.1 h1:qiyop7gCflfhwCzGyeT0gro3sF9AIg9HU98JORTkqfI=
@ -476,7 +484,6 @@ github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hd
github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
@ -638,7 +645,6 @@ github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtX
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/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
github.com/valyala/fasttemplate v1.1.0/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
github.com/valyala/fasttemplate v1.2.1 h1:TVEnxayobAdVkhQfrfes2IzOB6o+z4roRkPF52WA1u4=
github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
github.com/vmware/govmomi v0.26.1 h1:awC7cFIT0SOCt3A6rbUCCEtFdt+X1L6Nppm0mkL7zQk=
@ -685,9 +691,9 @@ golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8U
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191112222119-e1110fd1c708/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
@ -731,6 +737,7 @@ golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@ -836,10 +843,8 @@ golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191112214154-59a1497f0cea/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@ -861,6 +866,7 @@ golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200826173525-f9321e4c35a6/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200828194041-157a740278f4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@ -906,8 +912,9 @@ golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxb
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20201208040808-7e3f01d25324 h1:Hir2P/De0WpUhtrKGGjvSb2YxUgyZ7EFOSLIcSSpiwE=
golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba h1:O8mE0/t419eoIwhTFpKVkHiTs/Igowgfkj25AcZrtiE=
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=

View file

@ -1,6 +1,6 @@
// Package v2 provides primitives to interact the openapi HTTP API.
// Package v2 provides primitives to interact with the openapi HTTP API.
//
// Code generated by github.com/deepmap/oapi-codegen DO NOT EDIT.
// Code generated by github.com/deepmap/oapi-codegen version v1.8.2 DO NOT EDIT.
package v2
import (
@ -8,11 +8,76 @@ import (
"compress/gzip"
"encoding/base64"
"fmt"
"net/http"
"net/url"
"path"
"strings"
"github.com/deepmap/oapi-codegen/pkg/runtime"
"github.com/getkin/kin-openapi/openapi3"
"github.com/labstack/echo/v4"
"net/http"
"strings"
)
const (
BearerScopes = "Bearer.Scopes"
)
// Defines values for ImageStatusValue.
const (
ImageStatusValueBuilding ImageStatusValue = "building"
ImageStatusValueFailure ImageStatusValue = "failure"
ImageStatusValuePending ImageStatusValue = "pending"
ImageStatusValueRegistering ImageStatusValue = "registering"
ImageStatusValueSuccess ImageStatusValue = "success"
ImageStatusValueUploading ImageStatusValue = "uploading"
)
// Defines values for ImageTypes.
const (
ImageTypesAws ImageTypes = "aws"
ImageTypesAzure ImageTypes = "azure"
ImageTypesEdgeCommit ImageTypes = "edge-commit"
ImageTypesEdgeContainer ImageTypes = "edge-container"
ImageTypesEdgeInstaller ImageTypes = "edge-installer"
ImageTypesGcp ImageTypes = "gcp"
ImageTypesGuestImage ImageTypes = "guest-image"
ImageTypesImageInstaller ImageTypes = "image-installer"
ImageTypesVsphere ImageTypes = "vsphere"
)
// Defines values for UploadStatusValue.
const (
UploadStatusValueFailure UploadStatusValue = "failure"
UploadStatusValuePending UploadStatusValue = "pending"
UploadStatusValueRunning UploadStatusValue = "running"
UploadStatusValueSuccess UploadStatusValue = "success"
)
// Defines values for UploadTypes.
const (
UploadTypesAws UploadTypes = "aws"
UploadTypesAwsS3 UploadTypes = "aws.s3"
UploadTypesAzure UploadTypes = "azure"
UploadTypesGcp UploadTypes = "gcp"
)
// AWSEC2UploadOptions defines model for AWSEC2UploadOptions.
@ -40,7 +105,6 @@ type AWSS3UploadStatus struct {
// AzureUploadOptions defines model for AzureUploadOptions.
type AzureUploadOptions struct {
// Name of the uploaded image. It must be unique in the given resource group.
// If name is omitted from the request, a random one based on a UUID is
// generated.
@ -71,7 +135,7 @@ type AzureUploadStatus struct {
// ComposeId defines model for ComposeId.
type ComposeId struct {
// Embedded struct due to allOf(#/components/schemas/ObjectReference)
ObjectReference
ObjectReference `yaml:",inline"`
// Embedded fields due to inline allOf schema
Id string `json:"id"`
}
@ -79,9 +143,8 @@ type ComposeId struct {
// ComposeMetadata defines model for ComposeMetadata.
type ComposeMetadata struct {
// Embedded struct due to allOf(#/components/schemas/ObjectReference)
ObjectReference
ObjectReference `yaml:",inline"`
// Embedded fields due to inline allOf schema
// ID (hash) of the built commit
OstreeCommit *string `json:"ostree_commit,omitempty"`
@ -99,7 +162,7 @@ type ComposeRequest struct {
// ComposeStatus defines model for ComposeStatus.
type ComposeStatus struct {
// Embedded struct due to allOf(#/components/schemas/ObjectReference)
ObjectReference
ObjectReference `yaml:",inline"`
// Embedded fields due to inline allOf schema
ImageStatus ImageStatus `json:"image_status"`
}
@ -115,7 +178,7 @@ type Customizations struct {
// Error defines model for Error.
type Error struct {
// Embedded struct due to allOf(#/components/schemas/ObjectReference)
ObjectReference
ObjectReference `yaml:",inline"`
// Embedded fields due to inline allOf schema
Code string `json:"code"`
OperationId string `json:"operation_id"`
@ -125,14 +188,13 @@ type Error struct {
// ErrorList defines model for ErrorList.
type ErrorList struct {
// Embedded struct due to allOf(#/components/schemas/List)
List
List `yaml:",inline"`
// Embedded fields due to inline allOf schema
Items []Error `json:"items"`
}
// GCPUploadOptions defines model for GCPUploadOptions.
type GCPUploadOptions struct {
// Name of an existing STANDARD Storage class Bucket.
Bucket string `json:"bucket"`
@ -187,32 +249,9 @@ type ImageStatus struct {
// ImageStatusValue defines model for ImageStatusValue.
type ImageStatusValue string
// List of ImageStatusValue
const (
ImageStatusValue_building ImageStatusValue = "building"
ImageStatusValue_failure ImageStatusValue = "failure"
ImageStatusValue_pending ImageStatusValue = "pending"
ImageStatusValue_registering ImageStatusValue = "registering"
ImageStatusValue_success ImageStatusValue = "success"
ImageStatusValue_uploading ImageStatusValue = "uploading"
)
// ImageTypes defines model for ImageTypes.
type ImageTypes string
// List of ImageTypes
const (
ImageTypes_aws ImageTypes = "aws"
ImageTypes_azure ImageTypes = "azure"
ImageTypes_edge_commit ImageTypes = "edge-commit"
ImageTypes_edge_container ImageTypes = "edge-container"
ImageTypes_edge_installer ImageTypes = "edge-installer"
ImageTypes_gcp ImageTypes = "gcp"
ImageTypes_guest_image ImageTypes = "guest-image"
ImageTypes_image_installer ImageTypes = "image-installer"
ImageTypes_vsphere ImageTypes = "vsphere"
)
// List defines model for List.
type List struct {
Kind string `json:"kind"`
@ -271,26 +310,21 @@ type UploadOptions interface{}
// UploadStatus defines model for UploadStatus.
type UploadStatus struct {
Options interface{} `json:"options"`
Status string `json:"status"`
Type UploadTypes `json:"type"`
Options interface{} `json:"options"`
Status UploadStatusValue `json:"status"`
Type UploadTypes `json:"type"`
}
// UploadStatusValue defines model for UploadStatusValue.
type UploadStatusValue string
// UploadTypes defines model for UploadTypes.
type UploadTypes string
// List of UploadTypes
const (
UploadTypes_aws UploadTypes = "aws"
UploadTypes_aws_s3 UploadTypes = "aws.s3"
UploadTypes_azure UploadTypes = "azure"
UploadTypes_gcp UploadTypes = "gcp"
)
// User defines model for User.
type User struct {
// Embedded struct due to allOf(#/components/schemas/ObjectReference)
ObjectReference
ObjectReference `yaml:",inline"`
// Embedded fields due to inline allOf schema
Groups *[]string `json:"groups,omitempty"`
Key *string `json:"key,omitempty"`
@ -308,7 +342,6 @@ type PostComposeJSONBody ComposeRequest
// GetErrorListParams defines parameters for GetErrorList.
type GetErrorListParams struct {
// Page index
Page *Page `json:"page,omitempty"`
@ -316,7 +349,7 @@ type GetErrorListParams struct {
Size *Size `json:"size,omitempty"`
}
// PostComposeRequestBody defines body for PostCompose for application/json ContentType.
// PostComposeJSONRequestBody defines body for PostCompose for application/json ContentType.
type PostComposeJSONRequestBody PostComposeJSONBody
// ServerInterface represents all server handlers.
@ -350,7 +383,7 @@ type ServerInterfaceWrapper struct {
func (w *ServerInterfaceWrapper) PostCompose(ctx echo.Context) error {
var err error
ctx.Set("Bearer.Scopes", []string{""})
ctx.Set(BearerScopes, []string{""})
// Invoke the callback with all the unmarshalled arguments
err = w.Handler.PostCompose(ctx)
@ -363,12 +396,12 @@ func (w *ServerInterfaceWrapper) GetComposeStatus(ctx echo.Context) error {
// ------------- Path parameter "id" -------------
var id string
err = runtime.BindStyledParameter("simple", false, "id", ctx.Param("id"), &id)
err = runtime.BindStyledParameterWithLocation("simple", false, "id", runtime.ParamLocationPath, ctx.Param("id"), &id)
if err != nil {
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter id: %s", err))
}
ctx.Set("Bearer.Scopes", []string{""})
ctx.Set(BearerScopes, []string{""})
// Invoke the callback with all the unmarshalled arguments
err = w.Handler.GetComposeStatus(ctx, id)
@ -381,12 +414,12 @@ func (w *ServerInterfaceWrapper) GetComposeMetadata(ctx echo.Context) error {
// ------------- Path parameter "id" -------------
var id string
err = runtime.BindStyledParameter("simple", false, "id", ctx.Param("id"), &id)
err = runtime.BindStyledParameterWithLocation("simple", false, "id", runtime.ParamLocationPath, ctx.Param("id"), &id)
if err != nil {
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter id: %s", err))
}
ctx.Set("Bearer.Scopes", []string{""})
ctx.Set(BearerScopes, []string{""})
// Invoke the callback with all the unmarshalled arguments
err = w.Handler.GetComposeMetadata(ctx, id)
@ -397,7 +430,7 @@ func (w *ServerInterfaceWrapper) GetComposeMetadata(ctx echo.Context) error {
func (w *ServerInterfaceWrapper) GetErrorList(ctx echo.Context) error {
var err error
ctx.Set("Bearer.Scopes", []string{""})
ctx.Set(BearerScopes, []string{""})
// Parameter object where we will unmarshal all parameters from the context
var params GetErrorListParams
@ -426,12 +459,12 @@ func (w *ServerInterfaceWrapper) GetError(ctx echo.Context) error {
// ------------- Path parameter "id" -------------
var id string
err = runtime.BindStyledParameter("simple", false, "id", ctx.Param("id"), &id)
err = runtime.BindStyledParameterWithLocation("simple", false, "id", runtime.ParamLocationPath, ctx.Param("id"), &id)
if err != nil {
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter id: %s", err))
}
ctx.Set("Bearer.Scopes", []string{""})
ctx.Set(BearerScopes, []string{""})
// Invoke the callback with all the unmarshalled arguments
err = w.Handler.GetError(ctx, id)
@ -442,7 +475,7 @@ func (w *ServerInterfaceWrapper) GetError(ctx echo.Context) error {
func (w *ServerInterfaceWrapper) GetOpenapi(ctx echo.Context) error {
var err error
ctx.Set("Bearer.Scopes", []string{""})
ctx.Set(BearerScopes, []string{""})
// Invoke the callback with all the unmarshalled arguments
err = w.Handler.GetOpenapi(ctx)
@ -466,88 +499,94 @@ type EchoRouter interface {
// RegisterHandlers adds each server route to the EchoRouter.
func RegisterHandlers(router EchoRouter, si ServerInterface) {
RegisterHandlersWithBaseURL(router, si, "")
}
// Registers handlers, and prepends BaseURL to the paths, so that the paths
// can be served under a prefix.
func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL string) {
wrapper := ServerInterfaceWrapper{
Handler: si,
}
router.POST("/compose", wrapper.PostCompose)
router.GET("/composes/:id", wrapper.GetComposeStatus)
router.GET("/composes/:id/metadata", wrapper.GetComposeMetadata)
router.GET("/errors", wrapper.GetErrorList)
router.GET("/errors/:id", wrapper.GetError)
router.GET("/openapi", wrapper.GetOpenapi)
router.POST(baseURL+"/compose", wrapper.PostCompose)
router.GET(baseURL+"/composes/:id", wrapper.GetComposeStatus)
router.GET(baseURL+"/composes/:id/metadata", wrapper.GetComposeMetadata)
router.GET(baseURL+"/errors", wrapper.GetErrorList)
router.GET(baseURL+"/errors/:id", wrapper.GetError)
router.GET(baseURL+"/openapi", wrapper.GetOpenapi)
}
// Base64 encoded, gzipped, json marshaled Swagger object
var swaggerSpec = []string{
"H4sIAAAAAAAC/+xbe28bOZL/KkTvAZ7BdUuyZDmOgMGs43iz3ps8YDmzuIsNgWKX1Nx0kx2SbUUJ9N0P",
"fHSrH5Ql73hmMYD/iSWRrPpVsapYVWS+B4RnOWfAlAwm34McC5yBAuG+LUH/jUESQXNFOQsmwQe8BERZ",
"DF+DMICvOMtTaEy/x2kBwSQ4DjabMKB6zZcCxDoIA4YzPWJmhoEkCWRYL1HrXP8ulaBsaZZJ+s3D+12R",
"zUEgvkBUQSYRZQgwSZAjWEdTEqjQDAY78Zi5D+HZlIOG9Pk/p5cXw495ynH83kCz8gueg1DU8hewNJi/",
"l6iCSQBFtAKpouMgbLMIA5lgAbMVVckME8ILtyXV6k/B8XB0Mj59cfZycDwM7sLA6MADtyKOhcBrQ5vh",
"XCZczazAdUzZOipHu6g2YSDgS0EFxBqAk8mP9a5azef/AqI037qmpgqrwqMonNEmIpzRaEDORoMXL0cv",
"XozHL8fxydynsUequCWM5lvR2AF+OnraXfbrcw/zXYorROr3nToLPclL/1shYI9wNMNLqEym5Yk4A+2H",
"KgFUGDIQI7Ogh64Uygqp0BxQweiXQocLM3FJ74EhAZIXggBaCl7kvVt2tUCaCaIS8YwqBTFaCJ6ZJVoW",
"kCpEGAnMYp4hzgDNsYQYcYYw+vjx6jWi8pYtgYHACuLeLdvGAmvhBpjPhFJOsHI72BTwFzeCVgkIMFgM",
"FSQTXqSxEa6UG7MY6b2UCoTh/3e+QoqjlEqFcJqiko2c3LJEqVxO+v2YE9nLKBFc8oXqEZ71gUWF7JOU",
"9rHenr7zrZ/vKax+Mj9FJKVRihVI9Rf8rXS+mWY0q5gctRSgrREKvbV+L7LbMTPb8fBON7fuANW09+KG",
"FwSza0fmjeHoi4XFvIIwo3EX1NVrDak+7d8AcwLj+Gw+JBGeD0+ik5PjUfRyQMbR6fFwNDiFs8FLGPrQ",
"KWCYqQdwaRB20mGonLksKIsRVaW3GBdFH7hQOD3EbkqbUfQeopgKIIqLdX9RsBhnwBROZWc0SvgqUjzS",
"rCMLuaWkMXkBi/H8NDomo0V0EuNBhE+Hw2gwH5wOhqOX8Yv4xd5At9VYd287Fljzyj2Ra1dkbAauQyJB",
"C2+NgA/ChU6aJFwZA8Bp+n4RTD59D/5LwCKYBH/pb5Oqvksb+u/N4mtYgABGINiEHdBxE+zxcAT6uI/g",
"7OU8Oh7GowifjE+jk+Hp6Xh8cjIYDAZBGCy4yLAKJkFRGGXuESz2CHS3FektKBxjhZ9SMC6VAJgRnmVU",
"eV3mhwTL5MfSc+YFTRVy0z3ul2PyGS8t7XZqakZs3KWMpEVM2RK9u/z1+jyo5UsPyeNoVIroZFObh/R3",
"bY+rrkmSQiqe0W+4OmsfAnHRnL0Jg5hqBcwL1Uk3RAJpdOZTlLVisYX0EMsrPbmE3zabBvc24Zr4W4d8",
"Mq8wrGRFd68IDoLfox2dHS7Q2aImlLrd1bLynEu1FCAfl5HneK0j2ExAziVVXJTyHmKj1+WitTfZrwXY",
"fZSm9bmbMCikq/0OwvFRgjjEQcLgUgguntIuCI/Bq2g9CdfyBk++g6VVzMOh0nCoprcI+y3ISPkLtc52",
"mKRmtsfsS/UftA9Wu76NaLiAIeVH/ubiw55iYF6Qz6B2p4eYIfhKpdIBd3pz/u71+fVrNFVc6IBMUiwl",
"emVI9NrJufsSOQ47A5m/ELlJwFYPiqNCAlpw4dKtnAvlknNTr8ZIR6lCAbpkS8pcRta7ZTdVdmYItWoX",
"XeW6jOzNxQeUC67VFqJVQkmia5ZCQnzLSr7vp46Wze8Me4ulh3ShwxWSORC6oBqbK2pu2RGxEVREOKfR",
"bTEYjIg+0c0nOEJWGSU7hGUtp9SoH1P0bIvWriq1iHa8lrpWMq1ommrVVMpVvK5fXbU5fZq2S6VKrL/T",
"2FAvk7semgKgMqslKS/i3pLzZQomp5XWdEy6269KG1ct1pUYGohZkSoaOeTldERSLkEqDVNPsmnmLfvB",
"VTGleVrDrJb9qNVMEi6BIVwonmFFCU7TdVvJUDyikdMqL3WKwhelXozcqJyu8RoqTUv2ma8xz94tu8Qk",
"KY3EaJ1wpjDVFXKpKVEmWI4N0sh76FeDwKaREmEBk1uGUISO9Fkw+Q4ZpimNN0cTdM6Q+YZwHAuQ2gSx",
"QgJyAVLHoy0vokmgllg99DcukNNeiI5wSgn81X3Xe37Uc5wliHtK4NyueyQGy9qR2MU7W0dcJcbb8r/i",
"PJc5V72lW1SuqUMypcljteHkL/scGldLBXFGmfTqIOYZpmzy3f7VDI17omlBFSD7K/ohFzTDYv1jl3ma",
"WoamQaNPdbv7WLm1bY1sXe8IcYGOWpj8XvewaVJp19jgoA0VYba+ZaV+m970ySQfk45V6JKxaQ+Hbl4Q",
"BnbbumoOwsApuP7jIzK4XZ1Rd4j5qsbqjH26sjUM3HE0a1ePWBJgMWYqmgtM42g0GI2PR3vrwxq5cF8V",
"3KgYum1dQRKqgKhCtMT5enY6Oz3Zfc7bnw9I9W/WOZjiyFaY+9a8n97oWUbiJ0+67Wk/4/lB9V0z1+p0",
"puuqa2ilBb3D9q7cll0m9uhC6ldzfbIV8DACDTtvi1cWYU2slpE2FFZkZlpBCEgt5ALT1KoiB6YreuNn",
"NHUfLTL7uezC6m93Hgur2U2NFV5pNqZ/piNSvISoaj+4b+YwBVH+QJlUOE3ND0uS63+1G1R+av42Zt3L",
"XOdTXlRlydDcq8+U+SuY8qLNDVCmYGkLsfLSqzuiuMKpb6i1OYZpWN3Q2YsxuzjcWUGEgfMtz/3Iotut",
"6J/1bQzoa136AsHOq40u41al2EGQOAjdYONX7g6td/toYakrw8GnlHYryRsjvSAg5ztGytPBk9SngKV/",
"TNJlFo93DTFcxugdZ55n4B6EpIdU0S5sGdjbZVu4oVVChVFHhVqk7ZahWIKzjq1RVUVEzHoC4gTbtrj2",
"WmCqH1Op+trwzraWp+lw2eey3+ihitRnjiQB8nm2zJc1eeecp4BN02SZL2efYe23siXjAmZSpv61GSic",
"UvbZL1BGdWUvewuIucDucO5xseyX637WB8JPdjwaDXW5ODzVKv2pOmb3SWeZpC4GNUFUGPRwjwBTXBr+",
"P7sN/Oks0ocvzmqcsf739MT+YvC9whLeTw/AIhKZ+RTVTrf0NJ/LTVu9r5a/EUXvbQ/H7VfzHhyIABXp",
"oRrSHEu54iL2wdVWNPOaY9caD5CeMkmXSeveX4kCQo/lcLHEzHUrm/yHg5PBaOjNsHSSDKILud4z7Gnt",
"1pDvTRobSMK2lhtMayqrievbyU47ijM4oJ/me5uxCfeuaV/071vS6Zft5dG9bzeNt4crAv5bxC/Tr8Ol",
"P3BFu5B5hOzlCi36NpU8LOUTBWO78rpDagaLwBUN/pw0LM+rekJdX9dNGleyJ0dVFmhzSB9C0yt/wga4",
"qWyb1cvWnc2g95VRu27pxEEpkwji4Xh8/BKdn5+fX4zefcMXx+n/vb46fndzOda/Xb0Tb/7nUrz9X/rf",
"b99+XBV/x9fn/8iuf+FX364Xwy+vh/Hr8bfBq5uv/dOvPhDdEleX/vvfy+woRe/M+ywghaBqPdUatCp6",
"BVhYpc/Np7+V4fcf/7wpn3uZoGrnVXR1/LaPvihb8G7vbup6S4qbu0rX47W5vm19yF4QBiklwGxG5t6Z",
"neeYJICGvUHgctzqpF+tVj1shs3x6tbK/i9XF5fvppfRsDfoJSpLzR5SZZT2fvrKsHeXbwKZJirCOa2l",
"WpNg6K5FmB6YBKPeoHdsUnyVGDX1XevZhB8uPT3+CwFYAcKIwQq52SHKuc6uKE7TNSKcSdf85wsk4R4E",
"LnVh1OO64ea1nu3GUoFi0EtcZ7d+xXIVB5PgA5fKiRZYOwCpXvF4be9/TG5nPCrPU2o7t/1/uaud7VO+",
"B69Zm5e2m6a96YPXvo/Jud4LTW04OH5q7lexZdxSuR1ECZZIKiwUxHobTwaDJ+Pvbo26vK+Y7Uq7nS7f",
"YFn+x78///NCaSP5DAxRiahFY7mPfn/uHxkuVMIF/WbvN3IQOm9DlXFaJCd/BJLPjK9YtQ9WCeM/wgQ+",
"MviaA1EQI9BzECekENot6rHWHGNllP10t7kLA1lkGdaFWxk0yuCi15WRRva/03hjTjHfleIbUPa6xhzK",
"5nIRucMfcWEopqChOXLmyslYCkmLGCRaJaASEHoy45ZWqUOTYkAMcTfevAHVfMYQNt5Df/K/9aoIW7CK",
"o6W5xDTvjHWM3T4zdo+d6vGl/uj4yZ/+3HWC1+Cpg1fV4utYUFMv/7HYVQaO57D1HLYOCls3rcCzO36Z",
"HkzZ2HswkJUTLcUFZVQmrfAFCL5iopDOOLVXU86QAFUIBjGKQVdBEnFWfxNdPri297gPhLOqAfkc0PYG",
"tO27v6513dS3snzvYd+0l1v5HOee49yfI851YpM2aFwzZB3vDHFZi2+dELN98tYJLj7JtlP65oppV+uo",
"Ns/cQf2urr+VwWft9jUxXyCnjGc3+8+4mTX0P5+T4cqAcJqinEtJ5ylU1rR1s/1FEWa2zcRI9T9yLLLt",
"i8L5Gpmj0++oh2UAFd3feuqP/uAzvNrKZx999tHH+KhdWydt/LJqmu4+/967KX6rboJ15Iy3IsqQ1oF7",
"ePlnzBweFGdTXTbaONPsduOc9vRymVD3X9hwTvv20YxpqYOIygfR/fth0JbirXv8yOOC2Be7lpfJJ7qs",
"pMJL+E0MpwovKVt22TySjtE1K99gBpu7zf8HAAD//xaq+MiDPwAA",
"H4sIAAAAAAAC/+xbe28bOZL/KkTvAZ7BdUuyHo4jYDDrON6s9yYPWM4s7mJDoNglNTfdZIdkW1ECf/cD",
"H93qB2XJO55ZDOB/Ykkkq35VrCpWFZnvAeFZzhkwJYPp9yDHAmegQLhvK9B/Y5BE0FxRzoJp8AGvAFEW",
"w9cgDOArzvIUGtPvcFpAMA2Og/v7MKB6zZcCxCYIA4YzPWJmhoEkCWRYL1GbXP8ulaBsZZZJ+s3D+12R",
"LUAgvkRUQSYRZQgwSZAjWEdTEqjQDAY78Zi5D+G5LwcN6bN/zi7Ohx/zlOP4vYFm5Rc8B6Go5S9gZTB/",
"L1EF0wCKaA1SRcdB2GYRBjLBAuZrqpI5JoQXbkuq1Z+C4+FoPDl5cfpycDwMbsPA6MADtyKOhcAbQ5vh",
"XCZcza3AdUzZJipHu6juw0DAl4IKiDUAJ5Mf6221mi/+BURpvnVNzRRWhUdROKNNRDij0YCcjgYvXo5e",
"vJhMXk7i8cKnsUequCWM5lvR2AF+NnraXfbrcw/zXYorROr3nToLPclL/1shYI9wNMMrqEym5Yk4A+2H",
"KgFUGDIQI7Oghy4Vygqp0AJQweiXQocLM3FF74AhAZIXggBaCV7kvRt2uUSaCaIS8YwqBTFaCp6ZJVoW",
"kCpEGAnMYp4hzgAtsIQYcYYw+vjx8jWi8oatgIHACuLeDdvGAmvhBpjPhFJOsHI72BTwFzeC1gkIMFgM",
"FSQTXqSxEa6UG7MY6b2UCoTh/3e+RoqjlEqFcJqiko2c3rBEqVxO+/2YE9nLKBFc8qXqEZ71gUWF7JOU",
"9rHenr7zrZ/vKKx/Mj9FJKVRihVI9Rf8rXS+uWY0r5gctRSgrREKvbV+L7LbMTfb8fBON7fuANW09+Ka",
"FwSzK0fmjeHoi4XFooIwp3EX1OVrDak+7d8AM4ZJfLoYkggvhuNoPD4eRS8HZBKdHA9HgxM4HbyEoQ+d",
"AoaZegCXBmEnHYbKmcuSshhRVXqLcVH0gQuF00PsprQZRe8giqkAorjY9JcFi3EGTOFUdkajhK8jxSPN",
"OrKQW0qakBewnCxOomMyWkbjGA8ifDIcRoPF4GQwHL2MX8Qv9ga6rca6e9uxwJpX7olcuyJjM3AdEgla",
"eGsEfBDOddIk4dIYAE7T98tg+ul78F8ClsE0+Et/m1T1XdrQf28WX8ESBDACwX3YAR03wR4PR6CP+whO",
"Xy6i42E8ivB4chKNhycnk8l4PBgMBkEYLLnIsAqmQVEYZe4RLPYIdLsV6S0oHGOFn1IwLpUAmBOeZVR5",
"XeaHBMvkx9JzFgVNFXLTPe6XY/IZryztdmpqRmzcpYykRUzZCr27+PXqLKjlSw/J42hUiuhkU/cP6e/K",
"HlddkySFVDyj33B11j4E4rw5+z4MYqoVsChUJ90QCaTRqU9R1orFFtJDLC/15BJ+22wa3NuEa+JvHfLJ",
"vMKwkhXdvSI4CH6PdnR2uEBni5pQ6nZXy8pzLtVKgHxcRp7jjY5gcwE5l1RxUcp7iI1elYs23mS/FmD3",
"UZrV596HQSFd7XcQjo8SxCEOEgYXQnDxlHZBeAxeRetJuJY3ePIdLK1iHg6VhkM1vUXYb0FGyl+odbbD",
"JDWzPWZfqv+gfbDa9W1EwwUMKT/yN+cf9hQDi4J8BrU7PcQMwVcqlQ64s+uzd6/Prl6jmeJCB2SSYinR",
"K0Oi107O3ZfIcdgZyPyFyHUCtnpQHBUS0JILl27lXCiXnJt6NUY6ShUK0AVbUeYyst4Nu66yM0OoVbvo",
"KtdlZG/OP6BccK22EK0TShJdsxQS4htW8n0/c7RsfmfYWyw9pAsdrpDMgdAl1dhcUXPDjoiNoCLCOY1u",
"isFgRPSJbj7BEbLKKNkhLGs5pUb9mKJnW7R2ValFtOO11LWSaU3TVKumUq7idf3qqs3p07RdKlVi/Z3G",
"hnqZ3PXQDACVWS1JeRH3VpyvUjA5rbSmY9LdflXauGqxrsTQQMyKVNHIIS+nI5JyCVJpmHqSTTNv2A+u",
"iinN0xpmtexHrWaScAkM4ULxDCtKcJpu2kqG4hGNnFZ5qVMUviz1YuRG5XSN11BpWrLPfI159m7YBSZJ",
"aSRG64QzhamukEtNiTLBcmyQRt5DvxoENo2UCAuY3jCEInSkz4Lpd8gwTWl8fzRFZwyZbwjHsQCpTRAr",
"JCAXIHU82vIimgRqidVDf+MCOe2F6AinlMBf3Xe950c9x1mCuKMEzuy6R2KwrB2JXbyzTcRVYrwt/yvO",
"c5lz1Vu5ReWaOiRTmjxWG07+ss+hcbVUEGeUSa8OYp5hyqbf7V/N0LgnmhVUAbK/oh9yQTMsNj92maep",
"ZWgaNPpUt7uPlVvb1sjW9Y4QF+iohcnvdQ+bJpV2jQ0O2lARZpsbVuq36U2fTPIx7ViFLhmb9nDo5gVh",
"YLetq+YgDJyC6z8+IoPb1Rl1h5ivaqzO2KcrW8PAHUfzdvWIJQEWY6aihcA0jkaD0eR4tLc+rJEL91XB",
"jYqh29YVJKEKiCpES5yvpyfzk/Huc97+fECqf73JwRRHtsLct+b97FrPMhI/edJtT/s5zw+q75q5Vqcz",
"XVddQyst6B22t+W27DKxRxdSv5rrk62AhxFo2HlbvLIIa2K1jLShsCIz0wpCQGohl5imVhU5MF3RGz+j",
"qftokdnPZRdWf7v1WFjNbmqs8FqzMf0zHZHiFURV+8F9M4cpiPIHyqTCaWp+WJFc/6vdoPJT87cx607m",
"Op/yoipLhuZefabMX8GUF21ugDIFK1uIlZde3RHFFU59Q63NMUzD6obOXozZxeHOCiIMnG957keW3W5F",
"/7RvY0Bf69IXCHZebXQZtyrFDoLEQegGG79yd2i920cLS10ZDj6ltFtJ3hjpBQE53zFSng6epD4FLP1j",
"kq6yeLJriOEyRu848zwDdyAkPaSKdmHLwN4u28INrRIqjDoq1CJttwzFEpx1bI2qKiJi1hMQJ9i2xbXX",
"AlP9mErV14Z3urU8TYfLPpf9Rg9VpD5zJAmQz/NVvqrJu+A8BWyaJqt8Nf8MG7+VrRgXMJcy9a/NQOGU",
"ss9+gTKqK3vZW0LMBXaHc4+LVb9c97M+EH6y49FoqMvF4YlW6U/VMbtPOsskdTGoCaLCoId7BJji0vD/",
"2W3gT6eRPnxxVuOM9b8nY/uLwfcKS3g/OwCLSGTmU1Q73dLTfC43a/W+Wv5GFL2zPRy3X817cCACVKSH",
"akhzLOWai9gHV1vR3GuOXWs8QHrKJF0lrXt/JQoIPZbDxQoz161s8h8OxoPR0Jth6SQZRBdyvWfY09qt",
"Id+bNDaQhG0tN5jWVFYT17eTnXYUZ3BAP833NuM+3LumfdG/b0mnX7aXR/e+3TTeHq4I+G8Rv0y/Dpf+",
"wBXtQuYRspcrtOiPTyWrZPSQEsEudDWCPwUNy+Opnj93GR6clIqCsV2ZZx1ON/Vcy54cVbmkzUS9VCQ8",
"aRvd1MfNGmgbFMyg961Su/rpRFMpkwji4WRy/BKdnZ2dnY/efcPnx+n/vb48fnd9MdG/Xb4Tb/7nQrz9",
"X/rfb99+XBd/x1dn/8iufuGX366Wwy+vh/HrybfBq+uv/ZOvPhDdQrmQIPa/utlR0N6aV15ACkHVZqY1",
"aFX0CrCwSl+YT38rg/g//nldPhozodnOq+jqU8A+HaNsybsdwJnrUClubjxdp9hWDLaBIntBGKSUALN5",
"nXutdpZjkgAa9gaBy5SrfGG9XvewGTaHtFsr+79cnl+8m11Ew96gl6gsNXtIlVHa+9krw95d4QlkWrEI",
"57SWsE2DobtcYXpgGox6g96xKRRUYtTUdw1sE8S49NwUnAvAChBGDNbIzQ5RznWORnGabhDhTLorBL5E",
"Eu5A4FIXRj2up27e/NmeLhUoBr3E9YfrFzWXcTANPnCpnGiBtQOQ6hWPN/YWyWSIxqPyPKW2/9v/l7sg",
"2j4IfPCytnn1e9+0N31821c2Odd7oakNB8dPzf0ytoxbKreDKMESSYWFglhv43gweDL+7u6py/uS2d62",
"2+nyJZflf/z78z8rlDaSz8AQlYhaNJb76Pfn/pHhQiVc0G/2liQHobM/VBmnRTL+I5B8ZnzNqn2wSpj8",
"ESbwkcHXHIiCGIGegzghhdBuUY+15hgro+yn2/vbMJBFlmFd/pVBowwuel0ZaWT/O43vzSnmu5h8A8pe",
"+piT3FxRIndAIy4MxRQ0NEfOXFwZSyFpEYNE6wRUAkJPZtzSKnVo0gCIIe7Gmzegmo8hwsar6k/+F2MV",
"YQtWcbQyV6HmtbKOsdvHyu7JVD2+1J8uP/kDottO8Bo8dfCqGoUdC2rq5T8Wu8rA8Ry2nsPWQWHruhV4",
"dscv08kp24MPBrJyoqW4pIzKpBW+AMFXTBTSGaf2asoZEqAKwSBGMehKRSLO6i+ry2fb9jb4gXBWtTGf",
"A9regLZ9Pdi1ruv6VpavRuzL+HIrn+Pcc5z7c8S5TmzSBo1rhqzjnSEua/GtE2K2D+c6wcUn2XZK31xU",
"7WpA1eaZm6zf1fW3Mvis3b5J5kvklPHsZv8ZN7OG/udzMlwZEE5TlHMp6SKFypq2bra/KMLMtpkYqf5f",
"j0W2fZe42CBzdPod9bAMoKL7W0/90R98hldb+eyjzz76GB+1a+ukjV9WTdPd5997N8Vv1U2wjpzxVkQZ",
"0jpwzzf/jJnDg+LcV1eWvjjz1j2B5HFB7LtdO7fTFsc57Wk+MqHuf8zhnPbtGx3TewcRle+v+3dDk0+0",
"mvUKryhbPcRAKryC38jGKJGVTzQrNvvo3N7/fwAAAP//5y+av8k/AAA=",
}
// GetSwagger returns the Swagger specification corresponding to the generated code
// in this file.
func GetSwagger() (*openapi3.Swagger, error) {
// GetSwagger returns the content of the embedded swagger specification file
// or error if failed to decode
func decodeSpec() ([]byte, error) {
zipped, err := base64.StdEncoding.DecodeString(strings.Join(swaggerSpec, ""))
if err != nil {
return nil, fmt.Errorf("error base64 decoding spec: %s", err)
@ -562,9 +601,57 @@ func GetSwagger() (*openapi3.Swagger, error) {
return nil, fmt.Errorf("error decompressing spec: %s", err)
}
swagger, err := openapi3.NewSwaggerLoader().LoadSwaggerFromData(buf.Bytes())
if err != nil {
return nil, fmt.Errorf("error loading Swagger: %s", err)
}
return swagger, nil
return buf.Bytes(), nil
}
var rawSpec = decodeSpecCached()
// a naive cached of a decoded swagger spec
func decodeSpecCached() func() ([]byte, error) {
data, err := decodeSpec()
return func() ([]byte, error) {
return data, err
}
}
// Constructs a synthetic filesystem for resolving external references when loading openapi specifications.
func PathToRawSpec(pathToFile string) map[string]func() ([]byte, error) {
var res = make(map[string]func() ([]byte, error))
if len(pathToFile) > 0 {
res[pathToFile] = rawSpec
}
return res
}
// GetSwagger returns the Swagger specification corresponding to the generated code
// in this file. The external references of Swagger specification are resolved.
// The logic of resolving external references is tightly connected to "import-mapping" feature.
// Externally referenced files must be embedded in the corresponding golang packages.
// Urls can be supported but this task was out of the scope.
func GetSwagger() (swagger *openapi3.T, err error) {
var resolvePath = PathToRawSpec("")
loader := openapi3.NewLoader()
loader.IsExternalRefsAllowed = true
loader.ReadFromURIFunc = func(loader *openapi3.Loader, url *url.URL) ([]byte, error) {
var pathToFile = url.String()
pathToFile = path.Clean(pathToFile)
getSpec, ok := resolvePath[pathToFile]
if !ok {
err1 := fmt.Errorf("path not found: %s", pathToFile)
return nil, err1
}
return getSpec()
}
var specData []byte
specData, err = rawSpec()
if err != nil {
return
}
swagger, err = loader.LoadFromData(specData)
if err != nil {
return
}
return
}

View file

@ -372,8 +372,7 @@ components:
- options
properties:
status:
type: string
enum: ['success', 'failure', 'pending', 'running']
$ref: '#/components/schemas/UploadStatusValue'
type:
$ref: '#/components/schemas/UploadTypes'
options:
@ -382,6 +381,9 @@ components:
- $ref: '#/components/schemas/AWSS3UploadStatus'
- $ref: '#/components/schemas/GCPUploadStatus'
- $ref: '#/components/schemas/AzureUploadStatus'
UploadStatusValue:
type: string
enum: ['success', 'failure', 'pending', 'running']
UploadTypes:
type: string
enum:

View file

@ -281,7 +281,7 @@ func (h *apiHandlers) PostCompose(ctx echo.Context) error {
var irTarget *target.Target
/* oneOf is not supported by the openapi generator so marshal and unmarshal the uploadrequest based on the type */
switch ir.ImageType {
case ImageTypes_aws:
case ImageTypesAws:
var awsUploadOptions AWSEC2UploadOptions
jsonUploadOptions, err := json.Marshal(ir.UploadOptions)
if err != nil {
@ -311,17 +311,17 @@ func (h *apiHandlers) PostCompose(ctx echo.Context) error {
}
irTarget = t
case ImageTypes_guest_image:
case ImageTypesGuestImage:
fallthrough
case ImageTypes_vsphere:
case ImageTypesVsphere:
fallthrough
case ImageTypes_image_installer:
case ImageTypesImageInstaller:
fallthrough
case ImageTypes_edge_installer:
case ImageTypesEdgeInstaller:
fallthrough
case ImageTypes_edge_container:
case ImageTypesEdgeContainer:
fallthrough
case ImageTypes_edge_commit:
case ImageTypesEdgeCommit:
var awsS3UploadOptions AWSS3UploadOptions
jsonUploadOptions, err := json.Marshal(ir.UploadOptions)
if err != nil {
@ -342,7 +342,7 @@ func (h *apiHandlers) PostCompose(ctx echo.Context) error {
t.ImageName = key
irTarget = t
case ImageTypes_gcp:
case ImageTypesGcp:
var gcpUploadOptions GCPUploadOptions
jsonUploadOptions, err := json.Marshal(ir.UploadOptions)
if err != nil {
@ -375,7 +375,7 @@ func (h *apiHandlers) PostCompose(ctx echo.Context) error {
}
irTarget = t
case ImageTypes_azure:
case ImageTypesAzure:
var azureUploadOptions AzureUploadOptions
jsonUploadOptions, err := json.Marshal(ir.UploadOptions)
if err != nil {
@ -515,23 +515,23 @@ func (h *apiHandlers) PostCompose(ctx echo.Context) error {
func imageTypeFromApiImageType(it ImageTypes) string {
switch it {
case ImageTypes_aws:
case ImageTypesAws:
return "ami"
case ImageTypes_gcp:
case ImageTypesGcp:
return "vhd"
case ImageTypes_azure:
case ImageTypesAzure:
return "vhd"
case ImageTypes_guest_image:
case ImageTypesGuestImage:
return "qcow2"
case ImageTypes_vsphere:
case ImageTypesVsphere:
return "vmdk"
case ImageTypes_image_installer:
case ImageTypesImageInstaller:
return "image-installer"
case ImageTypes_edge_commit:
case ImageTypesEdgeCommit:
return "rhel-edge-commit"
case ImageTypes_edge_container:
case ImageTypesEdgeContainer:
return "rhel-edge-container"
case ImageTypes_edge_installer:
case ImageTypesEdgeInstaller:
return "rhel-edge-installer"
}
return ""
@ -562,27 +562,27 @@ func (h *apiHandlers) GetComposeStatus(ctx echo.Context, id string) error {
switch tr.Name {
case "org.osbuild.aws":
uploadType = UploadTypes_aws
uploadType = UploadTypesAws
awsOptions := tr.Options.(*target.AWSTargetResultOptions)
uploadOptions = AWSEC2UploadStatus{
Ami: awsOptions.Ami,
Region: awsOptions.Region,
}
case "org.osbuild.aws.s3":
uploadType = UploadTypes_aws_s3
uploadType = UploadTypesAwsS3
awsOptions := tr.Options.(*target.AWSS3TargetResultOptions)
uploadOptions = AWSS3UploadStatus{
Url: awsOptions.URL,
}
case "org.osbuild.gcp":
uploadType = UploadTypes_gcp
uploadType = UploadTypesGcp
gcpOptions := tr.Options.(*target.GCPTargetResultOptions)
uploadOptions = GCPUploadStatus{
ImageName: gcpOptions.ImageName,
ProjectId: gcpOptions.ProjectID,
}
case "org.osbuild.azure.image":
uploadType = UploadTypes_azure
uploadType = UploadTypesAzure
gcpOptions := tr.Options.(*target.AzureImageTargetResultOptions)
uploadOptions = AzureUploadStatus{
ImageName: gcpOptions.ImageName,
@ -592,7 +592,7 @@ func (h *apiHandlers) GetComposeStatus(ctx echo.Context, id string) error {
}
us = &UploadStatus{
Status: result.UploadStatus,
Status: UploadStatusValue(result.UploadStatus),
Type: uploadType,
Options: uploadOptions,
}
@ -613,24 +613,24 @@ func (h *apiHandlers) GetComposeStatus(ctx echo.Context, id string) error {
func composeStatusFromJobStatus(js *worker.JobStatus, result *worker.OSBuildJobResult) ImageStatusValue {
if js.Canceled {
return ImageStatusValue_failure
return ImageStatusValueFailure
}
if js.Started.IsZero() {
return ImageStatusValue_pending
return ImageStatusValuePending
}
if js.Finished.IsZero() {
// TODO: handle also ImageStatusValue_uploading
// TODO: handle also ImageStatusValue_registering
return ImageStatusValue_building
// TODO: handle also ImageStatusValueUploading
// TODO: handle also ImageStatusValueRegistering
return ImageStatusValueBuilding
}
if result.Success {
return ImageStatusValue_success
return ImageStatusValueSuccess
}
return ImageStatusValue_failure
return ImageStatusValueFailure
}
// ComposeMetadata handles a /composes/{id}/metadata GET request

View file

@ -441,7 +441,7 @@ func TestImageTypes(t *testing.T) {
"share_with_accounts": ["123456789012","234567890123"]
}
}
}`, test_distro.TestDistroName, test_distro.TestArch3Name, string(v2.ImageTypes_aws)), http.StatusCreated, `
}`, test_distro.TestDistroName, test_distro.TestArch3Name, string(v2.ImageTypesAws)), http.StatusCreated, `
{
"href": "/api/image-builder-composer/v2/compose",
"kind": "ComposeId"
@ -460,7 +460,7 @@ func TestImageTypes(t *testing.T) {
"region": "eu-central-1"
}
}
}`, test_distro.TestDistroName, test_distro.TestArch3Name, string(v2.ImageTypes_aws)), http.StatusCreated, `
}`, test_distro.TestDistroName, test_distro.TestArch3Name, string(v2.ImageTypesAws)), http.StatusCreated, `
{
"href": "/api/image-builder-composer/v2/compose",
"kind": "ComposeId"
@ -479,7 +479,7 @@ func TestImageTypes(t *testing.T) {
"region": "eu-central-1"
}
}
}`, test_distro.TestDistroName, test_distro.TestArch3Name, string(v2.ImageTypes_edge_commit)), http.StatusCreated, `
}`, test_distro.TestDistroName, test_distro.TestArch3Name, string(v2.ImageTypesEdgeCommit)), http.StatusCreated, `
{
"href": "/api/image-builder-composer/v2/compose",
"kind": "ComposeId"
@ -498,7 +498,7 @@ func TestImageTypes(t *testing.T) {
"region": "eu-central-1"
}
}
}`, test_distro.TestDistroName, test_distro.TestArch3Name, string(v2.ImageTypes_edge_installer)), http.StatusCreated, `
}`, test_distro.TestDistroName, test_distro.TestArch3Name, string(v2.ImageTypesEdgeInstaller)), http.StatusCreated, `
{
"href": "/api/image-builder-composer/v2/compose",
"kind": "ComposeId"
@ -520,7 +520,7 @@ func TestImageTypes(t *testing.T) {
"location": "westeurope"
}
}
}`, test_distro.TestDistroName, test_distro.TestArch3Name, string(v2.ImageTypes_azure)), http.StatusCreated, `
}`, test_distro.TestDistroName, test_distro.TestArch3Name, string(v2.ImageTypesAzure)), http.StatusCreated, `
{
"href": "/api/image-builder-composer/v2/compose",
"kind": "ComposeId"
@ -541,7 +541,7 @@ func TestImageTypes(t *testing.T) {
"share_with_accounts": ["user:alice@example.com"]
}
}
}`, test_distro.TestDistroName, test_distro.TestArch3Name, string(v2.ImageTypes_gcp)), http.StatusCreated, `
}`, test_distro.TestDistroName, test_distro.TestArch3Name, string(v2.ImageTypesGcp)), http.StatusCreated, `
{
"href": "/api/image-builder-composer/v2/compose",
"kind": "ComposeId"
@ -560,7 +560,7 @@ func TestImageTypes(t *testing.T) {
"region": "eu-central-1"
}
}
}`, test_distro.TestDistroName, test_distro.TestArch3Name, string(v2.ImageTypes_image_installer)), http.StatusCreated, `
}`, test_distro.TestDistroName, test_distro.TestArch3Name, string(v2.ImageTypesImageInstaller)), http.StatusCreated, `
{
"href": "/api/image-builder-composer/v2/compose",
"kind": "ComposeId"
@ -579,7 +579,7 @@ func TestImageTypes(t *testing.T) {
"region": "eu-central-1"
}
}
}`, test_distro.TestDistroName, test_distro.TestArch3Name, string(v2.ImageTypes_guest_image)), http.StatusCreated, `
}`, test_distro.TestDistroName, test_distro.TestArch3Name, string(v2.ImageTypesGuestImage)), http.StatusCreated, `
{
"href": "/api/image-builder-composer/v2/compose",
"kind": "ComposeId"
@ -598,7 +598,7 @@ func TestImageTypes(t *testing.T) {
"region": "eu-central-1"
}
}
}`, test_distro.TestDistroName, test_distro.TestArch3Name, string(v2.ImageTypes_vsphere)), http.StatusCreated, `
}`, test_distro.TestDistroName, test_distro.TestArch3Name, string(v2.ImageTypesVsphere)), http.StatusCreated, `
{
"href": "/api/image-builder-composer/v2/compose",
"kind": "ComposeId"

View file

@ -1,13 +1,43 @@
// Package api provides primitives to interact the openapi HTTP API.
// Package api provides primitives to interact with the openapi HTTP API.
//
// Code generated by github.com/deepmap/oapi-codegen DO NOT EDIT.
// Code generated by github.com/deepmap/oapi-codegen version v1.8.2 DO NOT EDIT.
package api
import (
"fmt"
"net/http"
"github.com/deepmap/oapi-codegen/pkg/runtime"
"github.com/labstack/echo/v4"
"net/http"
)
// Defines values for ComposeStatusValue.
const (
ComposeStatusValueFailure ComposeStatusValue = "failure"
ComposeStatusValuePending ComposeStatusValue = "pending"
ComposeStatusValueRegistering ComposeStatusValue = "registering"
ComposeStatusValueSuccess ComposeStatusValue = "success"
)
// Defines values for ImageStatusValue.
const (
ImageStatusValueBuilding ImageStatusValue = "building"
ImageStatusValueFailure ImageStatusValue = "failure"
ImageStatusValuePending ImageStatusValue = "pending"
ImageStatusValueSuccess ImageStatusValue = "success"
ImageStatusValueUploading ImageStatusValue = "uploading"
)
// Defines values for StatusStatus.
const (
StatusStatusOK StatusStatus = "OK"
)
// ComposeLogs defines model for ComposeLogs.
@ -35,12 +65,15 @@ type ComposeResponse struct {
// ComposeStatus defines model for ComposeStatus.
type ComposeStatus struct {
ImageStatuses []ImageStatus `json:"image_statuses"`
KojiBuildId *int `json:"koji_build_id,omitempty"`
KojiTaskId int `json:"koji_task_id"`
Status string `json:"status"`
ImageStatuses []ImageStatus `json:"image_statuses"`
KojiBuildId *int `json:"koji_build_id,omitempty"`
KojiTaskId int `json:"koji_task_id"`
Status ComposeStatusValue `json:"status"`
}
// ComposeStatusValue defines model for ComposeStatusValue.
type ComposeStatusValue string
// ImageRequest defines model for ImageRequest.
type ImageRequest struct {
Architecture string `json:"architecture"`
@ -50,9 +83,12 @@ type ImageRequest struct {
// ImageStatus defines model for ImageStatus.
type ImageStatus struct {
Status string `json:"status"`
Status ImageStatusValue `json:"status"`
}
// ImageStatusValue defines model for ImageStatusValue.
type ImageStatusValue string
// Koji defines model for Koji.
type Koji struct {
Server string `json:"server"`
@ -67,13 +103,16 @@ type Repository struct {
// Status defines model for Status.
type Status struct {
Status string `json:"status"`
Status StatusStatus `json:"status"`
}
// StatusStatus defines model for Status.Status.
type StatusStatus string
// PostComposeJSONBody defines parameters for PostCompose.
type PostComposeJSONBody ComposeRequest
// PostComposeRequestBody defines body for PostCompose for application/json ContentType.
// PostComposeJSONRequestBody defines body for PostCompose for application/json ContentType.
type PostComposeJSONRequestBody PostComposeJSONBody
// ServerInterface represents all server handlers.
@ -115,7 +154,7 @@ func (w *ServerInterfaceWrapper) GetComposeId(ctx echo.Context) error {
// ------------- Path parameter "id" -------------
var id string
err = runtime.BindStyledParameter("simple", false, "id", ctx.Param("id"), &id)
err = runtime.BindStyledParameterWithLocation("simple", false, "id", runtime.ParamLocationPath, ctx.Param("id"), &id)
if err != nil {
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter id: %s", err))
}
@ -131,7 +170,7 @@ func (w *ServerInterfaceWrapper) GetComposeIdLogs(ctx echo.Context) error {
// ------------- Path parameter "id" -------------
var id string
err = runtime.BindStyledParameter("simple", false, "id", ctx.Param("id"), &id)
err = runtime.BindStyledParameterWithLocation("simple", false, "id", runtime.ParamLocationPath, ctx.Param("id"), &id)
if err != nil {
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter id: %s", err))
}
@ -147,7 +186,7 @@ func (w *ServerInterfaceWrapper) GetComposeIdManifests(ctx echo.Context) error {
// ------------- Path parameter "id" -------------
var id string
err = runtime.BindStyledParameter("simple", false, "id", ctx.Param("id"), &id)
err = runtime.BindStyledParameterWithLocation("simple", false, "id", runtime.ParamLocationPath, ctx.Param("id"), &id)
if err != nil {
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter id: %s", err))
}
@ -183,15 +222,21 @@ type EchoRouter interface {
// RegisterHandlers adds each server route to the EchoRouter.
func RegisterHandlers(router EchoRouter, si ServerInterface) {
RegisterHandlersWithBaseURL(router, si, "")
}
// Registers handlers, and prepends BaseURL to the paths, so that the paths
// can be served under a prefix.
func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL string) {
wrapper := ServerInterfaceWrapper{
Handler: si,
}
router.POST("/compose", wrapper.PostCompose)
router.GET("/compose/:id", wrapper.GetComposeId)
router.GET("/compose/:id/logs", wrapper.GetComposeIdLogs)
router.GET("/compose/:id/manifests", wrapper.GetComposeIdManifests)
router.GET("/status", wrapper.GetStatus)
router.POST(baseURL+"/compose", wrapper.PostCompose)
router.GET(baseURL+"/compose/:id", wrapper.GetComposeId)
router.GET(baseURL+"/compose/:id/logs", wrapper.GetComposeIdLogs)
router.GET(baseURL+"/compose/:id/manifests", wrapper.GetComposeIdManifests)
router.GET(baseURL+"/status", wrapper.GetStatus)
}

View file

@ -163,13 +163,7 @@ components:
- koji_task_id
properties:
status:
type: string
enum:
- success
- failure
- pending
- registering
example: success
$ref: '#/components/schemas/ComposeStatusValue'
image_statuses:
type: array
items:
@ -180,6 +174,14 @@ components:
koji_build_id:
type: integer
example: 42
ComposeStatusValue:
type: string
enum:
- success
- failure
- pending
- registering
example: success
ComposeLogs:
required:
- koji_init_logs
@ -195,14 +197,16 @@ components:
- status
properties:
status:
type: string
enum:
- success
- failure
- pending
- building
- uploading
example: success
$ref: '#/components/schemas/ImageStatusValue'
ImageStatusValue:
type: string
enum:
- success
- failure
- pending
- building
- uploading
example: success
ComposeRequest:
type: object
required:

View file

@ -245,54 +245,54 @@ func splitExtension(filename string) string {
return "." + strings.Join(filenameParts[1:], ".")
}
func composeStatusFromJobStatus(js *worker.JobStatus, initResult *worker.KojiInitJobResult, buildResults []worker.OSBuildKojiJobResult, result *worker.KojiFinalizeJobResult) string {
func composeStatusFromJobStatus(js *worker.JobStatus, initResult *worker.KojiInitJobResult, buildResults []worker.OSBuildKojiJobResult, result *worker.KojiFinalizeJobResult) api.ComposeStatusValue {
if js.Canceled {
return "failure"
return api.ComposeStatusValueFailure
}
if js.Finished.IsZero() {
return "pending"
return api.ComposeStatusValuePending
}
if initResult.KojiError != "" {
return "failure"
return api.ComposeStatusValueFailure
}
for _, buildResult := range buildResults {
if buildResult.OSBuildOutput != nil && !buildResult.OSBuildOutput.Success {
return "failure"
return api.ComposeStatusValueFailure
}
if buildResult.KojiError != "" {
return "failure"
return api.ComposeStatusValueFailure
}
}
if result.KojiError != "" {
return "failure"
return api.ComposeStatusValueFailure
}
return "success"
return api.ComposeStatusValueSuccess
}
func imageStatusFromJobStatus(js *worker.JobStatus, initResult *worker.KojiInitJobResult, buildResult *worker.OSBuildKojiJobResult) string {
func imageStatusFromJobStatus(js *worker.JobStatus, initResult *worker.KojiInitJobResult, buildResult *worker.OSBuildKojiJobResult) api.ImageStatusValue {
if js.Canceled {
return "failure"
return api.ImageStatusValueFailure
}
if initResult.KojiError != "" {
return "failure"
return api.ImageStatusValueFailure
}
if js.Started.IsZero() {
return "pending"
return api.ImageStatusValuePending
}
if js.Finished.IsZero() {
return "building"
return api.ImageStatusValueBuilding
}
if buildResult.OSBuildOutput != nil && buildResult.OSBuildOutput.Success && buildResult.KojiError == "" {
return "success"
return api.ImageStatusValueSuccess
}
return "failure"

View file

@ -1,6 +1,6 @@
// Package api provides primitives to interact the openapi HTTP API.
// Package api provides primitives to interact with the openapi HTTP API.
//
// Code generated by github.com/deepmap/oapi-codegen DO NOT EDIT.
// Code generated by github.com/deepmap/oapi-codegen version v1.8.2 DO NOT EDIT.
package api
import (
@ -9,17 +9,24 @@ import (
"encoding/base64"
"encoding/json"
"fmt"
"net/http"
"net/url"
"path"
"strings"
"github.com/deepmap/oapi-codegen/pkg/runtime"
"github.com/getkin/kin-openapi/openapi3"
"github.com/labstack/echo/v4"
"net/http"
"strings"
)
const (
BearerScopes = "Bearer.Scopes"
)
// Error defines model for Error.
type Error struct {
// Embedded struct due to allOf(#/components/schemas/ObjectReference)
ObjectReference
ObjectReference `yaml:",inline"`
// Embedded fields due to inline allOf schema
Code string `json:"code"`
@ -32,7 +39,7 @@ type Error struct {
// GetJobResponse defines model for GetJobResponse.
type GetJobResponse struct {
// Embedded struct due to allOf(#/components/schemas/ObjectReference)
ObjectReference
ObjectReference `yaml:",inline"`
// Embedded fields due to inline allOf schema
Canceled bool `json:"canceled"`
}
@ -53,7 +60,7 @@ type RequestJobRequest struct {
// RequestJobResponse defines model for RequestJobResponse.
type RequestJobResponse struct {
// Embedded struct due to allOf(#/components/schemas/ObjectReference)
ObjectReference
ObjectReference `yaml:",inline"`
// Embedded fields due to inline allOf schema
Args *json.RawMessage `json:"args,omitempty"`
ArtifactLocation string `json:"artifact_location"`
@ -65,7 +72,7 @@ type RequestJobResponse struct {
// StatusResponse defines model for StatusResponse.
type StatusResponse struct {
// Embedded struct due to allOf(#/components/schemas/ObjectReference)
ObjectReference
ObjectReference `yaml:",inline"`
// Embedded fields due to inline allOf schema
Status string `json:"status"`
}
@ -84,10 +91,10 @@ type RequestJobJSONBody RequestJobRequest
// UpdateJobJSONBody defines parameters for UpdateJob.
type UpdateJobJSONBody UpdateJobRequest
// RequestJobRequestBody defines body for RequestJob for application/json ContentType.
// RequestJobJSONRequestBody defines body for RequestJob for application/json ContentType.
type RequestJobJSONRequestBody RequestJobJSONBody
// UpdateJobRequestBody defines body for UpdateJob for application/json ContentType.
// UpdateJobJSONRequestBody defines body for UpdateJob for application/json ContentType.
type UpdateJobJSONRequestBody UpdateJobJSONBody
// ServerInterface represents all server handlers.
@ -126,12 +133,12 @@ func (w *ServerInterfaceWrapper) GetError(ctx echo.Context) error {
// ------------- Path parameter "id" -------------
var id string
err = runtime.BindStyledParameter("simple", false, "id", ctx.Param("id"), &id)
err = runtime.BindStyledParameterWithLocation("simple", false, "id", runtime.ParamLocationPath, ctx.Param("id"), &id)
if err != nil {
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter id: %s", err))
}
ctx.Set("Bearer.Scopes", []string{""})
ctx.Set(BearerScopes, []string{""})
// Invoke the callback with all the unmarshalled arguments
err = w.Handler.GetError(ctx, id)
@ -153,7 +160,7 @@ func (w *ServerInterfaceWrapper) GetJob(ctx echo.Context) error {
// ------------- Path parameter "token" -------------
var token string
err = runtime.BindStyledParameter("simple", false, "token", ctx.Param("token"), &token)
err = runtime.BindStyledParameterWithLocation("simple", false, "token", runtime.ParamLocationPath, ctx.Param("token"), &token)
if err != nil {
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter token: %s", err))
}
@ -169,7 +176,7 @@ func (w *ServerInterfaceWrapper) UpdateJob(ctx echo.Context) error {
// ------------- Path parameter "token" -------------
var token string
err = runtime.BindStyledParameter("simple", false, "token", ctx.Param("token"), &token)
err = runtime.BindStyledParameterWithLocation("simple", false, "token", runtime.ParamLocationPath, ctx.Param("token"), &token)
if err != nil {
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter token: %s", err))
}
@ -185,7 +192,7 @@ func (w *ServerInterfaceWrapper) UploadJobArtifact(ctx echo.Context) error {
// ------------- Path parameter "token" -------------
var token string
err = runtime.BindStyledParameter("simple", false, "token", ctx.Param("token"), &token)
err = runtime.BindStyledParameterWithLocation("simple", false, "token", runtime.ParamLocationPath, ctx.Param("token"), &token)
if err != nil {
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter token: %s", err))
}
@ -193,7 +200,7 @@ func (w *ServerInterfaceWrapper) UploadJobArtifact(ctx echo.Context) error {
// ------------- Path parameter "name" -------------
var name string
err = runtime.BindStyledParameter("simple", false, "name", ctx.Param("name"), &name)
err = runtime.BindStyledParameterWithLocation("simple", false, "name", runtime.ParamLocationPath, ctx.Param("name"), &name)
if err != nil {
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter name: %s", err))
}
@ -238,49 +245,55 @@ type EchoRouter interface {
// RegisterHandlers adds each server route to the EchoRouter.
func RegisterHandlers(router EchoRouter, si ServerInterface) {
RegisterHandlersWithBaseURL(router, si, "")
}
// Registers handlers, and prepends BaseURL to the paths, so that the paths
// can be served under a prefix.
func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL string) {
wrapper := ServerInterfaceWrapper{
Handler: si,
}
router.GET("/errors/:id", wrapper.GetError)
router.POST("/jobs", wrapper.RequestJob)
router.GET("/jobs/:token", wrapper.GetJob)
router.PATCH("/jobs/:token", wrapper.UpdateJob)
router.PUT("/jobs/:token/artifacts/:name", wrapper.UploadJobArtifact)
router.GET("/openapi", wrapper.GetOpenapi)
router.GET("/status", wrapper.GetStatus)
router.GET(baseURL+"/errors/:id", wrapper.GetError)
router.POST(baseURL+"/jobs", wrapper.RequestJob)
router.GET(baseURL+"/jobs/:token", wrapper.GetJob)
router.PATCH(baseURL+"/jobs/:token", wrapper.UpdateJob)
router.PUT(baseURL+"/jobs/:token/artifacts/:name", wrapper.UploadJobArtifact)
router.GET(baseURL+"/openapi", wrapper.GetOpenapi)
router.GET(baseURL+"/status", wrapper.GetStatus)
}
// Base64 encoded, gzipped, json marshaled Swagger object
var swaggerSpec = []string{
"H4sIAAAAAAAC/9xY32/bNhD+VwhuDxsgW07TvgjYQ9MNRTp0GZIVK5AFwZk6W0wkUiFPdgxD//tAUv4l",
"KXaKxg/NkxWJvB/fffzumCUXuii1QkWWJ0tuRYYF+Mc/jNHGPUCeX0x4cr3kPxuc8IT/FG82xc2O+GJ8",
"h4IucYIGlUBeR0teGl2iIYneoNApul9alMgTbslINeV1xAu0Fqb+W4pWGFmS1Ion/AzE/RxMypw/IDmW",
"uaQFm0vK2FybezSW/VeNRqfiNzY7PY0YPlSQW2YQrFY86rpy8YCzfivT3liard1P/ttDJQ2mPLkOyayX",
"twxvUrpZx6A9Pry+qSP+EemTHl+iLbWy+KIYgxKY43ZuY61zBNXNYLW0P8a2r6TtKvOB9kD4BLL3UqWH",
"cfXo+aVR8NCNLuKX+FChDRj6p250YETWG4Z74VdIwsI+uYQnHIyBRSfAsD8KDg4F9/IFBjP1v4+DqR40",
"vu+sVsNLmH9uSFe76EhOQNBtrgWE09STaLpQUEhxuzK6huSA9V2AIr7XSXhxqO7+65alvhT6iXpFQJU9",
"BtbWWz4ce7OuP7wvZQqE+6hq0FY5HYS95bTZ1cfALZcbUL4JCudMqonuSvI/mbRMWgaKvf/7nE20WSsx",
"aWZCjgxUyjJQaY7sTo/t0EmxpNyFeXF1Vsk8ZR9cGBYNG7B/vQEe8RkaG9ycNGKtoJQ84afD0XDEI14C",
"ZR6zGF13svFSprX7e4rUjfUjukiYVJac1jE9YZQh81uZLVHIicSUjRfMq85aws/TsDl0QOfVQIGExnpS",
"7To5/33HLnfA8cRHyiOuoHBJe/ub6pGpMGp6rQsbH6EoPTonp92uVd+4vaGSPvk3o1Hop4pQ+byhLHMZ",
"Tkl81/Svjfl9pQ851r7ib79+PYrdd0exW0fcoqiMpIUvyxmCQcOT6xsHmK2KAsyiYUEo+Xbh3PbYcdOf",
"R2176NMcWMvAkXjIPPXXJGHjXIt7yypFMg9L/LmYgcxhnOOww6hNY2jIgJbOdLp4MWy6bTHA1CLPyVEc",
"NkrjHe7i+MEgEKbuRL8ZvX0x572itev5L+3LMoetukSMzILBFKTiPxrn2/l5Fm+YfrlSX5f1huHxkvQ9",
"qm2d7EjdipRHUpnWwNuTysWf/IdUoB2ZMZVSUk0D/J2+0dMXfGH2toaeXlAChdl2t4rrrn8kdekMMr3i",
"MjqGv1dMm5Alg13utI9uvBqGbbx01PFnuayojwW5hvSTHr9vdvDn8ND/fAsNo5ej8/O4qgUhDSwZhGIX",
"9LbJp0j56ojjCu3m2xU3Am3WQ/PTYn/RLHkOTo05Py4zqZiL3U39BfirxrtjjKLtQ/5F4WOJgjBtBjkt",
"RGUcv7oS7AbxvTE7jDYXu957w5V00zgLq5p7jGHzTIqMGaTKKMssmpkUq0V9t4er1ZejKWTr5vsa5bGB",
"t5n2zWylYZXJecIzotImcQylHLqi20xOaCh04d7EsoApDsbutolmEG6p8eyEt0H6DFKxX0qj00q4V7+y",
"4Mn/R6DryBJM8TvcXRFMndB3nOy10lq29eGm/j8AAP//dP8YvMUVAAA=",
"H4sIAAAAAAAC/9xYX2/bNhD/KgS3hw2QLadpXwTsoemGIh26DMmKFciC4EydLSYSqZAnO4ah7z6QlP9J",
"ip0A8UPzJFk83p/f/Xh39JILXZRaoSLLkyW3IsMC/OsfxmjjXiDPLyY8uV7ynw1OeMJ/ijeb4mZHfDG+",
"Q0GXOEGDSiCvoyUvjS7RkESvUOgU3ZMWJfKEWzJSTXkd8QKthalfS9EKI0uSWvGEn4G4n4NJmbMHJMcy",
"l7Rgc0kZm2tzj8ay/6rR6FT8xmanpxHDhwpyywyC1YpHXVPOH3Dab2Xa60uztbvk1x4qaTDlyXUIZi3e",
"UrwJ6Wbtg/b48PqmjvhnpC96fIm21Mriq2IMSmCO27GNtc4RVDeClWi/j21bSdtU5h3tgfAJZO+lSg/j",
"6tHzolGw0PUu4pf4UKENGPq3rndgRNbrhvvgJSRhYZ8U4QkHY2DRcTDsj4KBQ869foLBTP3zcTDVg8b2",
"ndVqeAnzrw3paucdyQkIus21gHCaegJNFwoKKW5XSteQHNC+C1DE9xoJHw7l3a9uaeoLoZ+oVwRU2WNg",
"bb3mw743cv3ufStTINxHVYO2yukg7C2jza4+Bm6Z3IDyIiicMakmuluS/8mkZdIyUOzj3+dsos26EpNm",
"JsTIQKUsA5XmyO702A5dKZaUOzcvrs4qmafsk3PDomED9q9XwCM+Q2ODmZOmWCsoJU/46XA0HPGIl0CZ",
"xyxG151svJRp7X5Pkbq+fkbnCZPKkqt1TE8YZcj8VmZLFHIiMWXjBfNVZ13Cz9OwOXRAZ9VAgYTGelLt",
"Gjn/fUcvd8DxxHvKI66gcEF7/ZvskakwanqtcxsfoSg9Oien3a5V37i9IZM++HejUeinilD5uKEscxlO",
"SXzX9K+N+n2pDzHWPuPvv38/it4PR9FbR9yiqIykhU/LGYJBw5PrGweYrYoCzKJhQUj5duLc9thx059H",
"bXvo0xxYy8CReMg89dckYeNci3vLKkUyDyL+XMxA5jDOcdhh1KYxNGRAS2c6XbwaNt22GGBqkefkKAab",
"SuMN7uL4ySAQpu5Evxu9fzXjvUVr1/Jf2qdlDlt5iRiZBYMpSMV/NM634/Ms3jD9clV9XdQbhsdL0veo",
"tutkp9StSHmkKtMaeHtCufiT/5AVaKfMmEopqaYB/k7f6OkLPjF7W0NPLyiBwmy7m8V11z9SdekMMr3F",
"ZXQMe2+YNiFKBrvcaR/deDUM23jpqOPPcllRHwtyDekXPf7Y7ODP4aF/vISG0evR+Xlc1YKQBpYMQrEL",
"elvlU6R8c8RxiXbz7YobgTbrofnpYn/RiDwHp0adH5eZVMz57qb+AvxV48MxRtH2If+m8LFEQZg2g5wW",
"ojKOX90S7AbxvT47jDYXu957w5V00zgLUs09xrB5JkXGDFJllGUWzUyKlVDf7eFqtXK0Ctm6+b7F8tjA",
"20z7ZtZ/B/sKUrFfSqPTSrhPv7IgyyNemZwnPCMqbRLHUMqhY4fN5ISGQhfuSywLmOJg7K6laAbhOhvP",
"Tvw/Ai1mEExdkd6j3hJM8YVGgpaXiG0t3NT/BwAA//+IToO0xRUAAA==",
}
// GetSwagger returns the Swagger specification corresponding to the generated code
// in this file.
func GetSwagger() (*openapi3.Swagger, error) {
// GetSwagger returns the content of the embedded swagger specification file
// or error if failed to decode
func decodeSpec() ([]byte, error) {
zipped, err := base64.StdEncoding.DecodeString(strings.Join(swaggerSpec, ""))
if err != nil {
return nil, fmt.Errorf("error base64 decoding spec: %s", err)
@ -295,9 +308,57 @@ func GetSwagger() (*openapi3.Swagger, error) {
return nil, fmt.Errorf("error decompressing spec: %s", err)
}
swagger, err := openapi3.NewSwaggerLoader().LoadSwaggerFromData(buf.Bytes())
if err != nil {
return nil, fmt.Errorf("error loading Swagger: %s", err)
}
return swagger, nil
return buf.Bytes(), nil
}
var rawSpec = decodeSpecCached()
// a naive cached of a decoded swagger spec
func decodeSpecCached() func() ([]byte, error) {
data, err := decodeSpec()
return func() ([]byte, error) {
return data, err
}
}
// Constructs a synthetic filesystem for resolving external references when loading openapi specifications.
func PathToRawSpec(pathToFile string) map[string]func() ([]byte, error) {
var res = make(map[string]func() ([]byte, error))
if len(pathToFile) > 0 {
res[pathToFile] = rawSpec
}
return res
}
// GetSwagger returns the Swagger specification corresponding to the generated code
// in this file. The external references of Swagger specification are resolved.
// The logic of resolving external references is tightly connected to "import-mapping" feature.
// Externally referenced files must be embedded in the corresponding golang packages.
// Urls can be supported but this task was out of the scope.
func GetSwagger() (swagger *openapi3.T, err error) {
var resolvePath = PathToRawSpec("")
loader := openapi3.NewLoader()
loader.IsExternalRefsAllowed = true
loader.ReadFromURIFunc = func(loader *openapi3.Loader, url *url.URL) ([]byte, error) {
var pathToFile = url.String()
pathToFile = path.Clean(pathToFile)
getSpec, ok := resolvePath[pathToFile]
if !ok {
err1 := fmt.Errorf("path not found: %s", pathToFile)
return nil, err1
}
return getSpec()
}
var specData []byte
specData, err = rawSpec()
if err != nil {
return
}
swagger, err = loader.LoadFromData(specData)
if err != nil {
return
}
return
}

View file

@ -20,8 +20,11 @@ import (
"os"
"path"
"path/filepath"
"runtime/debug"
"strings"
"gopkg.in/yaml.v2"
"github.com/deepmap/oapi-codegen/pkg/codegen"
"github.com/deepmap/oapi-codegen/pkg/util"
)
@ -31,45 +34,79 @@ func errExit(format string, args ...interface{}) {
os.Exit(1)
}
var (
flagPackageName string
flagGenerate string
flagOutputFile string
flagIncludeTags string
flagExcludeTags string
flagTemplatesDir string
flagImportMapping string
flagExcludeSchemas string
flagConfigFile string
flagAliasTypes bool
flagPrintVersion bool
)
type configuration struct {
PackageName string `yaml:"package"`
GenerateTargets []string `yaml:"generate"`
OutputFile string `yaml:"output"`
IncludeTags []string `yaml:"include-tags"`
ExcludeTags []string `yaml:"exclude-tags"`
TemplatesDir string `yaml:"templates"`
ImportMapping map[string]string `yaml:"import-mapping"`
ExcludeSchemas []string `yaml:"exclude-schemas"`
}
func main() {
var (
packageName string
generate string
outputFile string
includeTags string
excludeTags string
templatesDir string
importMapping string
excludeSchemas string
)
flag.StringVar(&packageName, "package", "", "The package name for generated code")
flag.StringVar(&generate, "generate", "types,client,server,spec",
flag.StringVar(&flagPackageName, "package", "", "The package name for generated code")
flag.StringVar(&flagGenerate, "generate", "types,client,server,spec",
`Comma-separated list of code to generate; valid options: "types", "client", "chi-server", "server", "spec", "skip-fmt", "skip-prune"`)
flag.StringVar(&outputFile, "o", "", "Where to output generated code, stdout is default")
flag.StringVar(&includeTags, "include-tags", "", "Only include operations with the given tags. Comma-separated list of tags.")
flag.StringVar(&excludeTags, "exclude-tags", "", "Exclude operations that are tagged with the given tags. Comma-separated list of tags.")
flag.StringVar(&templatesDir, "templates", "", "Path to directory containing user templates")
flag.StringVar(&importMapping, "import-mapping", "", "A dict from the external reference to golang package path")
flag.StringVar(&excludeSchemas, "exclude-schemas", "", "A comma separated list of schemas which must be excluded from generation")
flag.StringVar(&flagOutputFile, "o", "", "Where to output generated code, stdout is default")
flag.StringVar(&flagIncludeTags, "include-tags", "", "Only include operations with the given tags. Comma-separated list of tags.")
flag.StringVar(&flagExcludeTags, "exclude-tags", "", "Exclude operations that are tagged with the given tags. Comma-separated list of tags.")
flag.StringVar(&flagTemplatesDir, "templates", "", "Path to directory containing user templates")
flag.StringVar(&flagImportMapping, "import-mapping", "", "A dict from the external reference to golang package path")
flag.StringVar(&flagExcludeSchemas, "exclude-schemas", "", "A comma separated list of schemas which must be excluded from generation")
flag.StringVar(&flagConfigFile, "config", "", "a YAML config file that controls oapi-codegen behavior")
flag.BoolVar(&flagAliasTypes, "alias-types", false, "Alias type declarations of possible")
flag.BoolVar(&flagPrintVersion, "version", false, "when specified, print version and exit")
flag.Parse()
if flagPrintVersion {
bi, ok := debug.ReadBuildInfo()
if !ok {
fmt.Fprintln(os.Stderr, "error reading build info")
os.Exit(1)
}
fmt.Println(bi.Main.Path + "/cmd/oapi-codegen")
fmt.Println(bi.Main.Version)
return
}
if flag.NArg() < 1 {
fmt.Println("Please specify a path to a OpenAPI 3.0 spec file")
os.Exit(1)
}
cfg := configFromFlags()
// If the package name has not been specified, we will use the name of the
// swagger file.
if packageName == "" {
if cfg.PackageName == "" {
path := flag.Arg(0)
baseName := filepath.Base(path)
// Split the base name on '.' to get the first part of the file.
nameParts := strings.Split(baseName, ".")
packageName = codegen.ToCamelCase(nameParts[0])
cfg.PackageName = codegen.ToCamelCase(nameParts[0])
}
opts := codegen.Options{}
for _, g := range splitCSVArg(generate) {
opts := codegen.Options{
AliasTypes: flagAliasTypes,
}
for _, g := range cfg.GenerateTargets {
switch g {
case "client":
opts.GenerateClient = true
@ -92,9 +129,9 @@ func main() {
}
}
opts.IncludeTags = splitCSVArg(includeTags)
opts.ExcludeTags = splitCSVArg(excludeTags)
opts.ExcludeSchemas = splitCSVArg(excludeSchemas)
opts.IncludeTags = cfg.IncludeTags
opts.ExcludeTags = cfg.ExcludeTags
opts.ExcludeSchemas = cfg.ExcludeSchemas
if opts.GenerateEchoServer && opts.GenerateChiServer {
errExit("can not specify both server and chi-server targets simultaneously")
@ -105,26 +142,21 @@ func main() {
errExit("error loading swagger spec\n: %s", err)
}
templates, err := loadTemplateOverrides(templatesDir)
templates, err := loadTemplateOverrides(cfg.TemplatesDir)
if err != nil {
errExit("error loading template overrides: %s\n", err)
}
opts.UserTemplates = templates
if len(importMapping) > 0 {
opts.ImportMapping, err = util.ParseCommandlineMap(importMapping)
if err != nil {
errExit("error parsing import-mapping: %s\n", err)
}
}
opts.ImportMapping = cfg.ImportMapping
code, err := codegen.Generate(swagger, packageName, opts)
code, err := codegen.Generate(swagger, cfg.PackageName, opts)
if err != nil {
errExit("error generating code: %s\n", err)
}
if outputFile != "" {
err = ioutil.WriteFile(outputFile, []byte(code), 0644)
if cfg.OutputFile != "" {
err = ioutil.WriteFile(cfg.OutputFile, []byte(code), 0644)
if err != nil {
errExit("error writing generated code to file: %s", err)
}
@ -133,22 +165,6 @@ func main() {
}
}
func splitCSVArg(input string) []string {
input = strings.TrimSpace(input)
if len(input) == 0 {
return nil
}
splitInput := strings.Split(input, ",")
args := make([]string, 0, len(splitInput))
for _, s := range splitInput {
s = strings.TrimSpace(s)
if len(s) > 0 {
args = append(args, s)
}
}
return args
}
func loadTemplateOverrides(templatesDir string) (map[string]string, error) {
var templates = make(map[string]string)
@ -171,3 +187,53 @@ func loadTemplateOverrides(templatesDir string) (map[string]string, error) {
return templates, nil
}
// configFromFlags parses the flags and the config file. Anything which is
// a zerovalue in the configuration file will be replaced with the flag
// value, this means that the config file overrides flag values.
func configFromFlags() *configuration {
var cfg configuration
// Load the configuration file first.
if flagConfigFile != "" {
f, err := os.Open(flagConfigFile)
if err != nil {
errExit("failed to open config file with error: %v\n", err)
}
defer f.Close()
err = yaml.NewDecoder(f).Decode(&cfg)
if err != nil {
errExit("error parsing config file: %v\n", err)
}
}
if cfg.PackageName == "" {
cfg.PackageName = flagPackageName
}
if cfg.GenerateTargets == nil {
cfg.GenerateTargets = util.ParseCommandLineList(flagGenerate)
}
if cfg.IncludeTags == nil {
cfg.IncludeTags = util.ParseCommandLineList(flagIncludeTags)
}
if cfg.ExcludeTags == nil {
cfg.ExcludeTags = util.ParseCommandLineList(flagExcludeTags)
}
if cfg.TemplatesDir == "" {
cfg.TemplatesDir = flagTemplatesDir
}
if cfg.ImportMapping == nil && flagImportMapping != "" {
var err error
cfg.ImportMapping, err = util.ParseCommandlineMap(flagImportMapping)
if err != nil {
errExit("error parsing import-mapping: %s\n", err)
}
}
if cfg.ExcludeSchemas == nil {
cfg.ExcludeSchemas = util.ParseCommandLineList(flagExcludeSchemas)
}
if cfg.OutputFile == "" {
cfg.OutputFile = flagOutputFile
}
return &cfg
}

View file

@ -18,14 +18,14 @@ import (
"bufio"
"bytes"
"fmt"
"go/format"
"regexp"
"runtime/debug"
"sort"
"strings"
"text/template"
"github.com/getkin/kin-openapi/openapi3"
"github.com/pkg/errors"
"golang.org/x/tools/imports"
"github.com/deepmap/oapi-codegen/pkg/codegen/templates"
)
@ -37,8 +37,9 @@ type Options struct {
GenerateClient bool // GenerateClient specifies whether to generate client boilerplate
GenerateTypes bool // GenerateTypes specifies whether to generate type definitions
EmbedSpec bool // Whether to embed the swagger spec in the generated code
SkipFmt bool // Whether to skip go fmt on the generated code
SkipFmt bool // Whether to skip go imports on the generated code
SkipPrune bool // Whether to skip pruning unused components on the generated code
AliasTypes bool // Whether to alias types if possible
IncludeTags []string // Only include operations that have one of these tags. Ignored when empty.
ExcludeTags []string // Exclude operations that have one of these tags. Ignored when empty.
UserTemplates map[string]string // Override built-in templates from user-provided files
@ -46,54 +47,38 @@ type Options struct {
ExcludeSchemas []string // Exclude from generation schemas with given names. Ignored when empty.
}
// goImport represents a go package to be imported in the generated code
type goImport struct {
lookFor string
alias string
packageName string
Name string // package name
Path string // package path
}
func (i goImport) String() string {
if i.alias != "" {
return fmt.Sprintf("%s %q", i.alias, i.packageName)
// String returns a go import statement
func (gi goImport) String() string {
if gi.Name != "" {
return fmt.Sprintf("%s %q", gi.Name, gi.Path)
}
return fmt.Sprintf("%q", i.packageName)
return fmt.Sprintf("%q", gi.Path)
}
type goImports []goImport
// importMap maps external OpenAPI specifications files/urls to external go packages
type importMap map[string]goImport
var (
allGoImports = goImports{
{lookFor: "base64\\.", packageName: "encoding/base64"},
{lookFor: "bytes\\.", packageName: "bytes"},
{lookFor: "chi\\.", packageName: "github.com/go-chi/chi"},
{lookFor: "context\\.", packageName: "context"},
{lookFor: "echo\\.", packageName: "github.com/labstack/echo/v4"},
{lookFor: "errors\\.", packageName: "github.com/pkg/errors"},
{lookFor: "fmt\\.", packageName: "fmt"},
{lookFor: "gzip\\.", packageName: "compress/gzip"},
{lookFor: "http\\.", packageName: "net/http"},
{lookFor: "io\\.", packageName: "io"},
{lookFor: "ioutil\\.", packageName: "io/ioutil"},
{lookFor: "json\\.", packageName: "encoding/json"},
{lookFor: "openapi3\\.", packageName: "github.com/getkin/kin-openapi/openapi3"},
{lookFor: "openapi_types\\.", alias: "openapi_types", packageName: "github.com/deepmap/oapi-codegen/pkg/types"},
{lookFor: "path\\.", packageName: "path"},
{lookFor: "runtime\\.", packageName: "github.com/deepmap/oapi-codegen/pkg/runtime"},
{lookFor: "strings\\.", packageName: "strings"},
{lookFor: "time\\.Duration", packageName: "time"},
{lookFor: "time\\.Time", packageName: "time"},
{lookFor: "url\\.", packageName: "net/url"},
{lookFor: "xml\\.", packageName: "encoding/xml"},
{lookFor: "yaml\\.", packageName: "gopkg.in/yaml.v2"},
// GoImports returns a slice of go import statements
func (im importMap) GoImports() []string {
goImports := make([]string, 0, len(im))
for _, v := range im {
goImports = append(goImports, v.String())
}
return goImports
}
importMapping = map[string]goImport{}
)
var importMapping importMap
func constructImportMapping(input map[string]string) map[string]goImport {
func constructImportMapping(input map[string]string) importMap {
var (
nameToAlias = map[string]string{}
result = map[string]goImport{}
pathToName = map[string]string{}
result = importMap{}
)
{
@ -103,14 +88,14 @@ func constructImportMapping(input map[string]string) map[string]goImport {
}
sort.Strings(packagePaths)
for _, packageName := range packagePaths {
if _, ok := nameToAlias[packageName]; !ok {
nameToAlias[packageName] = fmt.Sprintf("externalRef%d", len(nameToAlias))
for _, packagePath := range packagePaths {
if _, ok := pathToName[packagePath]; !ok {
pathToName[packagePath] = fmt.Sprintf("externalRef%d", len(pathToName))
}
}
}
for urlOrPath, packageName := range input {
result[urlOrPath] = goImport{alias: nameToAlias[packageName], packageName: packageName}
for specPath, packagePath := range input {
result[specPath] = goImport{Name: pathToName[packagePath], Path: packagePath}
}
return result
}
@ -118,7 +103,7 @@ func constructImportMapping(input map[string]string) map[string]goImport {
// Uses the Go templating engine to generate all of our server wrappers from
// the descriptions we've built up above from the schema objects.
// opts defines
func Generate(swagger *openapi3.Swagger, packageName string, opts Options) (string, error) {
func Generate(swagger *openapi3.T, packageName string, opts Options) (string, error) {
importMapping = constructImportMapping(opts.ImportMapping)
filterOperationsByTag(swagger, opts)
@ -127,6 +112,7 @@ func Generate(swagger *openapi3.Swagger, packageName string, opts Options) (stri
}
// This creates the golang templates text package
TemplateFunctions["opts"] = func() Options { return opts }
t := template.New("oapi-codegen").Funcs(TemplateFunctions)
// This parses all of our own template files into the template object
// above
@ -150,12 +136,18 @@ func Generate(swagger *openapi3.Swagger, packageName string, opts Options) (stri
return "", errors.Wrap(err, "error creating operation definitions")
}
var typeDefinitions string
var typeDefinitions, constantDefinitions string
if opts.GenerateTypes {
typeDefinitions, err = GenerateTypeDefinitions(t, swagger, ops, opts.ExcludeSchemas)
if err != nil {
return "", errors.Wrap(err, "error generating type definitions")
}
constantDefinitions, err = GenerateConstants(t, ops)
if err != nil {
return "", errors.Wrap(err, "error generating constants")
}
}
var echoServerOut string
@ -192,49 +184,17 @@ func Generate(swagger *openapi3.Swagger, packageName string, opts Options) (stri
var inlinedSpec string
if opts.EmbedSpec {
inlinedSpec, err = GenerateInlinedSpec(t, swagger)
inlinedSpec, err = GenerateInlinedSpec(t, importMapping, swagger)
if err != nil {
return "", errors.Wrap(err, "error generating Go handlers for Paths")
}
}
// Imports needed for the generated code to compile
var imports []string
for _, importGo := range importMapping {
imports = append(imports, importGo.String())
}
var buf bytes.Buffer
w := bufio.NewWriter(&buf)
// Based on module prefixes, figure out which optional imports are required.
pkgs := make(map[string]int)
for _, str := range []string{typeDefinitions, chiServerOut, echoServerOut, clientOut, clientWithResponsesOut, inlinedSpec} {
for _, line := range strings.Split(strings.TrimSpace(str), "\n") {
line = strings.TrimSpace(line)
if line == "" || strings.HasPrefix(line, "//") {
continue
}
for _, goImport := range allGoImports {
match, err := regexp.MatchString(fmt.Sprintf("[^a-zA-Z0-9_]%s", goImport.lookFor), line)
if err != nil {
return "", errors.Wrap(err, "error figuring out imports")
}
if match {
pkgs[goImport.String()]++
}
}
}
}
for k := range pkgs {
imports = append(imports, k)
}
importsOut, err := GenerateImports(t, imports, packageName)
externalImports := importMapping.GoImports()
importsOut, err := GenerateImports(t, externalImports, packageName)
if err != nil {
return "", errors.Wrap(err, "error generating imports")
}
@ -244,6 +204,11 @@ func Generate(swagger *openapi3.Swagger, packageName string, opts Options) (stri
return "", errors.Wrap(err, "error writing imports")
}
_, err = w.WriteString(constantDefinitions)
if err != nil {
return "", errors.Wrap(err, "error writing constants")
}
_, err = w.WriteString(typeDefinitions)
if err != nil {
return "", errors.Wrap(err, "error writing type definitions")
@ -290,12 +255,13 @@ func Generate(swagger *openapi3.Swagger, packageName string, opts Options) (stri
// remove any byte-order-marks which break Go-Code
goCode := SanitizeCode(buf.String())
// The generation code produces unindented horrors. Use the Go formatter
// The generation code produces unindented horrors. Use the Go Imports
// to make it all pretty.
if opts.SkipFmt {
return goCode, nil
}
outBytes, err := format.Source([]byte(goCode))
outBytes, err := imports.Process(packageName+".go", []byte(goCode), nil)
if err != nil {
fmt.Println(goCode)
return "", errors.Wrap(err, "error formatting Go code")
@ -303,7 +269,7 @@ func Generate(swagger *openapi3.Swagger, packageName string, opts Options) (stri
return string(outBytes), nil
}
func GenerateTypeDefinitions(t *template.Template, swagger *openapi3.Swagger, ops []OperationDefinition, excludeSchemas []string) (string, error) {
func GenerateTypeDefinitions(t *template.Template, swagger *openapi3.T, ops []OperationDefinition, excludeSchemas []string) (string, error) {
schemaTypes, err := GenerateTypesForSchemas(t, swagger.Components.Schemas, excludeSchemas)
if err != nil {
return "", errors.Wrap(err, "error generating Go types for component schemas")
@ -332,6 +298,11 @@ func GenerateTypeDefinitions(t *template.Template, swagger *openapi3.Swagger, op
return "", errors.Wrap(err, "error generating Go types for operation parameters")
}
enumsOut, err := GenerateEnums(t, allTypes)
if err != nil {
return "", errors.Wrap(err, "error generating code for type enums")
}
typesOut, err := GenerateTypes(t, allTypes)
if err != nil {
return "", errors.Wrap(err, "error generating code for type definitions")
@ -342,10 +313,50 @@ func GenerateTypeDefinitions(t *template.Template, swagger *openapi3.Swagger, op
return "", errors.Wrap(err, "error generating allOf boilerplate")
}
typeDefinitions := strings.Join([]string{typesOut, paramTypesOut, allOfBoilerplate}, "")
typeDefinitions := strings.Join([]string{enumsOut, typesOut, paramTypesOut, allOfBoilerplate}, "")
return typeDefinitions, nil
}
// Generates operation ids, context keys, paths, etc. to be exported as constants
func GenerateConstants(t *template.Template, ops []OperationDefinition) (string, error) {
var buf bytes.Buffer
w := bufio.NewWriter(&buf)
constants := Constants{
SecuritySchemeProviderNames: []string{},
}
providerNameMap := map[string]struct{}{}
for _, op := range ops {
for _, def := range op.SecurityDefinitions {
providerName := SanitizeGoIdentity(def.ProviderName)
providerNameMap[providerName] = struct{}{}
}
}
var providerNames []string
for providerName := range providerNameMap {
providerNames = append(providerNames, providerName)
}
sort.Strings(providerNames)
for _, providerName := range providerNames {
constants.SecuritySchemeProviderNames = append(constants.SecuritySchemeProviderNames, providerName)
}
err := t.ExecuteTemplate(w, "constants.tmpl", constants)
if err != nil {
return "", fmt.Errorf("error generating server interface: %s", err)
}
err = w.Flush()
if err != nil {
return "", fmt.Errorf("error flushing output buffer for server interface: %s", err)
}
return buf.String(), nil
}
// Generates type definitions for any custom types defined in the
// components/schemas section of the Swagger spec.
func GenerateTypesForSchemas(t *template.Template, schemas map[string]*openapi3.SchemaRef, excludeSchemas []string) ([]TypeDefinition, error) {
@ -509,18 +520,64 @@ func GenerateTypes(t *template.Template, types []TypeDefinition) (string, error)
return buf.String(), nil
}
// Generate our import statements and package definition.
func GenerateImports(t *template.Template, imports []string, packageName string) (string, error) {
sort.Strings(imports)
func GenerateEnums(t *template.Template, types []TypeDefinition) (string, error) {
var buf bytes.Buffer
w := bufio.NewWriter(&buf)
c := Constants{
EnumDefinitions: []EnumDefinition{},
}
for _, tp := range types {
if len(tp.Schema.EnumValues) > 0 {
wrapper := ""
if tp.Schema.GoType == "string" {
wrapper = `"`
}
c.EnumDefinitions = append(c.EnumDefinitions, EnumDefinition{
Schema: tp.Schema,
TypeName: tp.TypeName,
ValueWrapper: wrapper,
})
}
}
err := t.ExecuteTemplate(w, "constants.tmpl", c)
if err != nil {
return "", errors.Wrap(err, "error generating enums")
}
err = w.Flush()
if err != nil {
return "", errors.Wrap(err, "error flushing output buffer for enums")
}
return buf.String(), nil
}
// Generate our import statements and package definition.
func GenerateImports(t *template.Template, externalImports []string, packageName string) (string, error) {
var buf bytes.Buffer
w := bufio.NewWriter(&buf)
// Read build version for incorporating into generated files
var modulePath string
var moduleVersion string
if bi, ok := debug.ReadBuildInfo(); ok {
modulePath = bi.Main.Path
moduleVersion = bi.Main.Version
} else {
// Unit tests have ok=false, so we'll just use "unknown" for the
// version if we can't read this.
modulePath = "unknown module path"
moduleVersion = "unknown version"
}
context := struct {
Imports []string
PackageName string
ExternalImports []string
PackageName string
ModuleName string
Version string
}{
Imports: imports,
PackageName: packageName,
ExternalImports: externalImports,
PackageName: packageName,
ModuleName: modulePath,
Version: moduleVersion,
}
err := t.ExecuteTemplate(w, "imports.tmpl", context)
if err != nil {

View file

@ -8,7 +8,9 @@ import (
)
const (
extPropGoType = "x-go-type"
extPropGoType = "x-go-type"
extPropOmitEmpty = "x-omitempty"
extPropExtraTags = "x-oapi-codegen-extra-tags"
)
func extTypeName(extPropValue interface{}) (string, error) {
@ -23,3 +25,29 @@ func extTypeName(extPropValue interface{}) (string, error) {
return name, nil
}
func extParseOmitEmpty(extPropValue interface{}) (bool, error) {
raw, ok := extPropValue.(json.RawMessage)
if !ok {
return false, fmt.Errorf("failed to convert type: %T", extPropValue)
}
var omitEmpty bool
if err := json.Unmarshal(raw, &omitEmpty); err != nil {
return false, errors.Wrap(err, "failed to unmarshal json")
}
return omitEmpty, nil
}
func extExtraTags(extPropValue interface{}) (map[string]string, error) {
raw, ok := extPropValue.(json.RawMessage)
if !ok {
return nil, fmt.Errorf("failed to convert type: %T", extPropValue)
}
var tags map[string]string
if err := json.Unmarshal(raw, &tags); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal json")
}
return tags, nil
}

View file

@ -2,7 +2,7 @@ package codegen
import "github.com/getkin/kin-openapi/openapi3"
func filterOperationsByTag(swagger *openapi3.Swagger, opts Options) {
func filterOperationsByTag(swagger *openapi3.T, opts Options) {
if len(opts.ExcludeTags) > 0 {
excludeOperationsWithTags(swagger.Paths, opts.ExcludeTags)
}

View file

@ -26,7 +26,7 @@ import (
// This generates a gzipped, base64 encoded JSON representation of the
// swagger definition, which we embed inside the generated code.
func GenerateInlinedSpec(t *template.Template, swagger *openapi3.Swagger) (string, error) {
func GenerateInlinedSpec(t *template.Template, importMapping importMap, swagger *openapi3.T) (string, error) {
// Marshal to json
encoded, err := swagger.MarshalJSON()
if err != nil {
@ -65,7 +65,10 @@ func GenerateInlinedSpec(t *template.Template, swagger *openapi3.Swagger) (strin
// Generate inline code.
buf.Reset()
w := bufio.NewWriter(&buf)
err = t.ExecuteTemplate(w, "inline.tmpl", parts)
err = t.ExecuteTemplate(w, "inline.tmpl", struct {
SpecParts []string
ImportMapping importMap
}{SpecParts: parts, ImportMapping: importMapping})
if err != nil {
return "", fmt.Errorf("error generating inlined spec: %s", err)
}

View file

@ -120,7 +120,7 @@ func (pd ParameterDefinition) GoVariableName() string {
}
func (pd ParameterDefinition) GoName() string {
return ToCamelCase(pd.ParamName)
return SchemaNameToTypeName(pd.ParamName)
}
func (pd ParameterDefinition) IndirectOptional() bool {
@ -163,7 +163,7 @@ func DescribeParameters(params openapi3.Parameters, path []string) ([]ParameterD
// If this is a reference to a predefined type, simply use the reference
// name as the type. $ref: "#/components/schemas/custom_type" becomes
// "CustomType".
if paramOrRef.Ref != "" {
if IsGoTypeReference(paramOrRef.Ref) {
goType, err := RefPathToGoType(paramOrRef.Ref)
if err != nil {
return nil, fmt.Errorf("error dereferencing (%s) for param (%s): %s",
@ -185,7 +185,8 @@ func DescribeSecurityDefinition(securityRequirements openapi3.SecurityRequiremen
outDefs := make([]SecurityDefinition, 0)
for _, sr := range securityRequirements {
for k, v := range sr {
for _, k := range SortedSecurityRequirementKeys(sr) {
v := sr[k]
outDefs = append(outDefs, SecurityDefinition{ProviderName: k, Scopes: v})
}
}
@ -258,8 +259,8 @@ func (o *OperationDefinition) SummaryAsComment() string {
// types which we know how to parse. These will be turned into fields on a
// response object for automatic deserialization of responses in the generated
// Client code. See "client-with-responses.tmpl".
func (o *OperationDefinition) GetResponseTypeDefinitions() ([]TypeDefinition, error) {
var tds []TypeDefinition
func (o *OperationDefinition) GetResponseTypeDefinitions() ([]ResponseTypeDefinition, error) {
var tds []ResponseTypeDefinition
responses := o.Spec.Responses
sortedResponsesKeys := SortedResponsesKeys(responses)
@ -292,12 +293,15 @@ func (o *OperationDefinition) GetResponseTypeDefinitions() ([]TypeDefinition, er
continue
}
td := TypeDefinition{
TypeName: typeName,
Schema: responseSchema,
ResponseName: responseName,
td := ResponseTypeDefinition{
TypeDefinition: TypeDefinition{
TypeName: typeName,
Schema: responseSchema,
},
ResponseName: responseName,
ContentTypeName: contentTypeName,
}
if contentType.Schema.Ref != "" {
if IsGoTypeReference(contentType.Schema.Ref) {
refType, err := RefPathToGoType(contentType.Schema.Ref)
if err != nil {
return nil, errors.Wrap(err, "error dereferencing response Ref")
@ -333,8 +337,11 @@ type RequestBodyDefinition struct {
}
// Returns the Go type definition for a request body
func (r RequestBodyDefinition) TypeDef() string {
return r.Schema.TypeDecl()
func (r RequestBodyDefinition) TypeDef(opID string) *TypeDefinition {
return &TypeDefinition{
TypeName: fmt.Sprintf("%s%sRequestBody", opID, r.NameTag),
Schema: r.Schema,
}
}
// Returns whether the body is a custom inline type, or pre-defined. This is
@ -368,7 +375,7 @@ func FilterParameterDefinitionByType(params []ParameterDefinition, in string) []
}
// OperationDefinitions returns all operations for a swagger definition.
func OperationDefinitions(swagger *openapi3.Swagger) ([]OperationDefinition, error) {
func OperationDefinitions(swagger *openapi3.T) ([]OperationDefinition, error) {
var operations []OperationDefinition
for _, requestPath := range SortedPathsKeys(swagger.Paths) {
@ -385,6 +392,9 @@ func OperationDefinitions(swagger *openapi3.Swagger) ([]OperationDefinition, err
pathOps := pathItem.Operations()
for _, opName := range SortedOperationsKeys(pathOps) {
op := pathOps[opName]
if pathItem.Servers != nil {
op.Servers = &pathItem.Servers
}
// We rely on OperationID to generate function names, it's required
if op.OperationID == "" {
op.OperationID, err = generateDefaultOperationID(opName, requestPath)
@ -514,7 +524,7 @@ func GenerateBodyDefinitions(operationID string, bodyOrRef *openapi3.RequestBody
}
// If the body is a pre-defined type
if bodyOrRef.Ref != "" {
if IsGoTypeReference(bodyOrRef.Ref) {
// Convert the reference path to Go type
refType, err := RefPathToGoType(bodyOrRef.Ref)
if err != nil {
@ -589,14 +599,16 @@ func GenerateParamsTypes(op OperationDefinition) []TypeDefinition {
})
}
prop := Property{
Description: param.Spec.Description,
JsonFieldName: param.ParamName,
Required: param.Required,
Schema: pSchema,
Description: param.Spec.Description,
JsonFieldName: param.ParamName,
Required: param.Required,
Schema: pSchema,
ExtensionProps: &param.Spec.ExtensionProps,
}
s.Properties = append(s.Properties, prop)
}
s.Description = op.Spec.Description
s.GoType = GenStructFromSchema(s)
td := TypeDefinition{

View file

@ -21,7 +21,7 @@ type RefWrapper struct {
SourceRef interface{}
}
func walkSwagger(swagger *openapi3.Swagger, doFn func(RefWrapper) (bool, error)) error {
func walkSwagger(swagger *openapi3.T, doFn func(RefWrapper) (bool, error)) error {
if swagger == nil {
return nil
}
@ -377,7 +377,7 @@ func walkExampleRef(ref *openapi3.ExampleRef, doFn func(RefWrapper) (bool, error
return nil
}
func findComponentRefs(swagger *openapi3.Swagger) []string {
func findComponentRefs(swagger *openapi3.T) []string {
refs := []string{}
walkSwagger(swagger, func(ref RefWrapper) (bool, error) {
@ -391,7 +391,7 @@ func findComponentRefs(swagger *openapi3.Swagger) []string {
return refs
}
func removeOrphanedComponents(swagger *openapi3.Swagger, refs []string) int {
func removeOrphanedComponents(swagger *openapi3.T, refs []string) int {
countRemoved := 0
for key, _ := range swagger.Components.Schemas {
@ -472,7 +472,7 @@ func removeOrphanedComponents(swagger *openapi3.Swagger, refs []string) int {
return countRemoved
}
func pruneUnusedComponents(swagger *openapi3.Swagger) {
func pruneUnusedComponents(swagger *openapi3.T) {
for {
refs := findComponentRefs(swagger)
countRemoved := removeOrphanedComponents(swagger, refs)

View file

@ -13,6 +13,8 @@ type Schema struct {
GoType string // The Go type needed to represent the schema
RefType string // If the type has a type name, this is set
ArrayType *Schema // The schema of array element
EnumValues map[string]string // Enum values
Properties []Property // For an object, the fields with names
@ -21,6 +23,11 @@ type Schema struct {
AdditionalTypes []TypeDefinition // We may need to generate auxiliary helper types, stored here
SkipOptionalPointer bool // Some types don't need a * in front when they're optional
Description string // The description of the element
// The original OpenAPIv3 Schema.
OAPISchema *openapi3.Schema
}
func (s Schema) IsRef() bool {
@ -55,11 +62,12 @@ func (s Schema) GetAdditionalTypeDefs() []TypeDefinition {
}
type Property struct {
Description string
JsonFieldName string
Schema Schema
Required bool
Nullable bool
Description string
JsonFieldName string
Schema Schema
Required bool
Nullable bool
ExtensionProps *openapi3.ExtensionProps
}
func (p Property) GoFieldName() string {
@ -74,11 +82,56 @@ func (p Property) GoTypeDef() string {
return typeDef
}
type TypeDefinition struct {
TypeName string
JsonName string
ResponseName string
// EnumDefinition holds type information for enum
type EnumDefinition struct {
Schema Schema
TypeName string
ValueWrapper string
}
type Constants struct {
// SecuritySchemeProviderNames holds all provider names for security schemes.
SecuritySchemeProviderNames []string
// EnumDefinitions holds type and value information for all enums
EnumDefinitions []EnumDefinition
}
// TypeDefinition describes a Go type definition in generated code.
//
// Let's use this example schema:
// components:
// schemas:
// Person:
// type: object
// properties:
// name:
// type: string
type TypeDefinition struct {
// The name of the type, eg, type <...> Person
TypeName string
// The name of the corresponding JSON description, as it will sometimes
// differ due to invalid characters.
JsonName string
// This is the Schema wrapper is used to populate the type description
Schema Schema
}
// ResponseTypeDefinition is an extension of TypeDefinition, specifically for
// response unmarshaling in ClientWithResponses.
type ResponseTypeDefinition struct {
TypeDefinition
// The content type name where this is used, eg, application/json
ContentTypeName string
// The type name of a response model.
ResponseName string
}
func (t *TypeDefinition) CanAlias() bool {
return t.Schema.IsRef() || /* actual reference */
(t.Schema.ArrayType != nil && t.Schema.ArrayType.IsRef()) /* array to ref */
}
func PropertiesEqual(a, b Property) bool {
@ -86,39 +139,44 @@ func PropertiesEqual(a, b Property) bool {
}
func GenerateGoSchema(sref *openapi3.SchemaRef, path []string) (Schema, error) {
// If Ref is set on the SchemaRef, it means that this type is actually a reference to
// another type. We're not de-referencing, so simply use the referenced type.
var refType string
// Add a fallback value in case the sref is nil.
// i.e. the parent schema defines a type:array, but the array has
// no items defined. Therefore we have at least valid Go-Code.
if sref == nil {
return Schema{GoType: "interface{}", RefType: refType}, nil
return Schema{GoType: "interface{}"}, nil
}
schema := sref.Value
if sref.Ref != "" {
var err error
// If Ref is set on the SchemaRef, it means that this type is actually a reference to
// another type. We're not de-referencing, so simply use the referenced type.
if IsGoTypeReference(sref.Ref) {
// Convert the reference path to Go type
refType, err = RefPathToGoType(sref.Ref)
refType, err := RefPathToGoType(sref.Ref)
if err != nil {
return Schema{}, fmt.Errorf("error turning reference (%s) into a Go type: %s",
sref.Ref, err)
}
return Schema{
GoType: refType,
GoType: refType,
Description: StringToGoComment(schema.Description),
}, nil
}
outSchema := Schema{
Description: StringToGoComment(schema.Description),
OAPISchema: schema,
}
// We can't support this in any meaningful way
if schema.AnyOf != nil {
return Schema{GoType: "interface{}", RefType: refType}, nil
outSchema.GoType = "interface{}"
return outSchema, nil
}
// We can't support this in any meaningful way
if schema.OneOf != nil {
return Schema{GoType: "interface{}", RefType: refType}, nil
outSchema.GoType = "interface{}"
return outSchema, nil
}
// AllOf is interesting, and useful. It's the union of a number of other
@ -130,14 +188,10 @@ func GenerateGoSchema(sref *openapi3.SchemaRef, path []string) (Schema, error) {
if err != nil {
return Schema{}, errors.Wrap(err, "error merging schemas")
}
mergedSchema.RefType = refType
mergedSchema.OAPISchema = schema
return mergedSchema, nil
}
outSchema := Schema{
RefType: refType,
}
// Check for custom Go type extension
if extension, ok := schema.Extensions[extPropGoType]; ok {
typeName, err := extTypeName(extension)
@ -200,11 +254,12 @@ func GenerateGoSchema(sref *openapi3.SchemaRef, path []string) (Schema, error) {
description = p.Value.Description
}
prop := Property{
JsonFieldName: pName,
Schema: pSchema,
Required: required,
Description: description,
Nullable: p.Value.Nullable,
JsonFieldName: pName,
Schema: pSchema,
Required: required,
Description: description,
Nullable: p.Value.Nullable,
ExtensionProps: &p.Value.ExtensionProps,
}
outSchema.Properties = append(outSchema.Properties, prop)
}
@ -224,76 +279,133 @@ func GenerateGoSchema(sref *openapi3.SchemaRef, path []string) (Schema, error) {
outSchema.GoType = GenStructFromSchema(outSchema)
}
return outSchema, nil
} else if len(schema.Enum) > 0 {
err := resolveType(schema, path, &outSchema)
if err != nil {
return Schema{}, errors.Wrap(err, "error resolving primitive type")
}
enumValues := make([]string, len(schema.Enum))
for i, enumValue := range schema.Enum {
enumValues[i] = fmt.Sprintf("%v", enumValue)
}
sanitizedValues := SanitizeEnumNames(enumValues)
outSchema.EnumValues = make(map[string]string, len(sanitizedValues))
var constNamePath []string
for k, v := range sanitizedValues {
if v == "" {
constNamePath = append(path, "Empty")
} else {
constNamePath = append(path, k)
}
outSchema.EnumValues[SchemaNameToTypeName(PathToTypeName(constNamePath))] = v
}
if len(path) > 1 { // handle additional type only on non-toplevel types
typeName := SchemaNameToTypeName(PathToTypeName(path))
typeDef := TypeDefinition{
TypeName: typeName,
JsonName: strings.Join(path, "."),
Schema: outSchema,
}
outSchema.AdditionalTypes = append(outSchema.AdditionalTypes, typeDef)
outSchema.RefType = typeName
}
//outSchema.RefType = typeName
} else {
f := schema.Format
switch t {
case "array":
// For arrays, we'll get the type of the Items and throw a
// [] in front of it.
arrayType, err := GenerateGoSchema(schema.Items, path)
if err != nil {
return Schema{}, errors.Wrap(err, "error generating type for array")
}
outSchema.GoType = "[]" + arrayType.TypeDecl()
outSchema.Properties = arrayType.Properties
case "integer":
// We default to int if format doesn't ask for something else.
if f == "int64" {
outSchema.GoType = "int64"
} else if f == "int32" {
outSchema.GoType = "int32"
} else if f == "" {
outSchema.GoType = "int"
} else {
return Schema{}, fmt.Errorf("invalid integer format: %s", f)
}
case "number":
// We default to float for "number"
if f == "double" {
outSchema.GoType = "float64"
} else if f == "float" || f == "" {
outSchema.GoType = "float32"
} else {
return Schema{}, fmt.Errorf("invalid number format: %s", f)
}
case "boolean":
if f != "" {
return Schema{}, fmt.Errorf("invalid format (%s) for boolean", f)
}
outSchema.GoType = "bool"
case "string":
enumValues := make([]string, len(schema.Enum))
for i, enumValue := range schema.Enum {
enumValues[i] = enumValue.(string)
}
outSchema.EnumValues = SanitizeEnumNames(enumValues)
// Special case string formats here.
switch f {
case "byte":
outSchema.GoType = "[]byte"
case "email":
outSchema.GoType = "openapi_types.Email"
case "date":
outSchema.GoType = "openapi_types.Date"
case "date-time":
outSchema.GoType = "time.Time"
case "json":
outSchema.GoType = "json.RawMessage"
outSchema.SkipOptionalPointer = true
default:
// All unrecognized formats are simply a regular string.
outSchema.GoType = "string"
}
default:
return Schema{}, fmt.Errorf("unhandled Schema type: %s", t)
err := resolveType(schema, path, &outSchema)
if err != nil {
return Schema{}, errors.Wrap(err, "error resolving primitive type")
}
}
return outSchema, nil
}
// resolveType resolves primitive type or array for schema
func resolveType(schema *openapi3.Schema, path []string, outSchema *Schema) error {
f := schema.Format
t := schema.Type
switch t {
case "array":
// For arrays, we'll get the type of the Items and throw a
// [] in front of it.
arrayType, err := GenerateGoSchema(schema.Items, path)
if err != nil {
return errors.Wrap(err, "error generating type for array")
}
outSchema.ArrayType = &arrayType
outSchema.GoType = "[]" + arrayType.TypeDecl()
additionalTypes := arrayType.GetAdditionalTypeDefs()
// Check also types defined in array item
if len(additionalTypes) > 0 {
outSchema.AdditionalTypes = append(outSchema.AdditionalTypes, additionalTypes...)
}
outSchema.Properties = arrayType.Properties
case "integer":
// We default to int if format doesn't ask for something else.
if f == "int64" {
outSchema.GoType = "int64"
} else if f == "int32" {
outSchema.GoType = "int32"
} else if f == "int16" {
outSchema.GoType = "int16"
} else if f == "int8" {
outSchema.GoType = "int8"
} else if f == "int" {
outSchema.GoType = "int"
} else if f == "uint64" {
outSchema.GoType = "uint64"
} else if f == "uint32" {
outSchema.GoType = "uint32"
} else if f == "uint16" {
outSchema.GoType = "uint16"
} else if f == "uint8" {
outSchema.GoType = "uint8"
} else if f == "uint" {
outSchema.GoType = "uint"
} else if f == "" {
outSchema.GoType = "int"
} else {
return fmt.Errorf("invalid integer format: %s", f)
}
case "number":
// We default to float for "number"
if f == "double" {
outSchema.GoType = "float64"
} else if f == "float" || f == "" {
outSchema.GoType = "float32"
} else {
return fmt.Errorf("invalid number format: %s", f)
}
case "boolean":
if f != "" {
return fmt.Errorf("invalid format (%s) for boolean", f)
}
outSchema.GoType = "bool"
case "string":
// Special case string formats here.
switch f {
case "byte":
outSchema.GoType = "[]byte"
case "email":
outSchema.GoType = "openapi_types.Email"
case "date":
outSchema.GoType = "openapi_types.Date"
case "date-time":
outSchema.GoType = "time.Time"
case "json":
outSchema.GoType = "json.RawMessage"
outSchema.SkipOptionalPointer = true
default:
// All unrecognized formats are simply a regular string.
outSchema.GoType = "string"
}
default:
return fmt.Errorf("unhandled Schema type: %s", t)
}
return nil
}
// This describes a Schema, a type definition.
type SchemaDescriptor struct {
Fields []FieldDescriptor
@ -313,20 +425,49 @@ type FieldDescriptor struct {
// JSON annotations
func GenFieldsFromProperties(props []Property) []string {
var fields []string
for _, p := range props {
for i, p := range props {
field := ""
// Add a comment to a field in case we have one, otherwise skip.
if p.Description != "" {
// Separate the comment from a previous-defined, unrelated field.
// Make sure the actual field is separated by a newline.
field += fmt.Sprintf("\n%s\n", StringToGoComment(p.Description))
if i != 0 {
field += "\n"
}
field += fmt.Sprintf("%s\n", StringToGoComment(p.Description))
}
field += fmt.Sprintf(" %s %s", p.GoFieldName(), p.GoTypeDef())
if p.Required || p.Nullable {
field += fmt.Sprintf(" `json:\"%s\"`", p.JsonFieldName)
} else {
field += fmt.Sprintf(" `json:\"%s,omitempty\"`", p.JsonFieldName)
// Support x-omitempty
omitEmpty := true
if _, ok := p.ExtensionProps.Extensions[extPropOmitEmpty]; ok {
if extOmitEmpty, err := extParseOmitEmpty(p.ExtensionProps.Extensions[extPropOmitEmpty]); err == nil {
omitEmpty = extOmitEmpty
}
}
fieldTags := make(map[string]string)
if p.Required || p.Nullable || !omitEmpty {
fieldTags["json"] = p.JsonFieldName
} else {
fieldTags["json"] = p.JsonFieldName + ",omitempty"
}
if extension, ok := p.ExtensionProps.Extensions[extPropExtraTags]; ok {
if tags, err := extExtraTags(extension); err == nil {
keys := SortedStringKeys(tags)
for _, k := range keys {
fieldTags[k] = tags[k]
}
}
}
// Convert the fieldTags map into Go field annotations.
keys := SortedStringKeys(fieldTags)
tags := make([]string, len(keys))
for i, k := range keys {
tags[i] = fmt.Sprintf(`%s:"%s"`, k, fieldTags[k])
}
field += "`" + strings.Join(tags, " ") + "`"
fields = append(fields, field)
}
return fields
@ -359,7 +500,7 @@ func MergeSchemas(allOf []*openapi3.SchemaRef, path []string) (Schema, error) {
var refType string
var err error
if ref != "" {
if IsGoTypeReference(ref) {
refType, err = RefPathToGoType(ref)
if err != nil {
return Schema{}, errors.Wrap(err, "error converting reference path to a go type")
@ -412,7 +553,7 @@ func GenStructFromAllOf(allOf []*openapi3.SchemaRef, path []string) (string, err
objectParts := []string{"struct {"}
for _, schemaOrRef := range allOf {
ref := schemaOrRef.Ref
if ref != "" {
if IsGoTypeReference(ref) {
// We have a referenced type, we will generate an inlined struct
// member.
// struct {
@ -426,7 +567,7 @@ func GenStructFromAllOf(allOf []*openapi3.SchemaRef, path []string) (string, err
objectParts = append(objectParts,
fmt.Sprintf(" // Embedded struct due to allOf(%s)", ref))
objectParts = append(objectParts,
fmt.Sprintf(" %s", goType))
fmt.Sprintf(" %s `yaml:\",inline\"`", goType))
} else {
// Inline all the fields from the schema into the output struct,
// just like in the simple case of generating an object.
@ -471,7 +612,8 @@ func paramToGoType(param *openapi3.Parameter, path []string) (Schema, error) {
// so we'll return the parameter as a string, not bothering to decode it.
if len(param.Content) > 1 {
return Schema{
GoType: "string",
GoType: "string",
Description: StringToGoComment(param.Description),
}, nil
}
@ -480,7 +622,8 @@ func paramToGoType(param *openapi3.Parameter, path []string) (Schema, error) {
if !found {
// If we don't have json, it's a string
return Schema{
GoType: "string",
GoType: "string",
Description: StringToGoComment(param.Description),
}, nil
}

View file

@ -80,10 +80,6 @@ func genParamNames(params []ParameterDefinition) string {
return ", " + strings.Join(parts, ", ")
}
func genParamFmtString(path string) string {
return ReplacePathParamsWithStr(path)
}
// genResponsePayload generates the payload returned at the end of each client request function
func genResponsePayload(operationID string) string {
var buffer = bytes.NewBufferString("")
@ -99,8 +95,6 @@ func genResponsePayload(operationID string) string {
// genResponseUnmarshal generates unmarshaling steps for structured response payloads
func genResponseUnmarshal(op *OperationDefinition) string {
var buffer = bytes.NewBufferString("")
var handledCaseClauses = make(map[string]string)
var unhandledCaseClauses = make(map[string]string)
@ -110,7 +104,13 @@ func genResponseUnmarshal(op *OperationDefinition) string {
panic(err)
}
if len(typeDefinitions) == 0 {
// No types.
return ""
}
// Add a case for each possible response:
buffer := new(bytes.Buffer)
responses := op.Spec.Responses
for _, typeDefinition := range typeDefinitions {
@ -128,13 +128,8 @@ func genResponseUnmarshal(op *OperationDefinition) string {
// If there is no content-type then we have no unmarshaling to do:
if len(responseRef.Value.Content) == 0 {
caseAction := "break // No content-type"
if typeDefinition.ResponseName == "default" {
caseClauseKey := "default:"
unhandledCaseClauses[prefixLeastSpecific+caseClauseKey] = fmt.Sprintf("%s\n%s\n", caseClauseKey, caseAction)
} else {
caseClauseKey := fmt.Sprintf("case rsp.StatusCode == %s:", typeDefinition.ResponseName)
unhandledCaseClauses[prefixLessSpecific+caseClauseKey] = fmt.Sprintf("%s\n%s\n", caseClauseKey, caseAction)
}
caseClauseKey := "case " + getConditionOfResponseName("rsp.StatusCode", typeDefinition.ResponseName) + ":"
unhandledCaseClauses[prefixLeastSpecific+caseClauseKey] = fmt.Sprintf("%s\n%s\n", caseClauseKey, caseAction)
continue
}
@ -153,59 +148,65 @@ func genResponseUnmarshal(op *OperationDefinition) string {
// JSON:
case StringInArray(contentTypeName, contentTypesJSON):
var caseAction string
if typeDefinition.ContentTypeName == contentTypeName {
var caseAction string
caseAction = fmt.Sprintf("var dest %s\n"+
"if err := json.Unmarshal(bodyBytes, &dest); err != nil { \n"+
" return nil, err \n"+
"}\n"+
"response.%s = &dest",
typeDefinition.Schema.TypeDecl(),
typeDefinition.TypeName)
caseAction = fmt.Sprintf("var dest %s\n"+
"if err := json.Unmarshal(bodyBytes, &dest); err != nil { \n"+
" return nil, err \n"+
"}\n"+
"response.%s = &dest",
typeDefinition.Schema.TypeDecl(),
typeDefinition.TypeName)
caseKey, caseClause := buildUnmarshalCase(typeDefinition, caseAction, "json")
handledCaseClauses[caseKey] = caseClause
caseKey, caseClause := buildUnmarshalCase(typeDefinition, caseAction, "json")
handledCaseClauses[caseKey] = caseClause
}
// YAML:
case StringInArray(contentTypeName, contentTypesYAML):
var caseAction string
caseAction = fmt.Sprintf("var dest %s\n"+
"if err := yaml.Unmarshal(bodyBytes, &dest); err != nil { \n"+
" return nil, err \n"+
"}\n"+
"response.%s = &dest",
typeDefinition.Schema.TypeDecl(),
typeDefinition.TypeName)
caseKey, caseClause := buildUnmarshalCase(typeDefinition, caseAction, "yaml")
handledCaseClauses[caseKey] = caseClause
if typeDefinition.ContentTypeName == contentTypeName {
var caseAction string
caseAction = fmt.Sprintf("var dest %s\n"+
"if err := yaml.Unmarshal(bodyBytes, &dest); err != nil { \n"+
" return nil, err \n"+
"}\n"+
"response.%s = &dest",
typeDefinition.Schema.TypeDecl(),
typeDefinition.TypeName)
caseKey, caseClause := buildUnmarshalCase(typeDefinition, caseAction, "yaml")
handledCaseClauses[caseKey] = caseClause
}
// XML:
case StringInArray(contentTypeName, contentTypesXML):
var caseAction string
caseAction = fmt.Sprintf("var dest %s\n"+
"if err := xml.Unmarshal(bodyBytes, &dest); err != nil { \n"+
" return nil, err \n"+
"}\n"+
"response.%s = &dest",
typeDefinition.Schema.TypeDecl(),
typeDefinition.TypeName)
caseKey, caseClause := buildUnmarshalCase(typeDefinition, caseAction, "xml")
handledCaseClauses[caseKey] = caseClause
if typeDefinition.ContentTypeName == contentTypeName {
var caseAction string
caseAction = fmt.Sprintf("var dest %s\n"+
"if err := xml.Unmarshal(bodyBytes, &dest); err != nil { \n"+
" return nil, err \n"+
"}\n"+
"response.%s = &dest",
typeDefinition.Schema.TypeDecl(),
typeDefinition.TypeName)
caseKey, caseClause := buildUnmarshalCase(typeDefinition, caseAction, "xml")
handledCaseClauses[caseKey] = caseClause
}
// Everything else:
default:
caseAction := fmt.Sprintf("// Content-type (%s) unsupported", contentTypeName)
if typeDefinition.ResponseName == "default" {
caseClauseKey := "default:"
unhandledCaseClauses[prefixLeastSpecific+caseClauseKey] = fmt.Sprintf("%s\n%s\n", caseClauseKey, caseAction)
} else {
caseClauseKey := fmt.Sprintf("case rsp.StatusCode == %s:", typeDefinition.ResponseName)
unhandledCaseClauses[prefixLessSpecific+caseClauseKey] = fmt.Sprintf("%s\n%s\n", caseClauseKey, caseAction)
}
caseClauseKey := "case " + getConditionOfResponseName("rsp.StatusCode", typeDefinition.ResponseName) + ":"
unhandledCaseClauses[prefixLeastSpecific+caseClauseKey] = fmt.Sprintf("%s\n%s\n", caseClauseKey, caseAction)
}
}
}
if len(handledCaseClauses)+len(unhandledCaseClauses) == 0 {
// switch would be empty.
return ""
}
// Now build the switch statement in order of most-to-least specific:
// See: https://github.com/deepmap/oapi-codegen/issues/127 for why we handle this in two separate
// groups.
@ -224,13 +225,10 @@ func genResponseUnmarshal(op *OperationDefinition) string {
}
// buildUnmarshalCase builds an unmarshalling case clause for different content-types:
func buildUnmarshalCase(typeDefinition TypeDefinition, caseAction string, contentType string) (caseKey string, caseClause string) {
func buildUnmarshalCase(typeDefinition ResponseTypeDefinition, caseAction string, contentType string) (caseKey string, caseClause string) {
caseKey = fmt.Sprintf("%s.%s.%s", prefixLeastSpecific, contentType, typeDefinition.ResponseName)
if typeDefinition.ResponseName == "default" {
caseClause = fmt.Sprintf("case strings.Contains(rsp.Header.Get(\"%s\"), \"%s\"):\n%s\n", echo.HeaderContentType, contentType, caseAction)
} else {
caseClause = fmt.Sprintf("case strings.Contains(rsp.Header.Get(\"%s\"), \"%s\") && rsp.StatusCode == %s:\n%s\n", echo.HeaderContentType, contentType, typeDefinition.ResponseName, caseAction)
}
caseClauseKey := getConditionOfResponseName("rsp.StatusCode", typeDefinition.ResponseName)
caseClause = fmt.Sprintf("case strings.Contains(rsp.Header.Get(\"%s\"), \"%s\") && %s:\n%s\n", echo.HeaderContentType, contentType, caseClauseKey, caseAction)
return caseKey, caseClause
}
@ -239,7 +237,7 @@ func genResponseTypeName(operationID string) string {
return fmt.Sprintf("%s%s", UppercaseFirstCharacter(operationID), responseTypeSuffix)
}
func getResponseTypeDefinitions(op *OperationDefinition) []TypeDefinition {
func getResponseTypeDefinitions(op *OperationDefinition) []ResponseTypeDefinition {
td, err := op.GetResponseTypeDefinitions()
if err != nil {
panic(err)
@ -247,6 +245,18 @@ func getResponseTypeDefinitions(op *OperationDefinition) []TypeDefinition {
return td
}
// Return the statusCode comparison clause from the response name.
func getConditionOfResponseName(statusCodeVar, responseName string) string {
switch responseName {
case "default":
return "true"
case "1XX", "2XX", "3XX", "4XX", "5XX":
return fmt.Sprintf("%s / 100 == %s", statusCodeVar, responseName[:1])
default:
return fmt.Sprintf("%s == %s", statusCodeVar, responseName)
}
}
// This outputs a string array
func toStringArray(sarr []string) string {
return `[]string{"` + strings.Join(sarr, `","`) + `"}`
@ -263,7 +273,7 @@ var TemplateFunctions = template.FuncMap{
"genParamArgs": genParamArgs,
"genParamTypes": genParamTypes,
"genParamNames": genParamNames,
"genParamFmtString": genParamFmtString,
"genParamFmtString": ReplacePathParamsWithStr,
"swaggerUriToEchoUri": SwaggerUriToEchoUri,
"swaggerUriToChiUri": SwaggerUriToChiUri,
"lcFirst": LowercaseFirstCharacter,
@ -277,4 +287,5 @@ var TemplateFunctions = template.FuncMap{
"lower": strings.ToLower,
"title": strings.Title,
"stripNewLines": stripNewLines,
"sanitizeGoIdentity": SanitizeGoIdentity,
}

View file

@ -1,17 +1,43 @@
// Handler creates http.Handler with routing matching OpenAPI spec.
func Handler(si ServerInterface) http.Handler {
return HandlerFromMux(si, chi.NewRouter())
return HandlerWithOptions(si, ChiServerOptions{})
}
type ChiServerOptions struct {
BaseURL string
BaseRouter chi.Router
Middlewares []MiddlewareFunc
}
// HandlerFromMux creates http.Handler with routing matching OpenAPI spec based on the provided mux.
func HandlerFromMux(si ServerInterface, r chi.Router) http.Handler {
return HandlerWithOptions(si, ChiServerOptions {
BaseRouter: r,
})
}
func HandlerFromMuxWithBaseURL(si ServerInterface, r chi.Router, baseURL string) http.Handler {
return HandlerWithOptions(si, ChiServerOptions {
BaseURL: baseURL,
BaseRouter: r,
})
}
// HandlerWithOptions creates http.Handler with additional options
func HandlerWithOptions(si ServerInterface, options ChiServerOptions) http.Handler {
r := options.BaseRouter
if r == nil {
r = chi.NewRouter()
}
{{if .}}wrapper := ServerInterfaceWrapper{
Handler: si,
}
Handler: si,
HandlerMiddlewares: options.Middlewares,
}
{{end}}
{{range .}}r.Group(func(r chi.Router) {
r.{{.Method | lower | title }}("{{.Path | swaggerUriToChiUri}}", wrapper.{{.OperationId}})
r.{{.Method | lower | title }}(options.BaseURL+"{{.Path | swaggerUriToChiUri}}", wrapper.{{.OperationId}})
})
{{end}}
return r
return r
}

View file

@ -1,8 +1,11 @@
// ServerInterfaceWrapper converts contexts to parameters.
type ServerInterfaceWrapper struct {
Handler ServerInterface
HandlerMiddlewares []MiddlewareFunc
}
type MiddlewareFunc func(http.HandlerFunc) http.HandlerFunc
{{range .}}{{$opid := .OperationId}}
// {{$opid}} operation middleware
@ -36,7 +39,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(w http.ResponseWriter, r *http.Requ
{{end}}
{{range .SecurityDefinitions}}
ctx = context.WithValue(ctx, "{{.ProviderName}}.Scopes", {{toStringArray .Scopes}})
ctx = context.WithValue(ctx, {{.ProviderName | ucFirst}}Scopes, {{toStringArray .Scopes}})
{{end}}
{{if .RequiresParamObject}}
@ -98,7 +101,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(w http.ResponseWriter, r *http.Requ
{{end}}
{{if .IsStyled}}
err = runtime.BindStyledParameter("{{.Style}}",{{.Explode}}, "{{.ParamName}}", valueList[0], &{{.GoName}})
err = runtime.BindStyledParameterWithLocation("{{.Style}}",{{.Explode}}, "{{.ParamName}}", runtime.ParamLocationHeader, valueList[0], &{{.GoName}})
if err != nil {
http.Error(w, fmt.Sprintf("Invalid format for parameter {{.ParamName}}: %s", err), http.StatusBadRequest)
return
@ -116,7 +119,9 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(w http.ResponseWriter, r *http.Requ
{{end}}
{{range .CookieParams}}
if cookie, err := r.Cookie("{{.ParamName}}"); err == nil {
var cookie *http.Cookie
if cookie, err = r.Cookie("{{.ParamName}}"); err == nil {
{{- if .IsPassThrough}}
params.{{.GoName}} = {{if not .Required}}&{{end}}cookie.Value
@ -159,7 +164,16 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(w http.ResponseWriter, r *http.Requ
{{- end}}
{{end}}
{{end}}
siw.Handler.{{.OperationId}}(w, r.WithContext(ctx){{genParamNames .PathParams}}{{if .RequiresParamObject}}, params{{end}})
var handler = func(w http.ResponseWriter, r *http.Request) {
siw.Handler.{{.OperationId}}(w, r{{genParamNames .PathParams}}{{if .RequiresParamObject}}, params{{end}})
}
for _, middleware := range siw.HandlerMiddlewares {
handler = middleware(handler)
}
handler(w, r.WithContext(ctx))
}
{{end}}

View file

@ -31,10 +31,10 @@ type ClientWithResponsesInterface interface {
{{$hasParams := .RequiresParamObject -}}
{{$pathParams := .PathParams -}}
{{$opid := .OperationId -}}
// {{$opid}} request {{if .HasBody}} with any body{{end}}
{{$opid}}{{if .HasBody}}WithBody{{end}}WithResponse(ctx context.Context{{genParamArgs .PathParams}}{{if .RequiresParamObject}}, params *{{$opid}}Params{{end}}{{if .HasBody}}, contentType string, body io.Reader{{end}}) (*{{genResponseTypeName $opid}}, error)
// {{$opid}} request{{if .HasBody}} with any body{{end}}
{{$opid}}{{if .HasBody}}WithBody{{end}}WithResponse(ctx context.Context{{genParamArgs .PathParams}}{{if .RequiresParamObject}}, params *{{$opid}}Params{{end}}{{if .HasBody}}, contentType string, body io.Reader{{end}}, reqEditors... RequestEditorFn) (*{{genResponseTypeName $opid}}, error)
{{range .Bodies}}
{{$opid}}{{.Suffix}}WithResponse(ctx context.Context{{genParamArgs $pathParams}}{{if $hasParams}}, params *{{$opid}}Params{{end}}, body {{$opid}}{{.NameTag}}RequestBody) (*{{genResponseTypeName $opid}}, error)
{{$opid}}{{.Suffix}}WithResponse(ctx context.Context{{genParamArgs $pathParams}}{{if $hasParams}}, params *{{$opid}}Params{{end}}, body {{$opid}}{{.NameTag}}RequestBody, reqEditors... RequestEditorFn) (*{{genResponseTypeName $opid}}, error)
{{end}}{{/* range .Bodies */}}
{{end}}{{/* range . $opid := .OperationId */}}
}
@ -71,8 +71,8 @@ func (r {{$opid | ucFirst}}Response) StatusCode() int {
{{/* Generate client methods (with responses)*/}}
// {{$opid}}{{if .HasBody}}WithBody{{end}}WithResponse request{{if .HasBody}} with arbitrary body{{end}} returning *{{$opid}}Response
func (c *ClientWithResponses) {{$opid}}{{if .HasBody}}WithBody{{end}}WithResponse(ctx context.Context{{genParamArgs .PathParams}}{{if .RequiresParamObject}}, params *{{$opid}}Params{{end}}{{if .HasBody}}, contentType string, body io.Reader{{end}}) (*{{genResponseTypeName $opid}}, error){
rsp, err := c.{{$opid}}{{if .HasBody}}WithBody{{end}}(ctx{{genParamNames .PathParams}}{{if .RequiresParamObject}}, params{{end}}{{if .HasBody}}, contentType, body{{end}})
func (c *ClientWithResponses) {{$opid}}{{if .HasBody}}WithBody{{end}}WithResponse(ctx context.Context{{genParamArgs .PathParams}}{{if .RequiresParamObject}}, params *{{$opid}}Params{{end}}{{if .HasBody}}, contentType string, body io.Reader{{end}}, reqEditors... RequestEditorFn) (*{{genResponseTypeName $opid}}, error){
rsp, err := c.{{$opid}}{{if .HasBody}}WithBody{{end}}(ctx{{genParamNames .PathParams}}{{if .RequiresParamObject}}, params{{end}}{{if .HasBody}}, contentType, body{{end}}, reqEditors...)
if err != nil {
return nil, err
}
@ -83,8 +83,8 @@ func (c *ClientWithResponses) {{$opid}}{{if .HasBody}}WithBody{{end}}WithRespons
{{$pathParams := .PathParams -}}
{{$bodyRequired := .BodyRequired -}}
{{range .Bodies}}
func (c *ClientWithResponses) {{$opid}}{{.Suffix}}WithResponse(ctx context.Context{{genParamArgs $pathParams}}{{if $hasParams}}, params *{{$opid}}Params{{end}}, body {{$opid}}{{.NameTag}}RequestBody) (*{{genResponseTypeName $opid}}, error) {
rsp, err := c.{{$opid}}{{.Suffix}}(ctx{{genParamNames $pathParams}}{{if $hasParams}}, params{{end}}, body)
func (c *ClientWithResponses) {{$opid}}{{.Suffix}}WithResponse(ctx context.Context{{genParamArgs $pathParams}}{{if $hasParams}}, params *{{$opid}}Params{{end}}, body {{$opid}}{{.NameTag}}RequestBody, reqEditors... RequestEditorFn) (*{{genResponseTypeName $opid}}, error) {
rsp, err := c.{{$opid}}{{.Suffix}}(ctx{{genParamNames $pathParams}}{{if $hasParams}}, params{{end}}, body, reqEditors...)
if err != nil {
return nil, err
}

View file

@ -11,16 +11,18 @@ type HttpRequestDoer interface {
// Client which conforms to the OpenAPI3 specification for this service.
type Client struct {
// The endpoint of the server conforming to this interface, with scheme,
// https://api.deepmap.com for example.
// https://api.deepmap.com for example. This can contain a path relative
// to the server, such as https://api.deepmap.com/dev-test, and all the
// paths in the swagger spec will be appended to the server.
Server string
// Doer for performing requests, typically a *http.Client with any
// customized settings, such as certificate chains.
Client HttpRequestDoer
// A callback for modifying requests which are generated before sending over
// A list of callbacks for modifying requests which are generated before sending over
// the network.
RequestEditor RequestEditorFn
RequestEditors []RequestEditorFn
}
// ClientOption allows setting custom parameters during construction
@ -44,7 +46,7 @@ func NewClient(server string, opts ...ClientOption) (*Client, error) {
}
// create httpClient, if not already present
if client.Client == nil {
client.Client = http.DefaultClient
client.Client = &http.Client{}
}
return &client, nil
}
@ -62,7 +64,7 @@ func WithHTTPClient(doer HttpRequestDoer) ClientOption {
// called right before sending the request. This can be used to mutate the request.
func WithRequestEditorFn(fn RequestEditorFn) ClientOption {
return func(c *Client) error {
c.RequestEditor = fn
c.RequestEditors = append(c.RequestEditors, fn)
return nil
}
}
@ -73,10 +75,10 @@ type ClientInterface interface {
{{$hasParams := .RequiresParamObject -}}
{{$pathParams := .PathParams -}}
{{$opid := .OperationId -}}
// {{$opid}} request {{if .HasBody}} with any body{{end}}
{{$opid}}{{if .HasBody}}WithBody{{end}}(ctx context.Context{{genParamArgs $pathParams}}{{if $hasParams}}, params *{{$opid}}Params{{end}}{{if .HasBody}}, contentType string, body io.Reader{{end}}) (*http.Response, error)
// {{$opid}} request{{if .HasBody}} with any body{{end}}
{{$opid}}{{if .HasBody}}WithBody{{end}}(ctx context.Context{{genParamArgs $pathParams}}{{if $hasParams}}, params *{{$opid}}Params{{end}}{{if .HasBody}}, contentType string, body io.Reader{{end}}, reqEditors... RequestEditorFn) (*http.Response, error)
{{range .Bodies}}
{{$opid}}{{.Suffix}}(ctx context.Context{{genParamArgs $pathParams}}{{if $hasParams}}, params *{{$opid}}Params{{end}}, body {{$opid}}{{.NameTag}}RequestBody) (*http.Response, error)
{{$opid}}{{.Suffix}}(ctx context.Context{{genParamArgs $pathParams}}{{if $hasParams}}, params *{{$opid}}Params{{end}}, body {{$opid}}{{.NameTag}}RequestBody, reqEditors... RequestEditorFn) (*http.Response, error)
{{end}}{{/* range .Bodies */}}
{{end}}{{/* range . $opid := .OperationId */}}
}
@ -88,33 +90,27 @@ type ClientInterface interface {
{{$pathParams := .PathParams -}}
{{$opid := .OperationId -}}
func (c *Client) {{$opid}}{{if .HasBody}}WithBody{{end}}(ctx context.Context{{genParamArgs $pathParams}}{{if $hasParams}}, params *{{$opid}}Params{{end}}{{if .HasBody}}, contentType string, body io.Reader{{end}}) (*http.Response, error) {
func (c *Client) {{$opid}}{{if .HasBody}}WithBody{{end}}(ctx context.Context{{genParamArgs $pathParams}}{{if $hasParams}}, params *{{$opid}}Params{{end}}{{if .HasBody}}, contentType string, body io.Reader{{end}}, reqEditors... RequestEditorFn) (*http.Response, error) {
req, err := New{{$opid}}Request{{if .HasBody}}WithBody{{end}}(c.Server{{genParamNames .PathParams}}{{if $hasParams}}, params{{end}}{{if .HasBody}}, contentType, body{{end}})
if err != nil {
return nil, err
}
req = req.WithContext(ctx)
if c.RequestEditor != nil {
err = c.RequestEditor(ctx, req)
if err != nil {
return nil, err
}
if err := c.applyEditors(ctx, req, reqEditors); err != nil {
return nil, err
}
return c.Client.Do(req)
}
{{range .Bodies}}
func (c *Client) {{$opid}}{{.Suffix}}(ctx context.Context{{genParamArgs $pathParams}}{{if $hasParams}}, params *{{$opid}}Params{{end}}, body {{$opid}}{{.NameTag}}RequestBody) (*http.Response, error) {
func (c *Client) {{$opid}}{{.Suffix}}(ctx context.Context{{genParamArgs $pathParams}}{{if $hasParams}}, params *{{$opid}}Params{{end}}, body {{$opid}}{{.NameTag}}RequestBody, reqEditors... RequestEditorFn) (*http.Response, error) {
req, err := New{{$opid}}{{.Suffix}}Request(c.Server{{genParamNames $pathParams}}{{if $hasParams}}, params{{end}}, body)
if err != nil {
return nil, err
}
req = req.WithContext(ctx)
if c.RequestEditor != nil {
err = c.RequestEditor(ctx, req)
if err != nil {
return nil, err
}
if err := c.applyEditors(ctx, req, reqEditors); err != nil {
return nil, err
}
return c.Client.Do(req)
}
@ -147,39 +143,40 @@ func New{{$opid}}Request{{if .HasBody}}WithBody{{end}}(server string{{genParamAr
{{range $paramIdx, $param := .PathParams}}
var pathParam{{$paramIdx}} string
{{if .IsPassThrough}}
pathParam{{$paramIdx}} = {{.ParamName}}
pathParam{{$paramIdx}} = {{.GoVariableName}}
{{end}}
{{if .IsJson}}
var pathParamBuf{{$paramIdx}} []byte
pathParamBuf{{$paramIdx}}, err = json.Marshal({{.ParamName}})
pathParamBuf{{$paramIdx}}, err = json.Marshal({{.GoVariableName}})
if err != nil {
return nil, err
}
pathParam{{$paramIdx}} = string(pathParamBuf{{$paramIdx}})
{{end}}
{{if .IsStyled}}
pathParam{{$paramIdx}}, err = runtime.StyleParam("{{.Style}}", {{.Explode}}, "{{.ParamName}}", {{.GoVariableName}})
pathParam{{$paramIdx}}, err = runtime.StyleParamWithLocation("{{.Style}}", {{.Explode}}, "{{.ParamName}}", runtime.ParamLocationPath, {{.GoVariableName}})
if err != nil {
return nil, err
}
{{end}}
{{end}}
queryUrl, err := url.Parse(server)
serverURL, err := url.Parse(server)
if err != nil {
return nil, err
}
basePath := fmt.Sprintf("{{genParamFmtString .Path}}"{{range $paramIdx, $param := .PathParams}}, pathParam{{$paramIdx}}{{end}})
if basePath[0] == '/' {
basePath = basePath[1:]
operationPath := fmt.Sprintf("{{genParamFmtString .Path}}"{{range $paramIdx, $param := .PathParams}}, pathParam{{$paramIdx}}{{end}})
if operationPath[0] == '/' {
operationPath = "." + operationPath
}
queryUrl, err = queryUrl.Parse(basePath)
queryURL, err := serverURL.Parse(operationPath)
if err != nil {
return nil, err
}
{{if .QueryParams}}
queryValues := queryUrl.Query()
queryValues := queryURL.Query()
{{range $paramIdx, $param := .QueryParams}}
{{if not .Required}} if params.{{.GoName}} != nil { {{end}}
{{if .IsPassThrough}}
@ -194,7 +191,7 @@ func New{{$opid}}Request{{if .HasBody}}WithBody{{end}}(server string{{genParamAr
{{end}}
{{if .IsStyled}}
if queryFrag, err := runtime.StyleParam("{{.Style}}", {{.Explode}}, "{{.ParamName}}", {{if not .Required}}*{{end}}params.{{.GoName}}); err != nil {
if queryFrag, err := runtime.StyleParamWithLocation("{{.Style}}", {{.Explode}}, "{{.ParamName}}", runtime.ParamLocationQuery, {{if not .Required}}*{{end}}params.{{.GoName}}); err != nil {
return nil, err
} else if parsed, err := url.ParseQuery(queryFrag); err != nil {
return nil, err
@ -208,13 +205,14 @@ func New{{$opid}}Request{{if .HasBody}}WithBody{{end}}(server string{{genParamAr
{{end}}
{{if not .Required}}}{{end}}
{{end}}
queryUrl.RawQuery = queryValues.Encode()
queryURL.RawQuery = queryValues.Encode()
{{end}}{{/* if .QueryParams */}}
req, err := http.NewRequest("{{.Method}}", queryUrl.String(), {{if .HasBody}}body{{else}}nil{{end}})
req, err := http.NewRequest("{{.Method}}", queryURL.String(), {{if .HasBody}}body{{else}}nil{{end}})
if err != nil {
return nil, err
}
{{if .HasBody}}req.Header.Add("Content-Type", contentType){{end}}
{{range $paramIdx, $param := .HeaderParams}}
{{if not .Required}} if params.{{.GoName}} != nil { {{end}}
var headerParam{{$paramIdx}} string
@ -230,12 +228,12 @@ func New{{$opid}}Request{{if .HasBody}}WithBody{{end}}(server string{{genParamAr
headerParam{{$paramIdx}} = string(headerParamBuf{{$paramIdx}})
{{end}}
{{if .IsStyled}}
headerParam{{$paramIdx}}, err = runtime.StyleParam("{{.Style}}", {{.Explode}}, "{{.ParamName}}", {{if not .Required}}*{{end}}params.{{.GoName}})
headerParam{{$paramIdx}}, err = runtime.StyleParamWithLocation("{{.Style}}", {{.Explode}}, "{{.ParamName}}", runtime.ParamLocationHeader, {{if not .Required}}*{{end}}params.{{.GoName}})
if err != nil {
return nil, err
}
{{end}}
req.Header.Add("{{.ParamName}}", headerParam{{$paramIdx}})
req.Header.Set("{{.ParamName}}", headerParam{{$paramIdx}})
{{if not .Required}}}{{end}}
{{end}}
@ -254,7 +252,7 @@ func New{{$opid}}Request{{if .HasBody}}WithBody{{end}}(server string{{genParamAr
cookieParam{{$paramIdx}} = url.QueryEscape(string(cookieParamBuf{{$paramIdx}}))
{{end}}
{{if .IsStyled}}
cookieParam{{$paramIdx}}, err = runtime.StyleParam("simple", {{.Explode}}, "{{.ParamName}}", {{if not .Required}}*{{end}}params.{{.GoName}})
cookieParam{{$paramIdx}}, err = runtime.StyleParamWithLocation("simple", {{.Explode}}, "{{.ParamName}}", runtime.ParamLocationCookie, {{if not .Required}}*{{end}}params.{{.GoName}})
if err != nil {
return nil, err
}
@ -266,8 +264,21 @@ func New{{$opid}}Request{{if .HasBody}}WithBody{{end}}(server string{{genParamAr
req.AddCookie(cookie{{$paramIdx}})
{{if not .Required}}}{{end}}
{{end}}
{{if .HasBody}}req.Header.Add("Content-Type", contentType){{end}}
return req, nil
}
{{end}}{{/* Range */}}
func (c *Client) applyEditors(ctx context.Context, req *http.Request, additionalEditors []RequestEditorFn) error {
for _, r := range c.RequestEditors {
if err := r(ctx, req); err != nil {
return err
}
}
for _, r := range additionalEditors {
if err := r(ctx, req); err != nil {
return err
}
}
return nil
}

View file

@ -0,0 +1,17 @@
{{- if gt (len .SecuritySchemeProviderNames) 0 }}
const (
{{range $ProviderName := .SecuritySchemeProviderNames}}
{{- $ProviderName | ucFirst}}Scopes = "{{$ProviderName}}.Scopes"
{{end}}
)
{{end}}
{{if gt (len .EnumDefinitions) 0 }}
{{range $Enum := .EnumDefinitions}}
// Defines values for {{$Enum.TypeName}}.
const (
{{range $index, $value := $Enum.Schema.EnumValues}}
{{$index}} {{$Enum.TypeName}} = {{$Enum.ValueWrapper}}{{$value}}{{$Enum.ValueWrapper}}
{{end}}
)
{{end}}
{{end}}

View file

@ -1,10 +1,32 @@
// Package {{.PackageName}} provides primitives to interact the openapi HTTP API.
// Package {{.PackageName}} provides primitives to interact with the openapi HTTP API.
//
// Code generated by github.com/deepmap/oapi-codegen DO NOT EDIT.
// Code generated by {{.ModuleName}} version {{.Version}} DO NOT EDIT.
package {{.PackageName}}
{{if .Imports}}
import (
{{range .Imports}} {{ . }}
{{end}})
{{end}}
"bytes"
"compress/gzip"
"context"
"encoding/base64"
"encoding/json"
"encoding/xml"
"fmt"
"gopkg.in/yaml.v2"
"io"
"io/ioutil"
"net/http"
"net/url"
"path"
"strings"
"time"
"github.com/deepmap/oapi-codegen/pkg/runtime"
openapi_types "github.com/deepmap/oapi-codegen/pkg/types"
"github.com/getkin/kin-openapi/openapi3"
"github.com/go-chi/chi/v5"
"github.com/labstack/echo/v4"
"github.com/pkg/errors"
{{- range .ExternalImports}}
{{ . }}
{{- end}}
)

View file

@ -1,12 +1,12 @@
// Base64 encoded, gzipped, json marshaled Swagger object
var swaggerSpec = []string{
{{range .}}
{{range .SpecParts}}
"{{.}}",{{end}}
}
// GetSwagger returns the Swagger specification corresponding to the generated code
// in this file.
func GetSwagger() (*openapi3.Swagger, error) {
// GetSwagger returns the content of the embedded swagger specification file
// or error if failed to decode
func decodeSpec() ([]byte, error) {
zipped, err := base64.StdEncoding.DecodeString(strings.Join(swaggerSpec, ""))
if err != nil {
return nil, fmt.Errorf("error base64 decoding spec: %s", err)
@ -21,9 +21,67 @@ func GetSwagger() (*openapi3.Swagger, error) {
return nil, fmt.Errorf("error decompressing spec: %s", err)
}
swagger, err := openapi3.NewSwaggerLoader().LoadSwaggerFromData(buf.Bytes())
if err != nil {
return nil, fmt.Errorf("error loading Swagger: %s", err)
}
return swagger, nil
return buf.Bytes(), nil
}
var rawSpec = decodeSpecCached()
// a naive cached of a decoded swagger spec
func decodeSpecCached() func() ([]byte, error) {
data, err := decodeSpec()
return func() ([]byte, error) {
return data, err
}
}
// Constructs a synthetic filesystem for resolving external references when loading openapi specifications.
func PathToRawSpec(pathToFile string) map[string]func() ([]byte, error) {
var res = make(map[string]func() ([]byte, error))
if len(pathToFile) > 0 {
res[pathToFile] = rawSpec
}
{{ if .ImportMapping }}
pathPrefix := path.Dir(pathToFile)
{{ end }}
{{ range $key, $value := .ImportMapping }}
for rawPath, rawFunc := range {{ $value.Name }}.PathToRawSpec(path.Join(pathPrefix, "{{ $key }}")) {
if _, ok := res[rawPath]; ok {
// it is not possible to compare functions in golang, so always overwrite the old value
}
res[rawPath] = rawFunc
}
{{- end }}
return res
}
// GetSwagger returns the Swagger specification corresponding to the generated code
// in this file. The external references of Swagger specification are resolved.
// The logic of resolving external references is tightly connected to "import-mapping" feature.
// Externally referenced files must be embedded in the corresponding golang packages.
// Urls can be supported but this task was out of the scope.
func GetSwagger() (swagger *openapi3.T, err error) {
var resolvePath = PathToRawSpec("")
loader := openapi3.NewLoader()
loader.IsExternalRefsAllowed = true
loader.ReadFromURIFunc = func(loader *openapi3.Loader, url *url.URL) ([]byte, error) {
var pathToFile = url.String()
pathToFile = path.Clean(pathToFile)
getSpec, ok := resolvePath[pathToFile]
if !ok {
err1 := fmt.Errorf("path not found: %s", pathToFile)
return nil, err1
}
return getSpec()
}
var specData []byte
specData, err = rawSpec()
if err != nil {
return
}
swagger, err = loader.LoadFromData(specData)
if err != nil {
return
}
return
}

View file

@ -1,6 +1,6 @@
{{range .}}{{$opid := .OperationId}}
{{range .TypeDefinitions}}
// {{.TypeName}} defines parameters for {{$opid}}.
type {{.TypeName}} {{.Schema.TypeDecl}}
type {{.TypeName}} {{if and (opts.AliasTypes) (.CanAlias)}}={{end}} {{.Schema.TypeDecl}}
{{end}}
{{end}}

View file

@ -17,11 +17,17 @@ type EchoRouter interface {
// RegisterHandlers adds each server route to the EchoRouter.
func RegisterHandlers(router EchoRouter, si ServerInterface) {
RegisterHandlersWithBaseURL(router, si, "")
}
// Registers handlers, and prepends BaseURL to the paths, so that the paths
// can be served under a prefix.
func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL string) {
{{if .}}
wrapper := ServerInterfaceWrapper{
Handler: si,
}
{{end}}
{{range .}}router.{{.Method}}("{{.Path | swaggerUriToEchoUri}}", wrapper.{{.OperationId}})
{{range .}}router.{{.Method}}(baseURL + "{{.Path | swaggerUriToEchoUri}}", wrapper.{{.OperationId}})
{{end}}
}

View file

@ -1,6 +1,8 @@
{{range .}}{{$opid := .OperationId}}
{{range .Bodies}}
// {{$opid}}RequestBody defines body for {{$opid}} for application/json ContentType.
type {{$opid}}{{.NameTag}}RequestBody {{.TypeDef}}
{{with .TypeDef $opid}}
// {{.TypeName}} defines body for {{$opid}} for application/json ContentType.
type {{.TypeName}} {{if and (opts.AliasTypes) (.CanAlias)}}={{end}} {{.Schema.TypeDecl}}
{{end}}
{{end}}
{{end}}

View file

@ -75,20 +75,46 @@ func (a {{.TypeName}}) MarshalJSON() ([]byte, error) {
`,
"chi-handler.tmpl": `// Handler creates http.Handler with routing matching OpenAPI spec.
func Handler(si ServerInterface) http.Handler {
return HandlerFromMux(si, chi.NewRouter())
return HandlerWithOptions(si, ChiServerOptions{})
}
type ChiServerOptions struct {
BaseURL string
BaseRouter chi.Router
Middlewares []MiddlewareFunc
}
// HandlerFromMux creates http.Handler with routing matching OpenAPI spec based on the provided mux.
func HandlerFromMux(si ServerInterface, r chi.Router) http.Handler {
return HandlerWithOptions(si, ChiServerOptions {
BaseRouter: r,
})
}
func HandlerFromMuxWithBaseURL(si ServerInterface, r chi.Router, baseURL string) http.Handler {
return HandlerWithOptions(si, ChiServerOptions {
BaseURL: baseURL,
BaseRouter: r,
})
}
// HandlerWithOptions creates http.Handler with additional options
func HandlerWithOptions(si ServerInterface, options ChiServerOptions) http.Handler {
r := options.BaseRouter
if r == nil {
r = chi.NewRouter()
}
{{if .}}wrapper := ServerInterfaceWrapper{
Handler: si,
}
Handler: si,
HandlerMiddlewares: options.Middlewares,
}
{{end}}
{{range .}}r.Group(func(r chi.Router) {
r.{{.Method | lower | title }}("{{.Path | swaggerUriToChiUri}}", wrapper.{{.OperationId}})
r.{{.Method | lower | title }}(options.BaseURL+"{{.Path | swaggerUriToChiUri}}", wrapper.{{.OperationId}})
})
{{end}}
return r
return r
}
`,
"chi-interface.tmpl": `// ServerInterface represents all server handlers.
@ -102,8 +128,11 @@ type ServerInterface interface {
"chi-middleware.tmpl": `// ServerInterfaceWrapper converts contexts to parameters.
type ServerInterfaceWrapper struct {
Handler ServerInterface
HandlerMiddlewares []MiddlewareFunc
}
type MiddlewareFunc func(http.HandlerFunc) http.HandlerFunc
{{range .}}{{$opid := .OperationId}}
// {{$opid}} operation middleware
@ -137,7 +166,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(w http.ResponseWriter, r *http.Requ
{{end}}
{{range .SecurityDefinitions}}
ctx = context.WithValue(ctx, "{{.ProviderName}}.Scopes", {{toStringArray .Scopes}})
ctx = context.WithValue(ctx, {{.ProviderName | ucFirst}}Scopes, {{toStringArray .Scopes}})
{{end}}
{{if .RequiresParamObject}}
@ -199,7 +228,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(w http.ResponseWriter, r *http.Requ
{{end}}
{{if .IsStyled}}
err = runtime.BindStyledParameter("{{.Style}}",{{.Explode}}, "{{.ParamName}}", valueList[0], &{{.GoName}})
err = runtime.BindStyledParameterWithLocation("{{.Style}}",{{.Explode}}, "{{.ParamName}}", runtime.ParamLocationHeader, valueList[0], &{{.GoName}})
if err != nil {
http.Error(w, fmt.Sprintf("Invalid format for parameter {{.ParamName}}: %s", err), http.StatusBadRequest)
return
@ -217,7 +246,9 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(w http.ResponseWriter, r *http.Requ
{{end}}
{{range .CookieParams}}
if cookie, err := r.Cookie("{{.ParamName}}"); err == nil {
var cookie *http.Cookie
if cookie, err = r.Cookie("{{.ParamName}}"); err == nil {
{{- if .IsPassThrough}}
params.{{.GoName}} = {{if not .Required}}&{{end}}cookie.Value
@ -260,7 +291,16 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(w http.ResponseWriter, r *http.Requ
{{- end}}
{{end}}
{{end}}
siw.Handler.{{.OperationId}}(w, r.WithContext(ctx){{genParamNames .PathParams}}{{if .RequiresParamObject}}, params{{end}})
var handler = func(w http.ResponseWriter, r *http.Request) {
siw.Handler.{{.OperationId}}(w, r{{genParamNames .PathParams}}{{if .RequiresParamObject}}, params{{end}})
}
for _, middleware := range siw.HandlerMiddlewares {
handler = middleware(handler)
}
handler(w, r.WithContext(ctx))
}
{{end}}
@ -300,10 +340,10 @@ type ClientWithResponsesInterface interface {
{{$hasParams := .RequiresParamObject -}}
{{$pathParams := .PathParams -}}
{{$opid := .OperationId -}}
// {{$opid}} request {{if .HasBody}} with any body{{end}}
{{$opid}}{{if .HasBody}}WithBody{{end}}WithResponse(ctx context.Context{{genParamArgs .PathParams}}{{if .RequiresParamObject}}, params *{{$opid}}Params{{end}}{{if .HasBody}}, contentType string, body io.Reader{{end}}) (*{{genResponseTypeName $opid}}, error)
// {{$opid}} request{{if .HasBody}} with any body{{end}}
{{$opid}}{{if .HasBody}}WithBody{{end}}WithResponse(ctx context.Context{{genParamArgs .PathParams}}{{if .RequiresParamObject}}, params *{{$opid}}Params{{end}}{{if .HasBody}}, contentType string, body io.Reader{{end}}, reqEditors... RequestEditorFn) (*{{genResponseTypeName $opid}}, error)
{{range .Bodies}}
{{$opid}}{{.Suffix}}WithResponse(ctx context.Context{{genParamArgs $pathParams}}{{if $hasParams}}, params *{{$opid}}Params{{end}}, body {{$opid}}{{.NameTag}}RequestBody) (*{{genResponseTypeName $opid}}, error)
{{$opid}}{{.Suffix}}WithResponse(ctx context.Context{{genParamArgs $pathParams}}{{if $hasParams}}, params *{{$opid}}Params{{end}}, body {{$opid}}{{.NameTag}}RequestBody, reqEditors... RequestEditorFn) (*{{genResponseTypeName $opid}}, error)
{{end}}{{/* range .Bodies */}}
{{end}}{{/* range . $opid := .OperationId */}}
}
@ -340,8 +380,8 @@ func (r {{$opid | ucFirst}}Response) StatusCode() int {
{{/* Generate client methods (with responses)*/}}
// {{$opid}}{{if .HasBody}}WithBody{{end}}WithResponse request{{if .HasBody}} with arbitrary body{{end}} returning *{{$opid}}Response
func (c *ClientWithResponses) {{$opid}}{{if .HasBody}}WithBody{{end}}WithResponse(ctx context.Context{{genParamArgs .PathParams}}{{if .RequiresParamObject}}, params *{{$opid}}Params{{end}}{{if .HasBody}}, contentType string, body io.Reader{{end}}) (*{{genResponseTypeName $opid}}, error){
rsp, err := c.{{$opid}}{{if .HasBody}}WithBody{{end}}(ctx{{genParamNames .PathParams}}{{if .RequiresParamObject}}, params{{end}}{{if .HasBody}}, contentType, body{{end}})
func (c *ClientWithResponses) {{$opid}}{{if .HasBody}}WithBody{{end}}WithResponse(ctx context.Context{{genParamArgs .PathParams}}{{if .RequiresParamObject}}, params *{{$opid}}Params{{end}}{{if .HasBody}}, contentType string, body io.Reader{{end}}, reqEditors... RequestEditorFn) (*{{genResponseTypeName $opid}}, error){
rsp, err := c.{{$opid}}{{if .HasBody}}WithBody{{end}}(ctx{{genParamNames .PathParams}}{{if .RequiresParamObject}}, params{{end}}{{if .HasBody}}, contentType, body{{end}}, reqEditors...)
if err != nil {
return nil, err
}
@ -352,8 +392,8 @@ func (c *ClientWithResponses) {{$opid}}{{if .HasBody}}WithBody{{end}}WithRespons
{{$pathParams := .PathParams -}}
{{$bodyRequired := .BodyRequired -}}
{{range .Bodies}}
func (c *ClientWithResponses) {{$opid}}{{.Suffix}}WithResponse(ctx context.Context{{genParamArgs $pathParams}}{{if $hasParams}}, params *{{$opid}}Params{{end}}, body {{$opid}}{{.NameTag}}RequestBody) (*{{genResponseTypeName $opid}}, error) {
rsp, err := c.{{$opid}}{{.Suffix}}(ctx{{genParamNames $pathParams}}{{if $hasParams}}, params{{end}}, body)
func (c *ClientWithResponses) {{$opid}}{{.Suffix}}WithResponse(ctx context.Context{{genParamArgs $pathParams}}{{if $hasParams}}, params *{{$opid}}Params{{end}}, body {{$opid}}{{.NameTag}}RequestBody, reqEditors... RequestEditorFn) (*{{genResponseTypeName $opid}}, error) {
rsp, err := c.{{$opid}}{{.Suffix}}(ctx{{genParamNames $pathParams}}{{if $hasParams}}, params{{end}}, body, reqEditors...)
if err != nil {
return nil, err
}
@ -396,16 +436,18 @@ type HttpRequestDoer interface {
// Client which conforms to the OpenAPI3 specification for this service.
type Client struct {
// The endpoint of the server conforming to this interface, with scheme,
// https://api.deepmap.com for example.
// https://api.deepmap.com for example. This can contain a path relative
// to the server, such as https://api.deepmap.com/dev-test, and all the
// paths in the swagger spec will be appended to the server.
Server string
// Doer for performing requests, typically a *http.Client with any
// customized settings, such as certificate chains.
Client HttpRequestDoer
// A callback for modifying requests which are generated before sending over
// A list of callbacks for modifying requests which are generated before sending over
// the network.
RequestEditor RequestEditorFn
RequestEditors []RequestEditorFn
}
// ClientOption allows setting custom parameters during construction
@ -429,7 +471,7 @@ func NewClient(server string, opts ...ClientOption) (*Client, error) {
}
// create httpClient, if not already present
if client.Client == nil {
client.Client = http.DefaultClient
client.Client = &http.Client{}
}
return &client, nil
}
@ -447,7 +489,7 @@ func WithHTTPClient(doer HttpRequestDoer) ClientOption {
// called right before sending the request. This can be used to mutate the request.
func WithRequestEditorFn(fn RequestEditorFn) ClientOption {
return func(c *Client) error {
c.RequestEditor = fn
c.RequestEditors = append(c.RequestEditors, fn)
return nil
}
}
@ -458,10 +500,10 @@ type ClientInterface interface {
{{$hasParams := .RequiresParamObject -}}
{{$pathParams := .PathParams -}}
{{$opid := .OperationId -}}
// {{$opid}} request {{if .HasBody}} with any body{{end}}
{{$opid}}{{if .HasBody}}WithBody{{end}}(ctx context.Context{{genParamArgs $pathParams}}{{if $hasParams}}, params *{{$opid}}Params{{end}}{{if .HasBody}}, contentType string, body io.Reader{{end}}) (*http.Response, error)
// {{$opid}} request{{if .HasBody}} with any body{{end}}
{{$opid}}{{if .HasBody}}WithBody{{end}}(ctx context.Context{{genParamArgs $pathParams}}{{if $hasParams}}, params *{{$opid}}Params{{end}}{{if .HasBody}}, contentType string, body io.Reader{{end}}, reqEditors... RequestEditorFn) (*http.Response, error)
{{range .Bodies}}
{{$opid}}{{.Suffix}}(ctx context.Context{{genParamArgs $pathParams}}{{if $hasParams}}, params *{{$opid}}Params{{end}}, body {{$opid}}{{.NameTag}}RequestBody) (*http.Response, error)
{{$opid}}{{.Suffix}}(ctx context.Context{{genParamArgs $pathParams}}{{if $hasParams}}, params *{{$opid}}Params{{end}}, body {{$opid}}{{.NameTag}}RequestBody, reqEditors... RequestEditorFn) (*http.Response, error)
{{end}}{{/* range .Bodies */}}
{{end}}{{/* range . $opid := .OperationId */}}
}
@ -473,33 +515,27 @@ type ClientInterface interface {
{{$pathParams := .PathParams -}}
{{$opid := .OperationId -}}
func (c *Client) {{$opid}}{{if .HasBody}}WithBody{{end}}(ctx context.Context{{genParamArgs $pathParams}}{{if $hasParams}}, params *{{$opid}}Params{{end}}{{if .HasBody}}, contentType string, body io.Reader{{end}}) (*http.Response, error) {
func (c *Client) {{$opid}}{{if .HasBody}}WithBody{{end}}(ctx context.Context{{genParamArgs $pathParams}}{{if $hasParams}}, params *{{$opid}}Params{{end}}{{if .HasBody}}, contentType string, body io.Reader{{end}}, reqEditors... RequestEditorFn) (*http.Response, error) {
req, err := New{{$opid}}Request{{if .HasBody}}WithBody{{end}}(c.Server{{genParamNames .PathParams}}{{if $hasParams}}, params{{end}}{{if .HasBody}}, contentType, body{{end}})
if err != nil {
return nil, err
}
req = req.WithContext(ctx)
if c.RequestEditor != nil {
err = c.RequestEditor(ctx, req)
if err != nil {
return nil, err
}
if err := c.applyEditors(ctx, req, reqEditors); err != nil {
return nil, err
}
return c.Client.Do(req)
}
{{range .Bodies}}
func (c *Client) {{$opid}}{{.Suffix}}(ctx context.Context{{genParamArgs $pathParams}}{{if $hasParams}}, params *{{$opid}}Params{{end}}, body {{$opid}}{{.NameTag}}RequestBody) (*http.Response, error) {
func (c *Client) {{$opid}}{{.Suffix}}(ctx context.Context{{genParamArgs $pathParams}}{{if $hasParams}}, params *{{$opid}}Params{{end}}, body {{$opid}}{{.NameTag}}RequestBody, reqEditors... RequestEditorFn) (*http.Response, error) {
req, err := New{{$opid}}{{.Suffix}}Request(c.Server{{genParamNames $pathParams}}{{if $hasParams}}, params{{end}}, body)
if err != nil {
return nil, err
}
req = req.WithContext(ctx)
if c.RequestEditor != nil {
err = c.RequestEditor(ctx, req)
if err != nil {
return nil, err
}
if err := c.applyEditors(ctx, req, reqEditors); err != nil {
return nil, err
}
return c.Client.Do(req)
}
@ -532,39 +568,40 @@ func New{{$opid}}Request{{if .HasBody}}WithBody{{end}}(server string{{genParamAr
{{range $paramIdx, $param := .PathParams}}
var pathParam{{$paramIdx}} string
{{if .IsPassThrough}}
pathParam{{$paramIdx}} = {{.ParamName}}
pathParam{{$paramIdx}} = {{.GoVariableName}}
{{end}}
{{if .IsJson}}
var pathParamBuf{{$paramIdx}} []byte
pathParamBuf{{$paramIdx}}, err = json.Marshal({{.ParamName}})
pathParamBuf{{$paramIdx}}, err = json.Marshal({{.GoVariableName}})
if err != nil {
return nil, err
}
pathParam{{$paramIdx}} = string(pathParamBuf{{$paramIdx}})
{{end}}
{{if .IsStyled}}
pathParam{{$paramIdx}}, err = runtime.StyleParam("{{.Style}}", {{.Explode}}, "{{.ParamName}}", {{.GoVariableName}})
pathParam{{$paramIdx}}, err = runtime.StyleParamWithLocation("{{.Style}}", {{.Explode}}, "{{.ParamName}}", runtime.ParamLocationPath, {{.GoVariableName}})
if err != nil {
return nil, err
}
{{end}}
{{end}}
queryUrl, err := url.Parse(server)
serverURL, err := url.Parse(server)
if err != nil {
return nil, err
}
basePath := fmt.Sprintf("{{genParamFmtString .Path}}"{{range $paramIdx, $param := .PathParams}}, pathParam{{$paramIdx}}{{end}})
if basePath[0] == '/' {
basePath = basePath[1:]
operationPath := fmt.Sprintf("{{genParamFmtString .Path}}"{{range $paramIdx, $param := .PathParams}}, pathParam{{$paramIdx}}{{end}})
if operationPath[0] == '/' {
operationPath = "." + operationPath
}
queryUrl, err = queryUrl.Parse(basePath)
queryURL, err := serverURL.Parse(operationPath)
if err != nil {
return nil, err
}
{{if .QueryParams}}
queryValues := queryUrl.Query()
queryValues := queryURL.Query()
{{range $paramIdx, $param := .QueryParams}}
{{if not .Required}} if params.{{.GoName}} != nil { {{end}}
{{if .IsPassThrough}}
@ -579,7 +616,7 @@ func New{{$opid}}Request{{if .HasBody}}WithBody{{end}}(server string{{genParamAr
{{end}}
{{if .IsStyled}}
if queryFrag, err := runtime.StyleParam("{{.Style}}", {{.Explode}}, "{{.ParamName}}", {{if not .Required}}*{{end}}params.{{.GoName}}); err != nil {
if queryFrag, err := runtime.StyleParamWithLocation("{{.Style}}", {{.Explode}}, "{{.ParamName}}", runtime.ParamLocationQuery, {{if not .Required}}*{{end}}params.{{.GoName}}); err != nil {
return nil, err
} else if parsed, err := url.ParseQuery(queryFrag); err != nil {
return nil, err
@ -593,13 +630,14 @@ func New{{$opid}}Request{{if .HasBody}}WithBody{{end}}(server string{{genParamAr
{{end}}
{{if not .Required}}}{{end}}
{{end}}
queryUrl.RawQuery = queryValues.Encode()
queryURL.RawQuery = queryValues.Encode()
{{end}}{{/* if .QueryParams */}}
req, err := http.NewRequest("{{.Method}}", queryUrl.String(), {{if .HasBody}}body{{else}}nil{{end}})
req, err := http.NewRequest("{{.Method}}", queryURL.String(), {{if .HasBody}}body{{else}}nil{{end}})
if err != nil {
return nil, err
}
{{if .HasBody}}req.Header.Add("Content-Type", contentType){{end}}
{{range $paramIdx, $param := .HeaderParams}}
{{if not .Required}} if params.{{.GoName}} != nil { {{end}}
var headerParam{{$paramIdx}} string
@ -615,12 +653,12 @@ func New{{$opid}}Request{{if .HasBody}}WithBody{{end}}(server string{{genParamAr
headerParam{{$paramIdx}} = string(headerParamBuf{{$paramIdx}})
{{end}}
{{if .IsStyled}}
headerParam{{$paramIdx}}, err = runtime.StyleParam("{{.Style}}", {{.Explode}}, "{{.ParamName}}", {{if not .Required}}*{{end}}params.{{.GoName}})
headerParam{{$paramIdx}}, err = runtime.StyleParamWithLocation("{{.Style}}", {{.Explode}}, "{{.ParamName}}", runtime.ParamLocationHeader, {{if not .Required}}*{{end}}params.{{.GoName}})
if err != nil {
return nil, err
}
{{end}}
req.Header.Add("{{.ParamName}}", headerParam{{$paramIdx}})
req.Header.Set("{{.ParamName}}", headerParam{{$paramIdx}})
{{if not .Required}}}{{end}}
{{end}}
@ -639,7 +677,7 @@ func New{{$opid}}Request{{if .HasBody}}WithBody{{end}}(server string{{genParamAr
cookieParam{{$paramIdx}} = url.QueryEscape(string(cookieParamBuf{{$paramIdx}}))
{{end}}
{{if .IsStyled}}
cookieParam{{$paramIdx}}, err = runtime.StyleParam("simple", {{.Explode}}, "{{.ParamName}}", {{if not .Required}}*{{end}}params.{{.GoName}})
cookieParam{{$paramIdx}}, err = runtime.StyleParamWithLocation("simple", {{.Explode}}, "{{.ParamName}}", runtime.ParamLocationCookie, {{if not .Required}}*{{end}}params.{{.GoName}})
if err != nil {
return nil, err
}
@ -651,32 +689,85 @@ func New{{$opid}}Request{{if .HasBody}}WithBody{{end}}(server string{{genParamAr
req.AddCookie(cookie{{$paramIdx}})
{{if not .Required}}}{{end}}
{{end}}
{{if .HasBody}}req.Header.Add("Content-Type", contentType){{end}}
return req, nil
}
{{end}}{{/* Range */}}
func (c *Client) applyEditors(ctx context.Context, req *http.Request, additionalEditors []RequestEditorFn) error {
for _, r := range c.RequestEditors {
if err := r(ctx, req); err != nil {
return err
}
}
for _, r := range additionalEditors {
if err := r(ctx, req); err != nil {
return err
}
}
return nil
}
`,
"imports.tmpl": `// Package {{.PackageName}} provides primitives to interact the openapi HTTP API.
"constants.tmpl": `{{- if gt (len .SecuritySchemeProviderNames) 0 }}
const (
{{range $ProviderName := .SecuritySchemeProviderNames}}
{{- $ProviderName | ucFirst}}Scopes = "{{$ProviderName}}.Scopes"
{{end}}
)
{{end}}
{{if gt (len .EnumDefinitions) 0 }}
{{range $Enum := .EnumDefinitions}}
// Defines values for {{$Enum.TypeName}}.
const (
{{range $index, $value := $Enum.Schema.EnumValues}}
{{$index}} {{$Enum.TypeName}} = {{$Enum.ValueWrapper}}{{$value}}{{$Enum.ValueWrapper}}
{{end}}
)
{{end}}
{{end}}
`,
"imports.tmpl": `// Package {{.PackageName}} provides primitives to interact with the openapi HTTP API.
//
// Code generated by github.com/deepmap/oapi-codegen DO NOT EDIT.
// Code generated by {{.ModuleName}} version {{.Version}} DO NOT EDIT.
package {{.PackageName}}
{{if .Imports}}
import (
{{range .Imports}} {{ . }}
{{end}})
{{end}}
"bytes"
"compress/gzip"
"context"
"encoding/base64"
"encoding/json"
"encoding/xml"
"fmt"
"gopkg.in/yaml.v2"
"io"
"io/ioutil"
"net/http"
"net/url"
"path"
"strings"
"time"
"github.com/deepmap/oapi-codegen/pkg/runtime"
openapi_types "github.com/deepmap/oapi-codegen/pkg/types"
"github.com/getkin/kin-openapi/openapi3"
"github.com/go-chi/chi/v5"
"github.com/labstack/echo/v4"
"github.com/pkg/errors"
{{- range .ExternalImports}}
{{ . }}
{{- end}}
)
`,
"inline.tmpl": `// Base64 encoded, gzipped, json marshaled Swagger object
var swaggerSpec = []string{
{{range .}}
{{range .SpecParts}}
"{{.}}",{{end}}
}
// GetSwagger returns the Swagger specification corresponding to the generated code
// in this file.
func GetSwagger() (*openapi3.Swagger, error) {
// GetSwagger returns the content of the embedded swagger specification file
// or error if failed to decode
func decodeSpec() ([]byte, error) {
zipped, err := base64.StdEncoding.DecodeString(strings.Join(swaggerSpec, ""))
if err != nil {
return nil, fmt.Errorf("error base64 decoding spec: %s", err)
@ -691,17 +782,75 @@ func GetSwagger() (*openapi3.Swagger, error) {
return nil, fmt.Errorf("error decompressing spec: %s", err)
}
swagger, err := openapi3.NewSwaggerLoader().LoadSwaggerFromData(buf.Bytes())
if err != nil {
return nil, fmt.Errorf("error loading Swagger: %s", err)
return buf.Bytes(), nil
}
var rawSpec = decodeSpecCached()
// a naive cached of a decoded swagger spec
func decodeSpecCached() func() ([]byte, error) {
data, err := decodeSpec()
return func() ([]byte, error) {
return data, err
}
}
// Constructs a synthetic filesystem for resolving external references when loading openapi specifications.
func PathToRawSpec(pathToFile string) map[string]func() ([]byte, error) {
var res = make(map[string]func() ([]byte, error))
if len(pathToFile) > 0 {
res[pathToFile] = rawSpec
}
return swagger, nil
{{ if .ImportMapping }}
pathPrefix := path.Dir(pathToFile)
{{ end }}
{{ range $key, $value := .ImportMapping }}
for rawPath, rawFunc := range {{ $value.Name }}.PathToRawSpec(path.Join(pathPrefix, "{{ $key }}")) {
if _, ok := res[rawPath]; ok {
// it is not possible to compare functions in golang, so always overwrite the old value
}
res[rawPath] = rawFunc
}
{{- end }}
return res
}
// GetSwagger returns the Swagger specification corresponding to the generated code
// in this file. The external references of Swagger specification are resolved.
// The logic of resolving external references is tightly connected to "import-mapping" feature.
// Externally referenced files must be embedded in the corresponding golang packages.
// Urls can be supported but this task was out of the scope.
func GetSwagger() (swagger *openapi3.T, err error) {
var resolvePath = PathToRawSpec("")
loader := openapi3.NewLoader()
loader.IsExternalRefsAllowed = true
loader.ReadFromURIFunc = func(loader *openapi3.Loader, url *url.URL) ([]byte, error) {
var pathToFile = url.String()
pathToFile = path.Clean(pathToFile)
getSpec, ok := resolvePath[pathToFile]
if !ok {
err1 := fmt.Errorf("path not found: %s", pathToFile)
return nil, err1
}
return getSpec()
}
var specData []byte
specData, err = rawSpec()
if err != nil {
return
}
swagger, err = loader.LoadFromData(specData)
if err != nil {
return
}
return
}
`,
"param-types.tmpl": `{{range .}}{{$opid := .OperationId}}
{{range .TypeDefinitions}}
// {{.TypeName}} defines parameters for {{$opid}}.
type {{.TypeName}} {{.Schema.TypeDecl}}
type {{.TypeName}} {{if and (opts.AliasTypes) (.CanAlias)}}={{end}} {{.Schema.TypeDecl}}
{{end}}
{{end}}
`,
@ -724,19 +873,27 @@ type EchoRouter interface {
// RegisterHandlers adds each server route to the EchoRouter.
func RegisterHandlers(router EchoRouter, si ServerInterface) {
RegisterHandlersWithBaseURL(router, si, "")
}
// Registers handlers, and prepends BaseURL to the paths, so that the paths
// can be served under a prefix.
func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL string) {
{{if .}}
wrapper := ServerInterfaceWrapper{
Handler: si,
}
{{end}}
{{range .}}router.{{.Method}}("{{.Path | swaggerUriToEchoUri}}", wrapper.{{.OperationId}})
{{range .}}router.{{.Method}}(baseURL + "{{.Path | swaggerUriToEchoUri}}", wrapper.{{.OperationId}})
{{end}}
}
`,
"request-bodies.tmpl": `{{range .}}{{$opid := .OperationId}}
{{range .Bodies}}
// {{$opid}}RequestBody defines body for {{$opid}} for application/json ContentType.
type {{$opid}}{{.NameTag}}RequestBody {{.TypeDef}}
{{with .TypeDef $opid}}
// {{.TypeName}} defines body for {{$opid}} for application/json ContentType.
type {{.TypeName}} {{if and (opts.AliasTypes) (.CanAlias)}}={{end}} {{.Schema.TypeDecl}}
{{end}}
{{end}}
{{end}}
`,
@ -749,17 +906,8 @@ type ServerInterface interface {
}
`,
"typedef.tmpl": `{{range .Types}}
// {{.TypeName}} defines model for {{.JsonName}}.
type {{.TypeName}} {{.Schema.TypeDecl}}
{{- if gt (len .Schema.EnumValues) 0 }}
// List of {{ .TypeName }}
const (
{{- $typeName := .TypeName }}
{{- range $key, $value := .Schema.EnumValues }}
{{ $typeName }}_{{ $key }} {{ $typeName }} = "{{ $value }}"
{{- end }}
)
{{- end }}
{{ with .Schema.Description }}{{ . }}{{ else }}// {{.TypeName}} defines model for {{.JsonName}}.{{ end }}
type {{.TypeName}} {{if and (opts.AliasTypes) (.CanAlias)}}={{end}} {{.Schema.TypeDecl}}
{{end}}
`,
"wrappers.tmpl": `// ServerInterfaceWrapper converts echo contexts to parameters.
@ -782,7 +930,7 @@ func (w *ServerInterfaceWrapper) {{.OperationId}} (ctx echo.Context) error {
}
{{end}}
{{if .IsStyled}}
err = runtime.BindStyledParameter("{{.Style}}",{{.Explode}}, "{{.ParamName}}", ctx.Param("{{.ParamName}}"), &{{$varName}})
err = runtime.BindStyledParameterWithLocation("{{.Style}}",{{.Explode}}, "{{.ParamName}}", runtime.ParamLocationPath, ctx.Param("{{.ParamName}}"), &{{$varName}})
if err != nil {
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter {{.ParamName}}: %s", err))
}
@ -790,7 +938,7 @@ func (w *ServerInterfaceWrapper) {{.OperationId}} (ctx echo.Context) error {
{{end}}
{{range .SecurityDefinitions}}
ctx.Set("{{.ProviderName}}.Scopes", {{toStringArray .Scopes}})
ctx.Set({{.ProviderName | sanitizeGoIdentity | ucFirst}}Scopes, {{toStringArray .Scopes}})
{{end}}
{{if .RequiresParamObject}}
@ -840,7 +988,7 @@ func (w *ServerInterfaceWrapper) {{.OperationId}} (ctx echo.Context) error {
}
{{end}}
{{if .IsStyled}}
err = runtime.BindStyledParameter("{{.Style}}",{{.Explode}}, "{{.ParamName}}", valueList[0], &{{.GoName}})
err = runtime.BindStyledParameterWithLocation("{{.Style}}",{{.Explode}}, "{{.ParamName}}", runtime.ParamLocationHeader, valueList[0], &{{.GoName}})
if err != nil {
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter {{.ParamName}}: %s", err))
}
@ -872,7 +1020,7 @@ func (w *ServerInterfaceWrapper) {{.OperationId}} (ctx echo.Context) error {
{{end}}
{{if .IsStyled}}
var value {{.TypeDef}}
err = runtime.BindStyledParameter("simple",{{.Explode}}, "{{.ParamName}}", cookie.Value, &value)
err = runtime.BindStyledParameterWithLocation("simple",{{.Explode}}, "{{.ParamName}}", runtime.ParamLocationCookie, cookie.Value, &value)
if err != nil {
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter {{.ParamName}}: %s", err))
}

View file

@ -1,13 +1,4 @@
{{range .Types}}
// {{.TypeName}} defines model for {{.JsonName}}.
type {{.TypeName}} {{.Schema.TypeDecl}}
{{- if gt (len .Schema.EnumValues) 0 }}
// List of {{ .TypeName }}
const (
{{- $typeName := .TypeName }}
{{- range $key, $value := .Schema.EnumValues }}
{{ $typeName }}_{{ $key }} {{ $typeName }} = "{{ $value }}"
{{- end }}
)
{{- end }}
{{ with .Schema.Description }}{{ . }}{{ else }}// {{.TypeName}} defines model for {{.JsonName}}.{{ end }}
type {{.TypeName}} {{if and (opts.AliasTypes) (.CanAlias)}}={{end}} {{.Schema.TypeDecl}}
{{end}}

View file

@ -18,7 +18,7 @@ func (w *ServerInterfaceWrapper) {{.OperationId}} (ctx echo.Context) error {
}
{{end}}
{{if .IsStyled}}
err = runtime.BindStyledParameter("{{.Style}}",{{.Explode}}, "{{.ParamName}}", ctx.Param("{{.ParamName}}"), &{{$varName}})
err = runtime.BindStyledParameterWithLocation("{{.Style}}",{{.Explode}}, "{{.ParamName}}", runtime.ParamLocationPath, ctx.Param("{{.ParamName}}"), &{{$varName}})
if err != nil {
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter {{.ParamName}}: %s", err))
}
@ -26,7 +26,7 @@ func (w *ServerInterfaceWrapper) {{.OperationId}} (ctx echo.Context) error {
{{end}}
{{range .SecurityDefinitions}}
ctx.Set("{{.ProviderName}}.Scopes", {{toStringArray .Scopes}})
ctx.Set({{.ProviderName | sanitizeGoIdentity | ucFirst}}Scopes, {{toStringArray .Scopes}})
{{end}}
{{if .RequiresParamObject}}
@ -76,7 +76,7 @@ func (w *ServerInterfaceWrapper) {{.OperationId}} (ctx echo.Context) error {
}
{{end}}
{{if .IsStyled}}
err = runtime.BindStyledParameter("{{.Style}}",{{.Explode}}, "{{.ParamName}}", valueList[0], &{{.GoName}})
err = runtime.BindStyledParameterWithLocation("{{.Style}}",{{.Explode}}, "{{.ParamName}}", runtime.ParamLocationHeader, valueList[0], &{{.GoName}})
if err != nil {
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter {{.ParamName}}: %s", err))
}
@ -108,7 +108,7 @@ func (w *ServerInterfaceWrapper) {{.OperationId}} (ctx echo.Context) error {
{{end}}
{{if .IsStyled}}
var value {{.TypeDef}}
err = runtime.BindStyledParameter("simple",{{.Explode}}, "{{.ParamName}}", cookie.Value, &value)
err = runtime.BindStyledParameterWithLocation("simple",{{.Explode}}, "{{.ParamName}}", runtime.ParamLocationCookie, cookie.Value, &value)
if err != nil {
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter {{.ParamName}}: %s", err))
}

View file

@ -15,6 +15,7 @@ package codegen
import (
"fmt"
"net/url"
"regexp"
"sort"
"strconv"
@ -182,6 +183,17 @@ func SortedRequestBodyKeys(dict map[string]*openapi3.RequestBodyRef) []string {
return keys
}
func SortedSecurityRequirementKeys(sr openapi3.SecurityRequirement) []string {
keys := make([]string, len(sr))
i := 0
for key := range sr {
keys[i] = key
i++
}
sort.Strings(keys)
return keys
}
// This function checks whether the specified string is present in an array
// of strings
func StringInArray(str string, array []string) bool {
@ -198,15 +210,25 @@ func StringInArray(str string, array []string) bool {
// #/components/parameters/Bar -> Bar
// #/components/responses/Baz -> Baz
// Remote components (document.json#/Foo) are supported if they present in --import-mapping
// URL components (http://deepmap.com/schemas/document.json#Foo) are supported if they present in --import-mapping
//
// URL components (http://deepmap.com/schemas/document.json#/Foo) are supported if they present in --import-mapping
// Remote and URL also support standard local paths even though the spec doesn't mention them.
func RefPathToGoType(refPath string) (string, error) {
return refPathToGoType(refPath, true)
}
// refPathToGoType returns the Go typename for refPath given its
func refPathToGoType(refPath string, local bool) (string, error) {
if refPath[0] == '#' {
pathParts := strings.Split(refPath, "/")
if depth := len(pathParts); depth != 4 {
return "", fmt.Errorf("Parameter nesting is deeper than supported: %s has %d", refPath, depth)
depth := len(pathParts)
if local {
if depth != 4 {
return "", fmt.Errorf("unexpected reference depth: %d for ref: %s local: %t", depth, refPath, local)
}
} else if depth != 4 && depth != 2 {
return "", fmt.Errorf("unexpected reference depth: %d for ref: %s local: %t", depth, refPath, local)
}
return SchemaNameToTypeName(pathParts[3]), nil
return SchemaNameToTypeName(pathParts[len(pathParts)-1]), nil
}
pathParts := strings.Split(refPath, "#")
if len(pathParts) != 2 {
@ -216,14 +238,35 @@ func RefPathToGoType(refPath string) (string, error) {
if goImport, ok := importMapping[remoteComponent]; !ok {
return "", fmt.Errorf("unrecognized external reference '%s'; please provide the known import for this reference using option --import-mapping", remoteComponent)
} else {
goType, err := RefPathToGoType("#" + flatComponent)
goType, err := refPathToGoType("#"+flatComponent, false)
if err != nil {
return "", err
}
return fmt.Sprintf("%s.%s", goImport.alias, goType), nil
return fmt.Sprintf("%s.%s", goImport.Name, goType), nil
}
}
// This function takes a $ref value and checks if it has link to go type.
// #/components/schemas/Foo -> true
// ./local/file.yml#/components/parameters/Bar -> true
// ./local/file.yml -> false
// The function can be used to check whether RefPathToGoType($ref) is possible.
//
func IsGoTypeReference(ref string) bool {
return ref != "" && !IsWholeDocumentReference(ref)
}
// This function takes a $ref value and checks if it is whole document reference.
// #/components/schemas/Foo -> false
// ./local/file.yml#/components/parameters/Bar -> false
// ./local/file.yml -> true
// http://deepmap.com/schemas/document.json -> true
// http://deepmap.com/schemas/document.json#/Foo -> false
//
func IsWholeDocumentReference(ref string) bool {
return ref != "" && !strings.ContainsAny(ref, "#")
}
// This function converts a swagger style path URI with parameters to a
// Echo compatible path URI. We need to replace all of Swagger parameters with
// ":param". Valid input parameters are:
@ -265,7 +308,7 @@ func OrderedParamsFromUri(uri string) []string {
return result
}
// Replaces path parameters with %s
// Replaces path parameters of the form {param} with %s
func ReplacePathParamsWithStr(uri string) string {
return pathParamRE.ReplaceAllString(uri, "%s")
}
@ -456,7 +499,6 @@ func SanitizeEnumNames(enumNames []string) map[string]string {
if _, dup := dupCheck[n]; !dup {
deDup = append(deDup, n)
}
dupCheck[n] = 0
}
@ -464,14 +506,14 @@ func SanitizeEnumNames(enumNames []string) map[string]string {
sanitizedDeDup := make(map[string]string, len(deDup))
for _, n := range deDup {
sanitized := SanitizeGoIdentity(n)
sanitized := SanitizeGoIdentity(SchemaNameToTypeName(n))
if _, dup := dupCheck[sanitized]; !dup {
sanitizedDeDup[sanitized] = n
dupCheck[sanitized]++
} else {
sanitizedDeDup[sanitized+strconv.Itoa(dupCheck[sanitized])] = n
}
dupCheck[sanitized]++
}
return sanitizedDeDup
@ -480,10 +522,14 @@ func SanitizeEnumNames(enumNames []string) map[string]string {
// Converts a Schema name to a valid Go type name. It converts to camel case, and makes sure the name is
// valid in Go
func SchemaNameToTypeName(name string) string {
name = ToCamelCase(name)
// Prepend "N" to schemas starting with a number
if name != "" && unicode.IsDigit([]rune(name)[0]) {
name = "N" + name
if name == "$" {
name = "DollarSign"
} else {
name = ToCamelCase(name)
// Prepend "N" to schemas starting with a number
if name != "" && unicode.IsDigit([]rune(name)[0]) {
name = "N" + name
}
}
return name
}
@ -495,9 +541,10 @@ func SchemaNameToTypeName(name string) string {
// you must specify an additionalProperties type
// If additionalProperties it true/false, this field will be non-nil.
func SchemaHasAdditionalProperties(schema *openapi3.Schema) bool {
if schema.AdditionalPropertiesAllowed != nil {
return *schema.AdditionalPropertiesAllowed
if schema.AdditionalPropertiesAllowed != nil && *schema.AdditionalPropertiesAllowed {
return true
}
if schema.AdditionalProperties != nil {
return true
}
@ -516,6 +563,10 @@ func PathToTypeName(path []string) string {
// StringToGoComment renders a possible multi-line string as a valid Go-Comment.
// Each line is prefixed as a comment.
func StringToGoComment(in string) string {
if len(in) == 0 || len(strings.TrimSpace(in)) == 0 { // ignore empty comment
return ""
}
// Normalize newlines from Windows/Mac to Linux
in = strings.Replace(in, "\r\n", "\n", -1)
in = strings.Replace(in, "\r", "\n", -1)
@ -532,3 +583,17 @@ func StringToGoComment(in string) string {
in = strings.TrimSuffix(in, "\n// ")
return in
}
// This function breaks apart a path, and looks at each element. If it's
// not a path parameter, eg, {param}, it will URL-escape the element.
func EscapePathElements(path string) string {
elems := strings.Split(path, "/")
for i, e := range elems {
if strings.HasPrefix(e, "{") && strings.HasSuffix(e, "}") {
// This is a path parameter, we don't want to mess with its value
continue
}
elems[i] = url.QueryEscape(e)
}
return strings.Join(elems, "/")
}

View file

@ -0,0 +1,24 @@
// Copyright 2021 DeepMap, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package runtime
// Binder is the interface implemented by types that can be bound to a query string or a parameter string
// The input can be assumed to be a valid string. If you define a Bind method you are responsible for all
// data being completely bound to the type.
//
// By convention, to approximate the behavior of Bind functions themselves,
// Binder implements Bind("") as a no-op.
type Binder interface {
Bind(src string) error
}

View file

@ -14,6 +14,7 @@
package runtime
import (
"encoding"
"encoding/json"
"fmt"
"net/url"
@ -29,13 +30,51 @@ import (
// This function binds a parameter as described in the Path Parameters
// section here to a Go object:
// https://swagger.io/docs/specification/serialization/
// It is a backward compatible function to clients generated with codegen
// up to version v1.5.5. v1.5.6+ calls the function below.
func BindStyledParameter(style string, explode bool, paramName string,
value string, dest interface{}) error {
return BindStyledParameterWithLocation(style, explode, paramName, ParamLocationUndefined, value, dest)
}
// This function binds a parameter as described in the Path Parameters
// section here to a Go object:
// https://swagger.io/docs/specification/serialization/
func BindStyledParameterWithLocation(style string, explode bool, paramName string,
paramLocation ParamLocation, value string, dest interface{}) error {
if value == "" {
return fmt.Errorf("parameter '%s' is empty, can't bind its value", paramName)
}
// Based on the location of the parameter, we need to unescape it properly.
var err error
switch paramLocation {
case ParamLocationQuery, ParamLocationUndefined:
// We unescape undefined parameter locations here for older generated code,
// since prior to this refactoring, they always query unescaped.
value, err = url.QueryUnescape(value)
if err != nil {
return fmt.Errorf("error unescaping query parameter '%s': %v", paramName, err)
}
case ParamLocationPath:
value, err = url.PathUnescape(value)
if err != nil {
return fmt.Errorf("error unescaping path parameter '%s': %v", paramName, err)
}
default:
// Headers and cookies aren't escaped.
}
// If the destination implements encoding.TextUnmarshaler we use it for binding
if tu, ok := dest.(encoding.TextUnmarshaler); ok {
if err := tu.UnmarshalText([]byte(value)); err != nil {
return fmt.Errorf("error unmarshaling '%s' text as %T: %s", value, dest, err)
}
return nil
}
// Everything comes in by pointer, dereference it
v := reflect.Indirect(reflect.ValueOf(dest))
@ -395,22 +434,15 @@ func BindQueryParameter(style string, explode bool, required bool, paramName str
// We don't try to be smart here, if the field exists as a query argument,
// set its value.
func bindParamsToExplodedObject(paramName string, values url.Values, dest interface{}) error {
// special handling for custom types
switch dest.(type) {
case *types.Date:
// Dereference pointers to their destination values
binder, v, t := indirect(dest)
if binder != nil {
return BindStringToObject(values.Get(paramName), dest)
case *time.Time:
return BindStringToObject(values.Get(paramName), dest)
}
v := reflect.Indirect(reflect.ValueOf(dest))
if v.Type().Kind() != reflect.Struct {
if t.Kind() != reflect.Struct {
return fmt.Errorf("unmarshaling query arg '%s' into wrong type", paramName)
}
t := v.Type()
for i := 0; i < t.NumField(); i++ {
fieldT := t.Field(i)
@ -445,3 +477,26 @@ func bindParamsToExplodedObject(paramName string, values url.Values, dest interf
}
return nil
}
// indirect
func indirect(dest interface{}) (interface{}, reflect.Value, reflect.Type) {
v := reflect.ValueOf(dest)
if v.Type().NumMethod() > 0 && v.CanInterface() {
if u, ok := v.Interface().(Binder); ok {
return u, reflect.Value{}, nil
}
}
v = reflect.Indirect(v)
t := v.Type()
// special handling for custom types which might look like an object. We
// don't want to use object binding on them, but rather treat them as
// primitive types. time.Time{} is a unique case since we can't add a Binder
// to it without changing the underlying generated code.
if t.ConvertibleTo(reflect.TypeOf(time.Time{})) {
return dest, reflect.Value{}, nil
}
if t.ConvertibleTo(reflect.TypeOf(types.Date{})) {
return dest, reflect.Value{}, nil
}
return nil, v, t
}

View file

@ -76,8 +76,12 @@ func BindStringToObject(src string, dst interface{}) error {
v.SetBool(val)
}
case reflect.Struct:
switch dstType := dst.(type) {
case *time.Time:
// if this is not of type Time or of type Date look to see if this is of type Binder.
if dstType, ok := dst.(Binder); ok {
return dstType.Bind(src)
}
if t.ConvertibleTo(reflect.TypeOf(time.Time{})) {
// Don't fail on empty string.
if src == "" {
return nil
@ -90,9 +94,20 @@ func BindStringToObject(src string, dst interface{}) error {
return fmt.Errorf("error parsing '%s' as RFC3339 or 2006-01-02 time: %s", src, err)
}
}
*dstType = parsedTime
// So, assigning this gets a little fun. We have a value to the
// dereference destination. We can't do a conversion to
// time.Time because the result isn't assignable, so we need to
// convert pointers.
if t != reflect.TypeOf(time.Time{}) {
vPtr := v.Addr()
vtPtr := vPtr.Convert(reflect.TypeOf(&time.Time{}))
v = reflect.Indirect(vtPtr)
}
v.Set(reflect.ValueOf(parsedTime))
return nil
case *types.Date:
}
if t.ConvertibleTo(reflect.TypeOf(types.Date{})) {
// Don't fail on empty string.
if src == "" {
return nil
@ -101,9 +116,21 @@ func BindStringToObject(src string, dst interface{}) error {
if err != nil {
return fmt.Errorf("error parsing '%s' as date: %s", src, err)
}
dstType.Time = parsedTime
parsedDate := types.Date{Time: parsedTime}
// We have to do the same dance here to assign, just like with times
// above.
if t != reflect.TypeOf(types.Date{}) {
vPtr := v.Addr()
vtPtr := vPtr.Convert(reflect.TypeOf(&types.Date{}))
v = reflect.Indirect(vtPtr)
}
v.Set(reflect.ValueOf(parsedDate))
return nil
}
// We fall through to the error case below if we haven't handled the
// destination type above.
fallthrough
default:
// We've got a bunch of types unimplemented, don't fail silently.

View file

@ -3,6 +3,7 @@ package runtime
import (
"encoding/json"
"fmt"
"github.com/deepmap/oapi-codegen/pkg/types"
"net/url"
"reflect"
"sort"
@ -11,8 +12,6 @@ import (
"time"
"github.com/pkg/errors"
"github.com/deepmap/oapi-codegen/pkg/types"
)
func marshalDeepObject(in interface{}, path []string) ([]string, error) {
@ -212,26 +211,52 @@ func assignPathValues(dst interface{}, pathValues fieldOrValue) error {
return nil
case reflect.Struct:
// Some special types we care about are structs. Handle them
// here.
if _, isDate := iv.Interface().(types.Date); isDate {
// here. They may be redefined, so we need to do some hoop
// jumping. If the types are aliased, we need to type convert
// the pointer, then set the value of the dereference pointer.
// We check to see if the object implements the Binder interface first.
if dst, isBinder := v.Interface().(Binder); isBinder {
return dst.Bind(pathValues.value)
}
// Then check the legacy types
if it.ConvertibleTo(reflect.TypeOf(types.Date{})) {
var date types.Date
var err error
date.Time, err = time.Parse(types.DateFormat, pathValues.value)
if err != nil {
return errors.Wrap(err, "invalid date format")
}
iv.Set(reflect.ValueOf(date))
dst := iv
if it != reflect.TypeOf(types.Date{}) {
// Types are aliased, convert the pointers.
ivPtr := iv.Addr()
aPtr := ivPtr.Convert(reflect.TypeOf(&types.Date{}))
dst = reflect.Indirect(aPtr)
}
dst.Set(reflect.ValueOf(date))
}
if _, isTime := iv.Interface().(time.Time); isTime {
if it.ConvertibleTo(reflect.TypeOf(time.Time{})) {
var tm time.Time
var err error
tm, err = time.Parse(types.DateFormat, pathValues.value)
tm, err = time.Parse(time.RFC3339Nano, pathValues.value)
if err != nil {
// Fall back to parsing it as a date.
tm, err = time.Parse(types.DateFormat, pathValues.value)
if err != nil {
return fmt.Errorf("error parsing tim as RFC3339 or 2006-01-02 time: %s", err)
}
return errors.Wrap(err, "invalid date format")
}
iv.Set(reflect.ValueOf(tm))
dst := iv
if it != reflect.TypeOf(time.Time{}) {
// Types are aliased, convert the pointers.
ivPtr := iv.Addr()
aPtr := ivPtr.Convert(reflect.TypeOf(&time.Time{}))
dst = reflect.Indirect(aPtr)
}
dst.Set(reflect.ValueOf(tm))
}
fieldMap, err := fieldIndicesByJsonTag(iv.Interface())
if err != nil {
return errors.Wrap(err, "failed enumerating fields")
@ -311,9 +336,9 @@ func assignSlice(dst reflect.Value, pathValues fieldOrValue) error {
// This could be cleaner, but we can call into assignPathValues to
// avoid recreating this logic.
for i:=0; i < nValues; i++ {
for i := 0; i < nValues; i++ {
dstElem := dst.Index(i).Addr()
err := assignPathValues(dstElem.Interface(), fieldOrValue{value:values[i]})
err := assignPathValues(dstElem.Interface(), fieldOrValue{value: values[i]})
if err != nil {
return errors.Wrap(err, "error binding array")
}

View file

@ -14,18 +14,42 @@
package runtime
import (
"errors"
"fmt"
"net/url"
"reflect"
"sort"
"strconv"
"strings"
"time"
"github.com/pkg/errors"
"github.com/deepmap/oapi-codegen/pkg/types"
)
// Given an input value, such as a primitive type, array or object, turn it
// into a parameter based on style/explode definition.
// Parameter escaping works differently based on where a header is found
type ParamLocation int
const (
ParamLocationUndefined ParamLocation = iota
ParamLocationQuery
ParamLocationPath
ParamLocationHeader
ParamLocationCookie
)
// This function is used by older generated code, and must remain compatible
// with that code. It is not to be used in new templates. Please see the
// function below, which can specialize its output based on the location of
// the parameter.
func StyleParam(style string, explode bool, paramName string, value interface{}) (string, error) {
return StyleParamWithLocation(style, explode, paramName, ParamLocationUndefined, value)
}
// Given an input value, such as a primitive type, array or object, turn it
// into a parameter based on style/explode definition, performing whatever
// escaping is necessary based on parameter location
func StyleParamWithLocation(style string, explode bool, paramName string, paramLocation ParamLocation, value interface{}) (string, error) {
t := reflect.TypeOf(value)
v := reflect.ValueOf(value)
@ -46,17 +70,17 @@ func StyleParam(style string, explode bool, paramName string, value interface{})
for i := 0; i < n; i++ {
sliceVal[i] = v.Index(i).Interface()
}
return styleSlice(style, explode, paramName, sliceVal)
return styleSlice(style, explode, paramName, paramLocation, sliceVal)
case reflect.Struct:
return styleStruct(style, explode, paramName, value)
return styleStruct(style, explode, paramName, paramLocation, value)
case reflect.Map:
return styleMap(style, explode, paramName, value)
return styleMap(style, explode, paramName, paramLocation, value)
default:
return stylePrimitive(style, explode, paramName, value)
return stylePrimitive(style, explode, paramName, paramLocation, value)
}
}
func styleSlice(style string, explode bool, paramName string, values []interface{}) (string, error) {
func styleSlice(style string, explode bool, paramName string, paramLocation ParamLocation, values []interface{}) (string, error) {
if style == "deepObject" {
if !explode {
return "", errors.New("deepObjects must be exploded")
@ -111,9 +135,12 @@ func styleSlice(style string, explode bool, paramName string, values []interface
// We're going to assume here that the array is one of simple types.
var err error
var part string
parts := make([]string, len(values))
for i, v := range values {
parts[i], err = primitiveToString(v)
part, err = primitiveToString(v)
part = escapeParameterString(part, paramLocation)
parts[i] = part
if err != nil {
return "", fmt.Errorf("error formatting '%s': %s", paramName, err)
}
@ -132,24 +159,35 @@ func sortedKeys(strMap map[string]string) []string {
return keys
}
// This is a special case. The struct may be a date or time, in
// which case, marshal it in correct format.
func marshalDateTimeValue(value interface{}) (string, bool) {
v := reflect.Indirect(reflect.ValueOf(value))
t := v.Type()
// This is a special case. The struct may be a time, in which case, marshal
// it in RFC3339 format.
func marshalTimeValue(value interface{}) (string, bool) {
if timeVal, ok := value.(*time.Time); ok {
if t.ConvertibleTo(reflect.TypeOf(time.Time{})) {
tt := v.Convert(reflect.TypeOf(time.Time{}))
timeVal := tt.Interface().(time.Time)
return timeVal.Format(time.RFC3339Nano), true
}
if timeVal, ok := value.(time.Time); ok {
return timeVal.Format(time.RFC3339Nano), true
if t.ConvertibleTo(reflect.TypeOf(types.Date{})) {
d := v.Convert(reflect.TypeOf(types.Date{}))
dateVal := d.Interface().(types.Date)
return dateVal.Format(types.DateFormat), true
}
return "", false
}
func styleStruct(style string, explode bool, paramName string, value interface{}) (string, error) {
if timeVal, ok := marshalTimeValue(value); ok {
return stylePrimitive(style, explode, paramName, timeVal)
func styleStruct(style string, explode bool, paramName string, paramLocation ParamLocation, value interface{}) (string, error) {
if timeVal, ok := marshalDateTimeValue(value); ok {
styledVal, err := stylePrimitive(style, explode, paramName, paramLocation, timeVal)
if err != nil {
return "", errors.Wrap(err, "failed to style time")
}
return styledVal, nil
}
if style == "deepObject" {
@ -191,10 +229,10 @@ func styleStruct(style string, explode bool, paramName string, value interface{}
fieldDict[fieldName] = str
}
return processFieldDict(style, explode, paramName, fieldDict)
return processFieldDict(style, explode, paramName, paramLocation, fieldDict)
}
func styleMap(style string, explode bool, paramName string, value interface{}) (string, error) {
func styleMap(style string, explode bool, paramName string, paramLocation ParamLocation, value interface{}) (string, error) {
if style == "deepObject" {
if !explode {
return "", errors.New("deepObjects must be exploded")
@ -215,11 +253,10 @@ func styleMap(style string, explode bool, paramName string, value interface{}) (
}
fieldDict[fieldName] = str
}
return processFieldDict(style, explode, paramName, fieldDict)
return processFieldDict(style, explode, paramName, paramLocation, fieldDict)
}
func processFieldDict(style string, explode bool, paramName string, fieldDict map[string]string) (string, error) {
func processFieldDict(style string, explode bool, paramName string, paramLocation ParamLocation, fieldDict map[string]string) (string, error) {
var parts []string
// This works for everything except deepObject. We'll handle that one
@ -227,12 +264,12 @@ func processFieldDict(style string, explode bool, paramName string, fieldDict ma
if style != "deepObject" {
if explode {
for _, k := range sortedKeys(fieldDict) {
v := fieldDict[k]
v := escapeParameterString(fieldDict[k], paramLocation)
parts = append(parts, k+"="+v)
}
} else {
for _, k := range sortedKeys(fieldDict) {
v := fieldDict[k]
v := escapeParameterString(fieldDict[k], paramLocation)
parts = append(parts, k)
parts = append(parts, v)
}
@ -286,7 +323,7 @@ func processFieldDict(style string, explode bool, paramName string, fieldDict ma
return prefix + strings.Join(parts, separator), nil
}
func stylePrimitive(style string, explode bool, paramName string, value interface{}) (string, error) {
func stylePrimitive(style string, explode bool, paramName string, paramLocation ParamLocation, value interface{}) (string, error) {
strVal, err := primitiveToString(value)
if err != nil {
return "", err
@ -304,7 +341,7 @@ func stylePrimitive(style string, explode bool, paramName string, value interfac
default:
return "", fmt.Errorf("unsupported style '%s'", style)
}
return prefix + strVal, nil
return prefix + escapeParameterString(strVal, paramLocation), nil
}
// Converts a primitive value to a string. We need to do this based on the
@ -320,8 +357,10 @@ func primitiveToString(value interface{}) (string, error) {
switch kind {
case reflect.Int8, reflect.Int32, reflect.Int64, reflect.Int:
output = strconv.FormatInt(v.Int(), 10)
case reflect.Float32, reflect.Float64:
case reflect.Float64:
output = strconv.FormatFloat(v.Float(), 'f', -1, 64)
case reflect.Float32:
output = strconv.FormatFloat(v.Float(), 'f', -1, 32)
case reflect.Bool:
if v.Bool() {
output = "true"
@ -335,3 +374,17 @@ func primitiveToString(value interface{}) (string, error) {
}
return output, nil
}
// This function escapes a parameter value bas on the location of that parameter.
// Query params and path params need different kinds of escaping, while header
// and cookie params seem not to need escaping.
func escapeParameterString(value string, paramLocation ParamLocation) string {
switch paramLocation {
case ParamLocationQuery:
return url.QueryEscape(value)
case ParamLocationPath:
return url.PathEscape(value)
default:
return value
}
}

View file

@ -28,10 +28,29 @@ func ParseCommandlineMap(src string) (map[string]string, error) {
return result, nil
}
// ParseCommandLineList parses comma separated string lists which are passed
// in on the command line. Spaces are trimmed off both sides of result
// strings.
func ParseCommandLineList(input string) []string {
input = strings.TrimSpace(input)
if len(input) == 0 {
return nil
}
splitInput := strings.Split(input, ",")
args := make([]string, 0, len(splitInput))
for _, s := range splitInput {
s = strings.TrimSpace(s)
if len(s) > 0 {
args = append(args, s)
}
}
return args
}
// This function splits a string along the specifed separator, but it
// ignores anything between double quotes for splitting. We do simple
// inside/outside quote counting. Quotes are not stripped from output.
func splitString(s string, sep rune) ([]string) {
func splitString(s string, sep rune) []string {
const escapeChar rune = '"'
var parts []string
@ -39,7 +58,7 @@ func splitString(s string, sep rune) ([]string) {
inQuotes := false
for _, c := range s {
if c == escapeChar{
if c == escapeChar {
if inQuotes {
inQuotes = false
} else {

View file

@ -6,15 +6,15 @@ import (
"github.com/getkin/kin-openapi/openapi3"
)
func LoadSwagger(filePath string) (swagger *openapi3.Swagger, err error) {
func LoadSwagger(filePath string) (swagger *openapi3.T, err error) {
loader := openapi3.NewSwaggerLoader()
loader := openapi3.NewLoader()
loader.IsExternalRefsAllowed = true
u, err := url.Parse(filePath)
if err == nil && u.Scheme != "" && u.Host != "" {
return loader.LoadSwaggerFromURI(u)
return loader.LoadFromURI(u)
} else {
return loader.LoadSwaggerFromFile(filePath)
return loader.LoadFromFile(filePath)
}
}

View file

@ -63,7 +63,7 @@ iteration:
// Read our custom "multijson" tag that
// allows multiple fields with the same name.
if v := f.Tag.Get("multijson"); len(v) > 0 {
if v := f.Tag.Get("multijson"); v != "" {
field.MultipleFields = true
jsonTag = v
}
@ -74,11 +74,11 @@ iteration:
}
// Parse the tag
if len(jsonTag) > 0 {
if jsonTag != "" {
field.HasJSONTag = true
for i, part := range strings.Split(jsonTag, ",") {
if i == 0 {
if len(part) > 0 {
if part != "" {
field.JSONName = part
}
} else {
@ -92,12 +92,8 @@ iteration:
}
}
if _, ok := field.Type.MethodByName("MarshalJSON"); ok {
field.TypeIsMarshaller = true
}
if _, ok := field.Type.MethodByName("UnmarshalJSON"); ok {
field.TypeIsUnmarshaller = true
}
_, field.TypeIsMarshaller = field.Type.MethodByName("MarshalJSON")
_, field.TypeIsUnmarshaller = field.Type.MethodByName("UnmarshalJSON")
// Field is done
fields = append(fields, field)

View file

@ -59,11 +59,11 @@ func (encoder *ObjectEncoder) EncodeStructFieldsAndExtensions(value interface{})
// Follow "encoding/json" semantics
if reflection.Kind() != reflect.Ptr {
// Panic because this is a clear programming error
panic(fmt.Errorf("Value %s is not a pointer", reflection.Type().String()))
panic(fmt.Errorf("value %s is not a pointer", reflection.Type().String()))
}
if reflection.IsNil() {
// Panic because this is a clear programming error
panic(fmt.Errorf("Value %s is nil", reflection.Type().String()))
panic(fmt.Errorf("value %s is nil", reflection.Type().String()))
}
// Take the element
@ -146,7 +146,7 @@ iteration:
continue iteration
}
default:
panic(fmt.Errorf("Field '%s' has unsupported type %s", field.JSONName, field.Type.String()))
panic(fmt.Errorf("field %q has unsupported type %s", field.JSONName, field.Type.String()))
}
// No special treament is needed

View file

@ -25,7 +25,7 @@ type ObjectDecoder struct {
func NewObjectDecoder(data []byte) (*ObjectDecoder, error) {
var remainingFields map[string]json.RawMessage
if err := json.Unmarshal(data, &remainingFields); err != nil {
return nil, fmt.Errorf("Failed to unmarshal extension properties: %v\nInput: %s", err, data)
return nil, fmt.Errorf("failed to unmarshal extension properties: %v (%s)", err, data)
}
return &ObjectDecoder{
Data: data,
@ -41,10 +41,10 @@ func (decoder *ObjectDecoder) DecodeExtensionMap() map[string]json.RawMessage {
func (decoder *ObjectDecoder) DecodeStructFieldsAndExtensions(value interface{}) error {
reflection := reflect.ValueOf(value)
if reflection.Kind() != reflect.Ptr {
panic(fmt.Errorf("Value %T is not a pointer", value))
panic(fmt.Errorf("value %T is not a pointer", value))
}
if reflection.IsNil() {
panic(fmt.Errorf("Value %T is nil", value))
panic(fmt.Errorf("value %T is nil", value))
}
reflection = reflection.Elem()
for (reflection.Kind() == reflect.Interface || reflection.Kind() == reflect.Ptr) && !reflection.IsNil() {
@ -52,7 +52,7 @@ func (decoder *ObjectDecoder) DecodeStructFieldsAndExtensions(value interface{})
}
reflectionType := reflection.Type()
if reflectionType.Kind() != reflect.Struct {
panic(fmt.Errorf("Value %T is not a struct", value))
panic(fmt.Errorf("value %T is not a struct", value))
}
typeInfo := GetTypeInfo(reflectionType)
@ -87,7 +87,7 @@ func (decoder *ObjectDecoder) DecodeStructFieldsAndExtensions(value interface{})
continue
}
}
return fmt.Errorf("Error while unmarshalling property '%s' (%s): %v",
return fmt.Errorf("failed to unmarshal property %q (%s): %v",
field.JSONName, fieldValue.Type().String(), err)
}
if !isPtr {
@ -109,7 +109,7 @@ func (decoder *ObjectDecoder) DecodeStructFieldsAndExtensions(value interface{})
continue
}
}
return fmt.Errorf("Error while unmarshalling property '%s' (%s): %v",
return fmt.Errorf("failed to unmarshal property %q (%s): %v",
field.JSONName, fieldPtr.Type().String(), err)
}

View file

@ -4,7 +4,6 @@ import (
"encoding/json"
"fmt"
"sort"
"strings"
)
// UnsupportedPropertiesError is a helper for extensions that want to refuse
@ -27,7 +26,7 @@ func (err *UnsupportedPropertiesError) Error() string {
m := err.UnsupportedProperties
typeInfo := GetTypeInfoForValue(err.Value)
if m == nil || typeInfo == nil {
return "Invalid UnsupportedPropertiesError"
return fmt.Sprintf("invalid %T", *err)
}
keys := make([]string, 0, len(m))
for k := range m {
@ -36,10 +35,8 @@ func (err *UnsupportedPropertiesError) Error() string {
sort.Strings(keys)
supported := typeInfo.FieldNames()
if len(supported) == 0 {
return fmt.Sprintf("Type '%T' doesn't take any properties. Unsupported properties: '%s'\n",
err.Value, strings.Join(keys, "', '"))
return fmt.Sprintf("type \"%T\" doesn't take any properties. Unsupported properties: %+v",
err.Value, keys)
}
return fmt.Sprintf("Unsupported properties: '%s'\nSupported properties are: '%s'",
strings.Join(keys, "', '"),
strings.Join(supported, "', '"))
return fmt.Sprintf("unsupported properties: %+v (supported properties are: %+v)", keys, supported)
}

View file

@ -1,13 +1,34 @@
package openapi3
import "context"
import (
"context"
"fmt"
"github.com/go-openapi/jsonpointer"
)
type Callbacks map[string]*CallbackRef
var _ jsonpointer.JSONPointable = (*Callbacks)(nil)
func (c Callbacks) JSONLookup(token string) (interface{}, error) {
ref, ok := c[token]
if ref == nil || !ok {
return nil, fmt.Errorf("object has no field %q", token)
}
if ref.Ref != "" {
return &Ref{Ref: ref.Ref}, nil
}
return ref.Value, nil
}
// Callback is specified by OpenAPI/Swagger standard version 3.0.
type Callback map[string]*PathItem
func (value Callback) Validate(c context.Context) error {
func (value Callback) Validate(ctx context.Context) error {
for _, v := range value {
if err := v.Validate(c); err != nil {
if err := v.Validate(ctx); err != nil {
return err
}
}

View file

@ -11,15 +11,15 @@ import (
// Components is specified by OpenAPI/Swagger standard version 3.0.
type Components struct {
ExtensionProps
Schemas map[string]*SchemaRef `json:"schemas,omitempty" yaml:"schemas,omitempty"`
Parameters map[string]*ParameterRef `json:"parameters,omitempty" yaml:"parameters,omitempty"`
Headers map[string]*HeaderRef `json:"headers,omitempty" yaml:"headers,omitempty"`
RequestBodies map[string]*RequestBodyRef `json:"requestBodies,omitempty" yaml:"requestBodies,omitempty"`
Responses map[string]*ResponseRef `json:"responses,omitempty" yaml:"responses,omitempty"`
SecuritySchemes map[string]*SecuritySchemeRef `json:"securitySchemes,omitempty" yaml:"securitySchemes,omitempty"`
Examples map[string]*ExampleRef `json:"examples,omitempty" yaml:"examples,omitempty"`
Links map[string]*LinkRef `json:"links,omitempty" yaml:"links,omitempty"`
Callbacks map[string]*CallbackRef `json:"callbacks,omitempty" yaml:"callbacks,omitempty"`
Schemas Schemas `json:"schemas,omitempty" yaml:"schemas,omitempty"`
Parameters ParametersMap `json:"parameters,omitempty" yaml:"parameters,omitempty"`
Headers Headers `json:"headers,omitempty" yaml:"headers,omitempty"`
RequestBodies RequestBodies `json:"requestBodies,omitempty" yaml:"requestBodies,omitempty"`
Responses Responses `json:"responses,omitempty" yaml:"responses,omitempty"`
SecuritySchemes SecuritySchemes `json:"securitySchemes,omitempty" yaml:"securitySchemes,omitempty"`
Examples Examples `json:"examples,omitempty" yaml:"examples,omitempty"`
Links Links `json:"links,omitempty" yaml:"links,omitempty"`
Callbacks Callbacks `json:"callbacks,omitempty" yaml:"callbacks,omitempty"`
}
func NewComponents() Components {
@ -34,12 +34,12 @@ func (components *Components) UnmarshalJSON(data []byte) error {
return jsoninfo.UnmarshalStrictStruct(data, components)
}
func (components *Components) Validate(c context.Context) (err error) {
func (components *Components) Validate(ctx context.Context) (err error) {
for k, v := range components.Schemas {
if err = ValidateIdentifier(k); err != nil {
return
}
if err = v.Validate(c); err != nil {
if err = v.Validate(ctx); err != nil {
return
}
}
@ -48,7 +48,7 @@ func (components *Components) Validate(c context.Context) (err error) {
if err = ValidateIdentifier(k); err != nil {
return
}
if err = v.Validate(c); err != nil {
if err = v.Validate(ctx); err != nil {
return
}
}
@ -57,7 +57,7 @@ func (components *Components) Validate(c context.Context) (err error) {
if err = ValidateIdentifier(k); err != nil {
return
}
if err = v.Validate(c); err != nil {
if err = v.Validate(ctx); err != nil {
return
}
}
@ -66,7 +66,7 @@ func (components *Components) Validate(c context.Context) (err error) {
if err = ValidateIdentifier(k); err != nil {
return
}
if err = v.Validate(c); err != nil {
if err = v.Validate(ctx); err != nil {
return
}
}
@ -75,7 +75,7 @@ func (components *Components) Validate(c context.Context) (err error) {
if err = ValidateIdentifier(k); err != nil {
return
}
if err = v.Validate(c); err != nil {
if err = v.Validate(ctx); err != nil {
return
}
}
@ -84,7 +84,7 @@ func (components *Components) Validate(c context.Context) (err error) {
if err = ValidateIdentifier(k); err != nil {
return
}
if err = v.Validate(c); err != nil {
if err = v.Validate(ctx); err != nil {
return
}
}
@ -92,13 +92,16 @@ func (components *Components) Validate(c context.Context) (err error) {
return
}
const identifierPattern = `^[a-zA-Z0-9.\-_]+$`
const identifierPattern = `^[a-zA-Z0-9._-]+$`
var identifierRegExp = regexp.MustCompile(identifierPattern)
// IdentifierRegExp verifies whether Component object key matches 'identifierPattern' pattern, according to OapiAPI v3.x.0.
// Hovever, to be able supporting legacy OpenAPI v2.x, there is a need to customize above pattern in orde not to fail
// converted v2-v3 validation
var IdentifierRegExp = regexp.MustCompile(identifierPattern)
func ValidateIdentifier(value string) error {
if identifierRegExp.MatchString(value) {
if IdentifierRegExp.MatchString(value) {
return nil
}
return fmt.Errorf("Identifier '%s' is not supported by OpenAPI version 3 standard (regexp: '%s')", value, identifierPattern)
return fmt.Errorf("identifier %q is not supported by OpenAPIv3 standard (regexp: %q)", value, identifierPattern)
}

View file

@ -12,6 +12,32 @@ func NewContent() Content {
return make(map[string]*MediaType, 4)
}
func NewContentWithSchema(schema *Schema, consumes []string) Content {
if len(consumes) == 0 {
return Content{
"*/*": NewMediaType().WithSchema(schema),
}
}
content := make(map[string]*MediaType, len(consumes))
for _, mediaType := range consumes {
content[mediaType] = NewMediaType().WithSchema(schema)
}
return content
}
func NewContentWithSchemaRef(schema *SchemaRef, consumes []string) Content {
if len(consumes) == 0 {
return Content{
"*/*": NewMediaType().WithSchemaRef(schema),
}
}
content := make(map[string]*MediaType, len(consumes))
for _, mediaType := range consumes {
content[mediaType] = NewMediaType().WithSchemaRef(schema)
}
return content
}
func NewContentWithJSONSchema(schema *Schema) Content {
return Content{
"application/json": NewMediaType().WithSchema(schema),
@ -23,6 +49,18 @@ func NewContentWithJSONSchemaRef(schema *SchemaRef) Content {
}
}
func NewContentWithFormDataSchema(schema *Schema) Content {
return Content{
"multipart/form-data": NewMediaType().WithSchema(schema),
}
}
func NewContentWithFormDataSchemaRef(schema *SchemaRef) Content {
return Content{
"multipart/form-data": NewMediaType().WithSchemaRef(schema),
}
}
func (content Content) Get(mime string) *MediaType {
// If the mime is empty then short-circuit to the wildcard.
// We do this here so that we catch only the specific case of
@ -66,10 +104,10 @@ func (content Content) Get(mime string) *MediaType {
return content["*/*"]
}
func (content Content) Validate(c context.Context) error {
for _, v := range content {
func (value Content) Validate(ctx context.Context) error {
for _, v := range value {
// Validate MediaType
if err := v.Validate(c); err != nil {
if err := v.Validate(ctx); err != nil {
return err
}
}

View file

@ -21,6 +21,6 @@ func (value *Discriminator) UnmarshalJSON(data []byte) error {
return jsoninfo.UnmarshalStrictStruct(data, value)
}
func (value *Discriminator) Validate(c context.Context) error {
func (value *Discriminator) Validate(ctx context.Context) error {
return nil
}

View file

@ -1,5 +1,4 @@
// Package openapi3 parses and writes OpenAPI 3 specifications.
// Package openapi3 parses and writes OpenAPI 3 specification documents.
//
// The OpenAPI 3.0 specification can be found at:
// https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.md
// See https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md
package openapi3

View file

@ -11,11 +11,11 @@ import (
type Encoding struct {
ExtensionProps
ContentType string `json:"contentType,omitempty" yaml:"contentType,omitempty"`
Headers map[string]*HeaderRef `json:"headers,omitempty" yaml:"headers,omitempty"`
Style string `json:"style,omitempty" yaml:"style,omitempty"`
Explode *bool `json:"explode,omitempty" yaml:"explode,omitempty"`
AllowReserved bool `json:"allowReserved,omitempty" yaml:"allowReserved,omitempty"`
ContentType string `json:"contentType,omitempty" yaml:"contentType,omitempty"`
Headers Headers `json:"headers,omitempty" yaml:"headers,omitempty"`
Style string `json:"style,omitempty" yaml:"style,omitempty"`
Explode *bool `json:"explode,omitempty" yaml:"explode,omitempty"`
AllowReserved bool `json:"allowReserved,omitempty" yaml:"allowReserved,omitempty"`
}
func NewEncoding() *Encoding {
@ -61,21 +61,21 @@ func (encoding *Encoding) SerializationMethod() *SerializationMethod {
return sm
}
func (encoding *Encoding) Validate(c context.Context) error {
if encoding == nil {
func (value *Encoding) Validate(ctx context.Context) error {
if value == nil {
return nil
}
for k, v := range encoding.Headers {
for k, v := range value.Headers {
if err := ValidateIdentifier(k); err != nil {
return nil
}
if err := v.Validate(c); err != nil {
if err := v.Validate(ctx); err != nil {
return nil
}
}
// Validate a media types's serialization method.
sm := encoding.SerializationMethod()
sm := value.SerializationMethod()
switch {
case sm.Style == SerializationForm && sm.Explode,
sm.Style == SerializationForm && !sm.Explode,
@ -86,7 +86,7 @@ func (encoding *Encoding) Validate(c context.Context) error {
sm.Style == SerializationDeepObject && sm.Explode:
// it is a valid
default:
return fmt.Errorf("Serialization method with style=%q and explode=%v is not supported by media type", sm.Style, sm.Explode)
return fmt.Errorf("serialization method with style=%q and explode=%v is not supported by media type", sm.Style, sm.Explode)
}
return nil

View file

@ -0,0 +1,43 @@
package openapi3
import (
"bytes"
"errors"
)
// MultiError is a collection of errors, intended for when
// multiple issues need to be reported upstream
type MultiError []error
func (me MultiError) Error() string {
buff := &bytes.Buffer{}
for _, e := range me {
buff.WriteString(e.Error())
buff.WriteString(" | ")
}
return buff.String()
}
//Is allows you to determine if a generic error is in fact a MultiError using `errors.Is()`
//It will also return true if any of the contained errors match target
func (me MultiError) Is(target error) bool {
if _, ok := target.(MultiError); ok {
return true
}
for _, e := range me {
if errors.Is(e, target) {
return true
}
}
return false
}
//As allows you to use `errors.As()` to set target to the first error within the multi error that matches the target type
func (me MultiError) As(target interface{}) bool {
for _, e := range me {
if errors.As(e, target) {
return true
}
}
return false
}

View file

@ -1,9 +1,29 @@
package openapi3
import (
"context"
"fmt"
"github.com/getkin/kin-openapi/jsoninfo"
"github.com/go-openapi/jsonpointer"
)
type Examples map[string]*ExampleRef
var _ jsonpointer.JSONPointable = (*Examples)(nil)
func (e Examples) JSONLookup(token string) (interface{}, error) {
ref, ok := e[token]
if ref == nil || !ok {
return nil, fmt.Errorf("object has no field %q", token)
}
if ref.Ref != "" {
return &Ref{Ref: ref.Ref}, nil
}
return ref.Value, nil
}
// Example is specified by OpenAPI/Swagger 3.0 standard.
type Example struct {
ExtensionProps
@ -27,3 +47,7 @@ func (example *Example) MarshalJSON() ([]byte, error) {
func (example *Example) UnmarshalJSON(data []byte) error {
return jsoninfo.UnmarshalStrictStruct(data, example)
}
func (value *Example) Validate(ctx context.Context) error {
return nil // TODO
}

View file

@ -2,32 +2,79 @@ package openapi3
import (
"context"
"fmt"
"github.com/getkin/kin-openapi/jsoninfo"
"github.com/go-openapi/jsonpointer"
)
type Headers map[string]*HeaderRef
var _ jsonpointer.JSONPointable = (*Headers)(nil)
func (h Headers) JSONLookup(token string) (interface{}, error) {
ref, ok := h[token]
if ref == nil || !ok {
return nil, fmt.Errorf("object has no field %q", token)
}
if ref.Ref != "" {
return &Ref{Ref: ref.Ref}, nil
}
return ref.Value, nil
}
type Header struct {
ExtensionProps
// Optional description. Should use CommonMark syntax.
Description string `json:"description,omitempty" yaml:"description,omitempty"`
Deprecated bool `json:"deprecated,omitempty" yaml:"deprecated,omitempty"`
Required bool `json:"required,omitempty" yaml:"required,omitempty"`
Schema *SchemaRef `json:"schema,omitempty" yaml:"schema,omitempty"`
Example interface{} `json:"example,omitempty" yaml:"example,omitempty"`
Examples map[string]*ExampleRef `json:"examples,omitempty" yaml:"examples,omitempty"`
Content Content `json:"content,omitempty" yaml:"content,omitempty"`
Description string `json:"description,omitempty" yaml:"description,omitempty"`
Deprecated bool `json:"deprecated,omitempty" yaml:"deprecated,omitempty"`
Required bool `json:"required,omitempty" yaml:"required,omitempty"`
Schema *SchemaRef `json:"schema,omitempty" yaml:"schema,omitempty"`
Example interface{} `json:"example,omitempty" yaml:"example,omitempty"`
Examples Examples `json:"examples,omitempty" yaml:"examples,omitempty"`
Content Content `json:"content,omitempty" yaml:"content,omitempty"`
}
var _ jsonpointer.JSONPointable = (*Header)(nil)
func (value *Header) UnmarshalJSON(data []byte) error {
return jsoninfo.UnmarshalStrictStruct(data, value)
}
func (value *Header) Validate(c context.Context) error {
func (value *Header) Validate(ctx context.Context) error {
if v := value.Schema; v != nil {
if err := v.Validate(c); err != nil {
if err := v.Validate(ctx); err != nil {
return err
}
}
return nil
}
func (value Header) JSONLookup(token string) (interface{}, error) {
switch token {
case "schema":
if value.Schema != nil {
if value.Schema.Ref != "" {
return &Ref{Ref: value.Schema.Ref}, nil
}
return value.Schema.Value, nil
}
case "description":
return value.Description, nil
case "deprecated":
return value.Deprecated, nil
case "required":
return value.Required, nil
case "example":
return value.Example, nil
case "examples":
return value.Examples, nil
case "content":
return value.Content, nil
}
v, _, err := jsonpointer.GetForToken(value.ExtensionProps, token)
return v, err
}

View file

@ -26,25 +26,25 @@ func (value *Info) UnmarshalJSON(data []byte) error {
return jsoninfo.UnmarshalStrictStruct(data, value)
}
func (value *Info) Validate(c context.Context) error {
func (value *Info) Validate(ctx context.Context) error {
if contact := value.Contact; contact != nil {
if err := contact.Validate(c); err != nil {
if err := contact.Validate(ctx); err != nil {
return err
}
}
if license := value.License; license != nil {
if err := license.Validate(c); err != nil {
if err := license.Validate(ctx); err != nil {
return err
}
}
if value.Version == "" {
return errors.New("value of version must be a non-empty JSON string")
return errors.New("value of version must be a non-empty string")
}
if value.Title == "" {
return errors.New("value of title must be a non-empty JSON string")
return errors.New("value of title must be a non-empty string")
}
return nil
@ -66,7 +66,7 @@ func (value *Contact) UnmarshalJSON(data []byte) error {
return jsoninfo.UnmarshalStrictStruct(data, value)
}
func (value *Contact) Validate(c context.Context) error {
func (value *Contact) Validate(ctx context.Context) error {
return nil
}
@ -85,9 +85,9 @@ func (value *License) UnmarshalJSON(data []byte) error {
return jsoninfo.UnmarshalStrictStruct(data, value)
}
func (value *License) Validate(c context.Context) error {
func (value *License) Validate(ctx context.Context) error {
if value.Name == "" {
return errors.New("value of license name must be a non-empty JSON string")
return errors.New("value of license name must be a non-empty string")
}
return nil
}

View file

@ -6,8 +6,25 @@ import (
"fmt"
"github.com/getkin/kin-openapi/jsoninfo"
"github.com/go-openapi/jsonpointer"
)
type Links map[string]*LinkRef
func (l Links) JSONLookup(token string) (interface{}, error) {
ref, ok := l[token]
if ok == false {
return nil, fmt.Errorf("object has no field %q", token)
}
if ref != nil && ref.Ref != "" {
return &Ref{Ref: ref.Ref}, nil
}
return ref.Value, nil
}
var _ jsonpointer.JSONPointable = (*Links)(nil)
// Link is specified by OpenAPI/Swagger standard version 3.0.
type Link struct {
ExtensionProps
@ -27,12 +44,12 @@ func (value *Link) UnmarshalJSON(data []byte) error {
return jsoninfo.UnmarshalStrictStruct(data, value)
}
func (value *Link) Validate(c context.Context) error {
func (value *Link) Validate(ctx context.Context) error {
if value.OperationID == "" && value.OperationRef == "" {
return errors.New("missing operationId or operationRef on link")
}
if value.OperationID != "" && value.OperationRef != "" {
return fmt.Errorf("operationId '%s' and operationRef '%s' are mutually exclusive", value.OperationID, value.OperationRef)
return fmt.Errorf("operationId %q and operationRef %q are mutually exclusive", value.OperationID, value.OperationRef)
}
return nil
}

1012
vendor/github.com/getkin/kin-openapi/openapi3/loader.go generated vendored Normal file

File diff suppressed because it is too large Load diff

View file

@ -4,18 +4,21 @@ import (
"context"
"github.com/getkin/kin-openapi/jsoninfo"
"github.com/go-openapi/jsonpointer"
)
// MediaType is specified by OpenAPI/Swagger 3.0 standard.
type MediaType struct {
ExtensionProps
Schema *SchemaRef `json:"schema,omitempty" yaml:"schema,omitempty"`
Example interface{} `json:"example,omitempty" yaml:"example,omitempty"`
Examples map[string]*ExampleRef `json:"examples,omitempty" yaml:"examples,omitempty"`
Encoding map[string]*Encoding `json:"encoding,omitempty" yaml:"encoding,omitempty"`
Schema *SchemaRef `json:"schema,omitempty" yaml:"schema,omitempty"`
Example interface{} `json:"example,omitempty" yaml:"example,omitempty"`
Examples Examples `json:"examples,omitempty" yaml:"examples,omitempty"`
Encoding map[string]*Encoding `json:"encoding,omitempty" yaml:"encoding,omitempty"`
}
var _ jsonpointer.JSONPointable = (*MediaType)(nil)
func NewMediaType() *MediaType {
return &MediaType{}
}
@ -24,9 +27,7 @@ func (mediaType *MediaType) WithSchema(schema *Schema) *MediaType {
if schema == nil {
mediaType.Schema = nil
} else {
mediaType.Schema = &SchemaRef{
Value: schema,
}
mediaType.Schema = &SchemaRef{Value: schema}
}
return mediaType
}
@ -66,14 +67,34 @@ func (mediaType *MediaType) UnmarshalJSON(data []byte) error {
return jsoninfo.UnmarshalStrictStruct(data, mediaType)
}
func (mediaType *MediaType) Validate(c context.Context) error {
if mediaType == nil {
func (value *MediaType) Validate(ctx context.Context) error {
if value == nil {
return nil
}
if schema := mediaType.Schema; schema != nil {
if err := schema.Validate(c); err != nil {
if schema := value.Schema; schema != nil {
if err := schema.Validate(ctx); err != nil {
return err
}
}
return nil
}
func (mediaType MediaType) JSONLookup(token string) (interface{}, error) {
switch token {
case "schema":
if mediaType.Schema != nil {
if mediaType.Schema.Ref != "" {
return &Ref{Ref: mediaType.Schema.Ref}, nil
}
return mediaType.Schema.Value, nil
}
case "example":
return mediaType.Example, nil
case "examples":
return mediaType.Examples, nil
case "encoding":
return mediaType.Encoding, nil
}
v, _, err := jsonpointer.GetForToken(mediaType.ExtensionProps, token)
return v, err
}

View file

@ -8,7 +8,8 @@ import (
"github.com/getkin/kin-openapi/jsoninfo"
)
type Swagger struct {
// T is the root of an OpenAPI v3 document
type T struct {
ExtensionProps
OpenAPI string `json:"openapi" yaml:"openapi"` // Required
Components Components `json:"components,omitempty" yaml:"components,omitempty"`
@ -20,19 +21,19 @@ type Swagger struct {
ExternalDocs *ExternalDocs `json:"externalDocs,omitempty" yaml:"externalDocs,omitempty"`
}
func (swagger *Swagger) MarshalJSON() ([]byte, error) {
return jsoninfo.MarshalStrictStruct(swagger)
func (doc *T) MarshalJSON() ([]byte, error) {
return jsoninfo.MarshalStrictStruct(doc)
}
func (swagger *Swagger) UnmarshalJSON(data []byte) error {
return jsoninfo.UnmarshalStrictStruct(data, swagger)
func (doc *T) UnmarshalJSON(data []byte) error {
return jsoninfo.UnmarshalStrictStruct(data, doc)
}
func (swagger *Swagger) AddOperation(path string, method string, operation *Operation) {
paths := swagger.Paths
func (doc *T) AddOperation(path string, method string, operation *Operation) {
paths := doc.Paths
if paths == nil {
paths = make(Paths)
swagger.Paths = paths
doc.Paths = paths
}
pathItem := paths[path]
if pathItem == nil {
@ -42,50 +43,50 @@ func (swagger *Swagger) AddOperation(path string, method string, operation *Oper
pathItem.SetOperation(method, operation)
}
func (swagger *Swagger) AddServer(server *Server) {
swagger.Servers = append(swagger.Servers, server)
func (doc *T) AddServer(server *Server) {
doc.Servers = append(doc.Servers, server)
}
func (swagger *Swagger) Validate(c context.Context) error {
if swagger.OpenAPI == "" {
return errors.New("value of openapi must be a non-empty JSON string")
func (value *T) Validate(ctx context.Context) error {
if value.OpenAPI == "" {
return errors.New("value of openapi must be a non-empty string")
}
// NOTE: only mention info/components/paths/... key in this func's errors.
{
wrap := func(e error) error { return fmt.Errorf("invalid components: %v", e) }
if err := swagger.Components.Validate(c); err != nil {
if err := value.Components.Validate(ctx); err != nil {
return wrap(err)
}
}
{
wrap := func(e error) error { return fmt.Errorf("invalid info: %v", e) }
if v := swagger.Info; v != nil {
if err := v.Validate(c); err != nil {
if v := value.Info; v != nil {
if err := v.Validate(ctx); err != nil {
return wrap(err)
}
} else {
return wrap(errors.New("must be a JSON object"))
return wrap(errors.New("must be an object"))
}
}
{
wrap := func(e error) error { return fmt.Errorf("invalid paths: %v", e) }
if v := swagger.Paths; v != nil {
if err := v.Validate(c); err != nil {
if v := value.Paths; v != nil {
if err := v.Validate(ctx); err != nil {
return wrap(err)
}
} else {
return wrap(errors.New("must be a JSON object"))
return wrap(errors.New("must be an object"))
}
}
{
wrap := func(e error) error { return fmt.Errorf("invalid security: %v", e) }
if v := swagger.Security; v != nil {
if err := v.Validate(c); err != nil {
if v := value.Security; v != nil {
if err := v.Validate(ctx); err != nil {
return wrap(err)
}
}
@ -93,8 +94,8 @@ func (swagger *Swagger) Validate(c context.Context) error {
{
wrap := func(e error) error { return fmt.Errorf("invalid servers: %v", e) }
if v := swagger.Servers; v != nil {
if err := v.Validate(c); err != nil {
if v := value.Servers; v != nil {
if err := v.Validate(ctx); err != nil {
return wrap(err)
}
}

View file

@ -6,6 +6,7 @@ import (
"strconv"
"github.com/getkin/kin-openapi/jsoninfo"
"github.com/go-openapi/jsonpointer"
)
// Operation represents "operation" specified by" OpenAPI/Swagger 3.0 standard.
@ -34,7 +35,7 @@ type Operation struct {
Responses Responses `json:"responses" yaml:"responses"` // Required
// Optional callbacks
Callbacks map[string]*CallbackRef `json:"callbacks,omitempty" yaml:"callbacks,omitempty"`
Callbacks Callbacks `json:"callbacks,omitempty" yaml:"callbacks,omitempty"`
Deprecated bool `json:"deprecated,omitempty" yaml:"deprecated,omitempty"`
@ -47,6 +48,8 @@ type Operation struct {
ExternalDocs *ExternalDocs `json:"externalDocs,omitempty" yaml:"externalDocs,omitempty"`
}
var _ jsonpointer.JSONPointable = (*Operation)(nil)
func NewOperation() *Operation {
return &Operation{}
}
@ -59,6 +62,43 @@ func (operation *Operation) UnmarshalJSON(data []byte) error {
return jsoninfo.UnmarshalStrictStruct(data, operation)
}
func (operation Operation) JSONLookup(token string) (interface{}, error) {
switch token {
case "requestBody":
if operation.RequestBody != nil {
if operation.RequestBody.Ref != "" {
return &Ref{Ref: operation.RequestBody.Ref}, nil
}
return operation.RequestBody.Value, nil
}
case "tags":
return operation.Tags, nil
case "summary":
return operation.Summary, nil
case "description":
return operation.Description, nil
case "operationID":
return operation.OperationID, nil
case "parameters":
return operation.Parameters, nil
case "responses":
return operation.Responses, nil
case "callbacks":
return operation.Callbacks, nil
case "deprecated":
return operation.Deprecated, nil
case "security":
return operation.Security, nil
case "servers":
return operation.Servers, nil
case "externalDocs":
return operation.ExternalDocs, nil
}
v, _, err := jsonpointer.GetForToken(operation.ExtensionProps, token)
return v, err
}
func (operation *Operation) AddParameter(p *Parameter) {
operation.Parameters = append(operation.Parameters, &ParameterRef{
Value: p,
@ -80,23 +120,23 @@ func (operation *Operation) AddResponse(status int, response *Response) {
}
}
func (operation *Operation) Validate(c context.Context) error {
if v := operation.Parameters; v != nil {
if err := v.Validate(c); err != nil {
func (value *Operation) Validate(ctx context.Context) error {
if v := value.Parameters; v != nil {
if err := v.Validate(ctx); err != nil {
return err
}
}
if v := operation.RequestBody; v != nil {
if err := v.Validate(c); err != nil {
if v := value.RequestBody; v != nil {
if err := v.Validate(ctx); err != nil {
return err
}
}
if v := operation.Responses; v != nil {
if err := v.Validate(c); err != nil {
if v := value.Responses; v != nil {
if err := v.Validate(ctx); err != nil {
return err
}
} else {
return errors.New("value of responses must be a JSON object")
return errors.New("value of responses must be an object")
}
return nil
}

View file

@ -4,13 +4,51 @@ import (
"context"
"errors"
"fmt"
"strconv"
"github.com/getkin/kin-openapi/jsoninfo"
"github.com/go-openapi/jsonpointer"
)
type ParametersMap map[string]*ParameterRef
var _ jsonpointer.JSONPointable = (*ParametersMap)(nil)
func (p ParametersMap) JSONLookup(token string) (interface{}, error) {
ref, ok := p[token]
if ref == nil || ok == false {
return nil, fmt.Errorf("object has no field %q", token)
}
if ref.Ref != "" {
return &Ref{Ref: ref.Ref}, nil
}
return ref.Value, nil
}
// Parameters is specified by OpenAPI/Swagger 3.0 standard.
type Parameters []*ParameterRef
var _ jsonpointer.JSONPointable = (*Parameters)(nil)
func (p Parameters) JSONLookup(token string) (interface{}, error) {
index, err := strconv.Atoi(token)
if err != nil {
return nil, err
}
if index < 0 || index >= len(p) {
return nil, fmt.Errorf("index %d out of bounds of array of length %d", index, len(p))
}
ref := p[index]
if ref != nil && ref.Ref != "" {
return &Ref{Ref: ref.Ref}, nil
}
return ref.Value, nil
}
func NewParameters() Parameters {
return make(Parameters, 0, 4)
}
@ -26,9 +64,9 @@ func (parameters Parameters) GetByInAndName(in string, name string) *Parameter {
return nil
}
func (parameters Parameters) Validate(c context.Context) error {
func (value Parameters) Validate(ctx context.Context) error {
dupes := make(map[string]struct{})
for _, item := range parameters {
for _, item := range value {
if v := item.Value; v != nil {
key := v.In + ":" + v.Name
if _, ok := dupes[key]; ok {
@ -37,7 +75,7 @@ func (parameters Parameters) Validate(c context.Context) error {
dupes[key] = struct{}{}
}
if err := item.Validate(c); err != nil {
if err := item.Validate(ctx); err != nil {
return err
}
}
@ -47,21 +85,23 @@ func (parameters Parameters) Validate(c context.Context) error {
// Parameter is specified by OpenAPI/Swagger 3.0 standard.
type Parameter struct {
ExtensionProps
Name string `json:"name,omitempty" yaml:"name,omitempty"`
In string `json:"in,omitempty" yaml:"in,omitempty"`
Description string `json:"description,omitempty" yaml:"description,omitempty"`
Style string `json:"style,omitempty" yaml:"style,omitempty"`
Explode *bool `json:"explode,omitempty" yaml:"explode,omitempty"`
AllowEmptyValue bool `json:"allowEmptyValue,omitempty" yaml:"allowEmptyValue,omitempty"`
AllowReserved bool `json:"allowReserved,omitempty" yaml:"allowReserved,omitempty"`
Deprecated bool `json:"deprecated,omitempty" yaml:"deprecated,omitempty"`
Required bool `json:"required,omitempty" yaml:"required,omitempty"`
Schema *SchemaRef `json:"schema,omitempty" yaml:"schema,omitempty"`
Example interface{} `json:"example,omitempty" yaml:"example,omitempty"`
Examples map[string]*ExampleRef `json:"examples,omitempty" yaml:"examples,omitempty"`
Content Content `json:"content,omitempty" yaml:"content,omitempty"`
Name string `json:"name,omitempty" yaml:"name,omitempty"`
In string `json:"in,omitempty" yaml:"in,omitempty"`
Description string `json:"description,omitempty" yaml:"description,omitempty"`
Style string `json:"style,omitempty" yaml:"style,omitempty"`
Explode *bool `json:"explode,omitempty" yaml:"explode,omitempty"`
AllowEmptyValue bool `json:"allowEmptyValue,omitempty" yaml:"allowEmptyValue,omitempty"`
AllowReserved bool `json:"allowReserved,omitempty" yaml:"allowReserved,omitempty"`
Deprecated bool `json:"deprecated,omitempty" yaml:"deprecated,omitempty"`
Required bool `json:"required,omitempty" yaml:"required,omitempty"`
Schema *SchemaRef `json:"schema,omitempty" yaml:"schema,omitempty"`
Example interface{} `json:"example,omitempty" yaml:"example,omitempty"`
Examples Examples `json:"examples,omitempty" yaml:"examples,omitempty"`
Content Content `json:"content,omitempty" yaml:"content,omitempty"`
}
var _ jsonpointer.JSONPointable = (*Parameter)(nil)
const (
ParameterInPath = "path"
ParameterInQuery = "query"
@ -127,6 +167,45 @@ func (parameter *Parameter) UnmarshalJSON(data []byte) error {
return jsoninfo.UnmarshalStrictStruct(data, parameter)
}
func (parameter Parameter) JSONLookup(token string) (interface{}, error) {
switch token {
case "schema":
if parameter.Schema != nil {
if parameter.Schema.Ref != "" {
return &Ref{Ref: parameter.Schema.Ref}, nil
}
return parameter.Schema.Value, nil
}
case "name":
return parameter.Name, nil
case "in":
return parameter.In, nil
case "description":
return parameter.Description, nil
case "style":
return parameter.Style, nil
case "explode":
return parameter.Explode, nil
case "allowEmptyValue":
return parameter.AllowEmptyValue, nil
case "allowReserved":
return parameter.AllowReserved, nil
case "deprecated":
return parameter.Deprecated, nil
case "required":
return parameter.Required, nil
case "example":
return parameter.Example, nil
case "examples":
return parameter.Examples, nil
case "content":
return parameter.Content, nil
}
v, _, err := jsonpointer.GetForToken(parameter.ExtensionProps, token)
return v, err
}
// SerializationMethod returns a parameter's serialization method.
// When a parameter's serialization method is not defined the method returns
// the default serialization method corresponding to a parameter's location.
@ -157,11 +236,11 @@ func (parameter *Parameter) SerializationMethod() (*SerializationMethod, error)
}
}
func (parameter *Parameter) Validate(c context.Context) error {
if parameter.Name == "" {
func (value *Parameter) Validate(ctx context.Context) error {
if value.Name == "" {
return errors.New("parameter name can't be blank")
}
in := parameter.In
in := value.In
switch in {
case
ParameterInPath,
@ -169,55 +248,55 @@ func (parameter *Parameter) Validate(c context.Context) error {
ParameterInHeader,
ParameterInCookie:
default:
return fmt.Errorf("parameter can't have 'in' value %q", parameter.In)
return fmt.Errorf("parameter can't have 'in' value %q", value.In)
}
// Validate a parameter's serialization method.
sm, err := parameter.SerializationMethod()
sm, err := value.SerializationMethod()
if err != nil {
return err
}
var smSupported bool
switch {
case parameter.In == ParameterInPath && sm.Style == SerializationSimple && !sm.Explode,
parameter.In == ParameterInPath && sm.Style == SerializationSimple && sm.Explode,
parameter.In == ParameterInPath && sm.Style == SerializationLabel && !sm.Explode,
parameter.In == ParameterInPath && sm.Style == SerializationLabel && sm.Explode,
parameter.In == ParameterInPath && sm.Style == SerializationMatrix && !sm.Explode,
parameter.In == ParameterInPath && sm.Style == SerializationMatrix && sm.Explode,
case value.In == ParameterInPath && sm.Style == SerializationSimple && !sm.Explode,
value.In == ParameterInPath && sm.Style == SerializationSimple && sm.Explode,
value.In == ParameterInPath && sm.Style == SerializationLabel && !sm.Explode,
value.In == ParameterInPath && sm.Style == SerializationLabel && sm.Explode,
value.In == ParameterInPath && sm.Style == SerializationMatrix && !sm.Explode,
value.In == ParameterInPath && sm.Style == SerializationMatrix && sm.Explode,
parameter.In == ParameterInQuery && sm.Style == SerializationForm && sm.Explode,
parameter.In == ParameterInQuery && sm.Style == SerializationForm && !sm.Explode,
parameter.In == ParameterInQuery && sm.Style == SerializationSpaceDelimited && sm.Explode,
parameter.In == ParameterInQuery && sm.Style == SerializationSpaceDelimited && !sm.Explode,
parameter.In == ParameterInQuery && sm.Style == SerializationPipeDelimited && sm.Explode,
parameter.In == ParameterInQuery && sm.Style == SerializationPipeDelimited && !sm.Explode,
parameter.In == ParameterInQuery && sm.Style == SerializationDeepObject && sm.Explode,
value.In == ParameterInQuery && sm.Style == SerializationForm && sm.Explode,
value.In == ParameterInQuery && sm.Style == SerializationForm && !sm.Explode,
value.In == ParameterInQuery && sm.Style == SerializationSpaceDelimited && sm.Explode,
value.In == ParameterInQuery && sm.Style == SerializationSpaceDelimited && !sm.Explode,
value.In == ParameterInQuery && sm.Style == SerializationPipeDelimited && sm.Explode,
value.In == ParameterInQuery && sm.Style == SerializationPipeDelimited && !sm.Explode,
value.In == ParameterInQuery && sm.Style == SerializationDeepObject && sm.Explode,
parameter.In == ParameterInHeader && sm.Style == SerializationSimple && !sm.Explode,
parameter.In == ParameterInHeader && sm.Style == SerializationSimple && sm.Explode,
value.In == ParameterInHeader && sm.Style == SerializationSimple && !sm.Explode,
value.In == ParameterInHeader && sm.Style == SerializationSimple && sm.Explode,
parameter.In == ParameterInCookie && sm.Style == SerializationForm && !sm.Explode,
parameter.In == ParameterInCookie && sm.Style == SerializationForm && sm.Explode:
value.In == ParameterInCookie && sm.Style == SerializationForm && !sm.Explode,
value.In == ParameterInCookie && sm.Style == SerializationForm && sm.Explode:
smSupported = true
}
if !smSupported {
e := fmt.Errorf("serialization method with style=%q and explode=%v is not supported by a %s parameter", sm.Style, sm.Explode, in)
return fmt.Errorf("parameter %q schema is invalid: %v", parameter.Name, e)
return fmt.Errorf("parameter %q schema is invalid: %v", value.Name, e)
}
if (parameter.Schema == nil) == (parameter.Content == nil) {
if (value.Schema == nil) == (value.Content == nil) {
e := errors.New("parameter must contain exactly one of content and schema")
return fmt.Errorf("parameter %q schema is invalid: %v", parameter.Name, e)
return fmt.Errorf("parameter %q schema is invalid: %v", value.Name, e)
}
if schema := parameter.Schema; schema != nil {
if err := schema.Validate(c); err != nil {
return fmt.Errorf("parameter %q schema is invalid: %v", parameter.Name, err)
if schema := value.Schema; schema != nil {
if err := schema.Validate(ctx); err != nil {
return fmt.Errorf("parameter %q schema is invalid: %v", value.Name, err)
}
}
if content := parameter.Content; content != nil {
if err := content.Validate(c); err != nil {
return fmt.Errorf("parameter %q content is invalid: %v", parameter.Name, err)
if content := value.Content; content != nil {
if err := content.Validate(ctx); err != nil {
return fmt.Errorf("parameter %q content is invalid: %v", value.Name, err)
}
}
return nil

View file

@ -87,7 +87,7 @@ func (pathItem *PathItem) GetOperation(method string) *Operation {
case http.MethodTrace:
return pathItem.Trace
default:
panic(fmt.Errorf("Unsupported HTTP method '%s'", method))
panic(fmt.Errorf("unsupported HTTP method %q", method))
}
}
@ -112,13 +112,13 @@ func (pathItem *PathItem) SetOperation(method string, operation *Operation) {
case http.MethodTrace:
pathItem.Trace = operation
default:
panic(fmt.Errorf("Unsupported HTTP method '%s'", method))
panic(fmt.Errorf("unsupported HTTP method %q", method))
}
}
func (pathItem *PathItem) Validate(c context.Context) error {
for _, operation := range pathItem.Operations() {
if err := operation.Validate(c); err != nil {
func (value *PathItem) Validate(ctx context.Context) error {
for _, operation := range value.Operations() {
if err := operation.Validate(ctx); err != nil {
return err
}
}

View file

@ -9,13 +9,18 @@ import (
// Paths is specified by OpenAPI/Swagger standard version 3.0.
type Paths map[string]*PathItem
func (paths Paths) Validate(c context.Context) error {
func (value Paths) Validate(ctx context.Context) error {
normalizedPaths := make(map[string]string)
for path, pathItem := range paths {
for path, pathItem := range value {
if path == "" || path[0] != '/' {
return fmt.Errorf("path %q does not start with a forward slash (/)", path)
}
if pathItem == nil {
value[path] = &PathItem{}
pathItem = value[path]
}
normalizedPath, pathParamsCount := normalizeTemplatedPath(path)
if oldPath, ok := normalizedPaths[normalizedPath]; ok {
return fmt.Errorf("conflicting paths %q and %q", path, oldPath)
@ -44,7 +49,7 @@ func (paths Paths) Validate(c context.Context) error {
}
}
if err := pathItem.Validate(c); err != nil {
if err := pathItem.Validate(ctx); err != nil {
return err
}
}

View file

@ -4,13 +4,21 @@ import (
"context"
"github.com/getkin/kin-openapi/jsoninfo"
"github.com/go-openapi/jsonpointer"
)
// Ref is specified by OpenAPI/Swagger 3.0 standard.
type Ref struct {
Ref string `json:"$ref" yaml:"$ref"`
}
type CallbackRef struct {
Ref string
Value *Callback
}
var _ jsonpointer.JSONPointable = (*CallbackRef)(nil)
func (value *CallbackRef) MarshalJSON() ([]byte, error) {
return jsoninfo.MarshalRef(value.Ref, value.Value)
}
@ -19,12 +27,20 @@ func (value *CallbackRef) UnmarshalJSON(data []byte) error {
return jsoninfo.UnmarshalRef(data, &value.Ref, &value.Value)
}
func (value *CallbackRef) Validate(c context.Context) error {
v := value.Value
if v == nil {
return foundUnresolvedRef(value.Ref)
func (value *CallbackRef) Validate(ctx context.Context) error {
if v := value.Value; v != nil {
return v.Validate(ctx)
}
return v.Validate(c)
return foundUnresolvedRef(value.Ref)
}
func (value CallbackRef) JSONLookup(token string) (interface{}, error) {
if token == "$ref" {
return value.Ref, nil
}
ptr, _, err := jsonpointer.GetForToken(value.Value, token)
return ptr, err
}
type ExampleRef struct {
@ -32,6 +48,8 @@ type ExampleRef struct {
Value *Example
}
var _ jsonpointer.JSONPointable = (*ExampleRef)(nil)
func (value *ExampleRef) MarshalJSON() ([]byte, error) {
return jsoninfo.MarshalRef(value.Ref, value.Value)
}
@ -40,8 +58,20 @@ func (value *ExampleRef) UnmarshalJSON(data []byte) error {
return jsoninfo.UnmarshalRef(data, &value.Ref, &value.Value)
}
func (value *ExampleRef) Validate(c context.Context) error {
return nil
func (value *ExampleRef) Validate(ctx context.Context) error {
if v := value.Value; v != nil {
return v.Validate(ctx)
}
return foundUnresolvedRef(value.Ref)
}
func (value ExampleRef) JSONLookup(token string) (interface{}, error) {
if token == "$ref" {
return value.Ref, nil
}
ptr, _, err := jsonpointer.GetForToken(value.Value, token)
return ptr, err
}
type HeaderRef struct {
@ -49,6 +79,8 @@ type HeaderRef struct {
Value *Header
}
var _ jsonpointer.JSONPointable = (*HeaderRef)(nil)
func (value *HeaderRef) MarshalJSON() ([]byte, error) {
return jsoninfo.MarshalRef(value.Ref, value.Value)
}
@ -57,12 +89,20 @@ func (value *HeaderRef) UnmarshalJSON(data []byte) error {
return jsoninfo.UnmarshalRef(data, &value.Ref, &value.Value)
}
func (value *HeaderRef) Validate(c context.Context) error {
v := value.Value
if v == nil {
return foundUnresolvedRef(value.Ref)
func (value *HeaderRef) Validate(ctx context.Context) error {
if v := value.Value; v != nil {
return v.Validate(ctx)
}
return v.Validate(c)
return foundUnresolvedRef(value.Ref)
}
func (value HeaderRef) JSONLookup(token string) (interface{}, error) {
if token == "$ref" {
return value.Ref, nil
}
ptr, _, err := jsonpointer.GetForToken(value.Value, token)
return ptr, err
}
type LinkRef struct {
@ -78,12 +118,11 @@ func (value *LinkRef) UnmarshalJSON(data []byte) error {
return jsoninfo.UnmarshalRef(data, &value.Ref, &value.Value)
}
func (value *LinkRef) Validate(c context.Context) error {
v := value.Value
if v == nil {
return foundUnresolvedRef(value.Ref)
func (value *LinkRef) Validate(ctx context.Context) error {
if v := value.Value; v != nil {
return v.Validate(ctx)
}
return v.Validate(c)
return foundUnresolvedRef(value.Ref)
}
type ParameterRef struct {
@ -91,6 +130,8 @@ type ParameterRef struct {
Value *Parameter
}
var _ jsonpointer.JSONPointable = (*ParameterRef)(nil)
func (value *ParameterRef) MarshalJSON() ([]byte, error) {
return jsoninfo.MarshalRef(value.Ref, value.Value)
}
@ -99,12 +140,20 @@ func (value *ParameterRef) UnmarshalJSON(data []byte) error {
return jsoninfo.UnmarshalRef(data, &value.Ref, &value.Value)
}
func (value *ParameterRef) Validate(c context.Context) error {
v := value.Value
if v == nil {
return foundUnresolvedRef(value.Ref)
func (value *ParameterRef) Validate(ctx context.Context) error {
if v := value.Value; v != nil {
return v.Validate(ctx)
}
return v.Validate(c)
return foundUnresolvedRef(value.Ref)
}
func (value ParameterRef) JSONLookup(token string) (interface{}, error) {
if token == "$ref" {
return value.Ref, nil
}
ptr, _, err := jsonpointer.GetForToken(value.Value, token)
return ptr, err
}
type ResponseRef struct {
@ -112,6 +161,8 @@ type ResponseRef struct {
Value *Response
}
var _ jsonpointer.JSONPointable = (*ResponseRef)(nil)
func (value *ResponseRef) MarshalJSON() ([]byte, error) {
return jsoninfo.MarshalRef(value.Ref, value.Value)
}
@ -120,12 +171,20 @@ func (value *ResponseRef) UnmarshalJSON(data []byte) error {
return jsoninfo.UnmarshalRef(data, &value.Ref, &value.Value)
}
func (value *ResponseRef) Validate(c context.Context) error {
v := value.Value
if v == nil {
return foundUnresolvedRef(value.Ref)
func (value *ResponseRef) Validate(ctx context.Context) error {
if v := value.Value; v != nil {
return v.Validate(ctx)
}
return v.Validate(c)
return foundUnresolvedRef(value.Ref)
}
func (value ResponseRef) JSONLookup(token string) (interface{}, error) {
if token == "$ref" {
return value.Ref, nil
}
ptr, _, err := jsonpointer.GetForToken(value.Value, token)
return ptr, err
}
type RequestBodyRef struct {
@ -133,6 +192,8 @@ type RequestBodyRef struct {
Value *RequestBody
}
var _ jsonpointer.JSONPointable = (*RequestBodyRef)(nil)
func (value *RequestBodyRef) MarshalJSON() ([]byte, error) {
return jsoninfo.MarshalRef(value.Ref, value.Value)
}
@ -141,12 +202,20 @@ func (value *RequestBodyRef) UnmarshalJSON(data []byte) error {
return jsoninfo.UnmarshalRef(data, &value.Ref, &value.Value)
}
func (value *RequestBodyRef) Validate(c context.Context) error {
v := value.Value
if v == nil {
return foundUnresolvedRef(value.Ref)
func (value *RequestBodyRef) Validate(ctx context.Context) error {
if v := value.Value; v != nil {
return v.Validate(ctx)
}
return v.Validate(c)
return foundUnresolvedRef(value.Ref)
}
func (value RequestBodyRef) JSONLookup(token string) (interface{}, error) {
if token == "$ref" {
return value.Ref, nil
}
ptr, _, err := jsonpointer.GetForToken(value.Value, token)
return ptr, err
}
type SchemaRef struct {
@ -154,6 +223,8 @@ type SchemaRef struct {
Value *Schema
}
var _ jsonpointer.JSONPointable = (*SchemaRef)(nil)
func NewSchemaRef(ref string, value *Schema) *SchemaRef {
return &SchemaRef{
Ref: ref,
@ -169,12 +240,20 @@ func (value *SchemaRef) UnmarshalJSON(data []byte) error {
return jsoninfo.UnmarshalRef(data, &value.Ref, &value.Value)
}
func (value *SchemaRef) Validate(c context.Context) error {
v := value.Value
if v == nil {
return foundUnresolvedRef(value.Ref)
func (value *SchemaRef) Validate(ctx context.Context) error {
if v := value.Value; v != nil {
return v.Validate(ctx)
}
return v.Validate(c)
return foundUnresolvedRef(value.Ref)
}
func (value SchemaRef) JSONLookup(token string) (interface{}, error) {
if token == "$ref" {
return value.Ref, nil
}
ptr, _, err := jsonpointer.GetForToken(value.Value, token)
return ptr, err
}
type SecuritySchemeRef struct {
@ -182,6 +261,8 @@ type SecuritySchemeRef struct {
Value *SecurityScheme
}
var _ jsonpointer.JSONPointable = (*SecuritySchemeRef)(nil)
func (value *SecuritySchemeRef) MarshalJSON() ([]byte, error) {
return jsoninfo.MarshalRef(value.Ref, value.Value)
}
@ -190,10 +271,18 @@ func (value *SecuritySchemeRef) UnmarshalJSON(data []byte) error {
return jsoninfo.UnmarshalRef(data, &value.Ref, &value.Value)
}
func (value *SecuritySchemeRef) Validate(c context.Context) error {
v := value.Value
if v == nil {
return foundUnresolvedRef(value.Ref)
func (value *SecuritySchemeRef) Validate(ctx context.Context) error {
if v := value.Value; v != nil {
return v.Validate(ctx)
}
return v.Validate(c)
return foundUnresolvedRef(value.Ref)
}
func (value SecuritySchemeRef) JSONLookup(token string) (interface{}, error) {
if token == "$ref" {
return value.Ref, nil
}
ptr, _, err := jsonpointer.GetForToken(value.Value, token)
return ptr, err
}

View file

@ -2,10 +2,28 @@ package openapi3
import (
"context"
"fmt"
"github.com/getkin/kin-openapi/jsoninfo"
"github.com/go-openapi/jsonpointer"
)
type RequestBodies map[string]*RequestBodyRef
var _ jsonpointer.JSONPointable = (*RequestBodyRef)(nil)
func (r RequestBodies) JSONLookup(token string) (interface{}, error) {
ref, ok := r[token]
if ok == false {
return nil, fmt.Errorf("object has no field %q", token)
}
if ref != nil && ref.Ref != "" {
return &Ref{Ref: ref.Ref}, nil
}
return ref.Value, nil
}
// RequestBody is specified by OpenAPI/Swagger 3.0 standard.
type RequestBody struct {
ExtensionProps
@ -33,6 +51,16 @@ func (requestBody *RequestBody) WithContent(content Content) *RequestBody {
return requestBody
}
func (requestBody *RequestBody) WithSchemaRef(value *SchemaRef, consumes []string) *RequestBody {
requestBody.Content = NewContentWithSchemaRef(value, consumes)
return requestBody
}
func (requestBody *RequestBody) WithSchema(value *Schema, consumes []string) *RequestBody {
requestBody.Content = NewContentWithSchema(value, consumes)
return requestBody
}
func (requestBody *RequestBody) WithJSONSchemaRef(value *SchemaRef) *RequestBody {
requestBody.Content = NewContentWithJSONSchemaRef(value)
return requestBody
@ -43,6 +71,16 @@ func (requestBody *RequestBody) WithJSONSchema(value *Schema) *RequestBody {
return requestBody
}
func (requestBody *RequestBody) WithFormDataSchemaRef(value *SchemaRef) *RequestBody {
requestBody.Content = NewContentWithFormDataSchemaRef(value)
return requestBody
}
func (requestBody *RequestBody) WithFormDataSchema(value *Schema) *RequestBody {
requestBody.Content = NewContentWithFormDataSchema(value)
return requestBody
}
func (requestBody *RequestBody) GetMediaType(mediaType string) *MediaType {
m := requestBody.Content
if m == nil {
@ -59,9 +97,9 @@ func (requestBody *RequestBody) UnmarshalJSON(data []byte) error {
return jsoninfo.UnmarshalStrictStruct(data, requestBody)
}
func (requestBody *RequestBody) Validate(c context.Context) error {
if v := requestBody.Content; v != nil {
if err := v.Validate(c); err != nil {
func (value *RequestBody) Validate(ctx context.Context) error {
if v := value.Content; v != nil {
if err := v.Validate(ctx); err != nil {
return err
}
}

View file

@ -3,14 +3,18 @@ package openapi3
import (
"context"
"errors"
"fmt"
"strconv"
"github.com/getkin/kin-openapi/jsoninfo"
"github.com/go-openapi/jsonpointer"
)
// Responses is specified by OpenAPI/Swagger 3.0 standard.
type Responses map[string]*ResponseRef
var _ jsonpointer.JSONPointable = (*Responses)(nil)
func NewResponses() Responses {
r := make(Responses)
r["default"] = &ResponseRef{Value: NewResponse().WithDescription("")}
@ -25,25 +29,37 @@ func (responses Responses) Get(status int) *ResponseRef {
return responses[strconv.FormatInt(int64(status), 10)]
}
func (responses Responses) Validate(c context.Context) error {
if len(responses) == 0 {
func (value Responses) Validate(ctx context.Context) error {
if len(value) == 0 {
return errors.New("the responses object MUST contain at least one response code")
}
for _, v := range responses {
if err := v.Validate(c); err != nil {
for _, v := range value {
if err := v.Validate(ctx); err != nil {
return err
}
}
return nil
}
func (responses Responses) JSONLookup(token string) (interface{}, error) {
ref, ok := responses[token]
if ok == false {
return nil, fmt.Errorf("invalid token reference: %q", token)
}
if ref != nil && ref.Ref != "" {
return &Ref{Ref: ref.Ref}, nil
}
return ref.Value, nil
}
// Response is specified by OpenAPI/Swagger 3.0 standard.
type Response struct {
ExtensionProps
Description *string `json:"description,omitempty" yaml:"description,omitempty"`
Headers map[string]*HeaderRef `json:"headers,omitempty" yaml:"headers,omitempty"`
Content Content `json:"content,omitempty" yaml:"content,omitempty"`
Links map[string]*LinkRef `json:"links,omitempty" yaml:"links,omitempty"`
Description *string `json:"description,omitempty" yaml:"description,omitempty"`
Headers Headers `json:"headers,omitempty" yaml:"headers,omitempty"`
Content Content `json:"content,omitempty" yaml:"content,omitempty"`
Links Links `json:"links,omitempty" yaml:"links,omitempty"`
}
func NewResponse() *Response {
@ -78,13 +94,13 @@ func (response *Response) UnmarshalJSON(data []byte) error {
return jsoninfo.UnmarshalStrictStruct(data, response)
}
func (response *Response) Validate(c context.Context) error {
if response.Description == nil {
func (value *Response) Validate(ctx context.Context) error {
if value.Description == nil {
return errors.New("a short description of the response is required")
}
if content := response.Content; content != nil {
if err := content.Validate(c); err != nil {
if content := value.Content; content != nil {
if err := content.Validate(ctx); err != nil {
return err
}
}

File diff suppressed because it is too large Load diff

View file

@ -2,6 +2,7 @@ package openapi3
import (
"fmt"
"net"
"regexp"
)
@ -10,15 +11,70 @@ const (
FormatOfStringForUUIDOfRFC4122 = `^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$`
)
var SchemaStringFormats = make(map[string]*regexp.Regexp, 8)
//FormatCallback custom check on exotic formats
type FormatCallback func(Val string) error
type Format struct {
regexp *regexp.Regexp
callback FormatCallback
}
//SchemaStringFormats allows for validating strings format
var SchemaStringFormats = make(map[string]Format, 8)
//DefineStringFormat Defines a new regexp pattern for a given format
func DefineStringFormat(name string, pattern string) {
re, err := regexp.Compile(pattern)
if err != nil {
err := fmt.Errorf("Format '%v' has invalid pattern '%v': %v", name, pattern, err)
err := fmt.Errorf("format %q has invalid pattern %q: %v", name, pattern, err)
panic(err)
}
SchemaStringFormats[name] = re
SchemaStringFormats[name] = Format{regexp: re}
}
// DefineStringFormatCallback adds a validation function for a specific schema format entry
func DefineStringFormatCallback(name string, callback FormatCallback) {
SchemaStringFormats[name] = Format{callback: callback}
}
func validateIP(ip string) (*net.IP, error) {
parsed := net.ParseIP(ip)
if parsed == nil {
return nil, &SchemaError{
Value: ip,
Reason: "Not an IP address",
}
}
return &parsed, nil
}
func validateIPv4(ip string) error {
parsed, err := validateIP(ip)
if err != nil {
return err
}
if parsed.To4() == nil {
return &SchemaError{
Value: ip,
Reason: "Not an IPv4 address (it's IPv6)",
}
}
return nil
}
func validateIPv6(ip string) error {
parsed, err := validateIP(ip)
if err != nil {
return err
}
if parsed.To4() != nil {
return &SchemaError{
Value: ip,
Reason: "Not an IPv6 address (it's IPv4)",
}
}
return nil
}
func init() {
@ -35,4 +91,15 @@ func init() {
// date-time
DefineStringFormat("date-time", `^[0-9]{4}-(0[0-9]|10|11|12)-([0-2][0-9]|30|31)T[0-9]{2}:[0-9]{2}:[0-9]{2}(.[0-9]+)?(Z|(\+|-)[0-9]{2}:[0-9]{2})?$`)
}
// DefineIPv4Format opts in ipv4 format validation on top of OAS 3 spec
func DefineIPv4Format() {
DefineStringFormatCallback("ipv4", validateIPv4)
}
// DefineIPv6Format opts in ipv6 format validation on top of OAS 3 spec
func DefineIPv6Format() {
DefineStringFormatCallback("ipv6", validateIPv6)
}

View file

@ -0,0 +1,34 @@
package openapi3
// SchemaValidationOption describes options a user has when validating request / response bodies.
type SchemaValidationOption func(*schemaValidationSettings)
type schemaValidationSettings struct {
failfast bool
multiError bool
asreq, asrep bool // exclusive (XOR) fields
}
// FailFast returns schema validation errors quicker.
func FailFast() SchemaValidationOption {
return func(s *schemaValidationSettings) { s.failfast = true }
}
func MultiErrors() SchemaValidationOption {
return func(s *schemaValidationSettings) { s.multiError = true }
}
func VisitAsRequest() SchemaValidationOption {
return func(s *schemaValidationSettings) { s.asreq, s.asrep = true, false }
}
func VisitAsResponse() SchemaValidationOption {
return func(s *schemaValidationSettings) { s.asreq, s.asrep = false, true }
}
func newSchemaValidationSettings(opts ...SchemaValidationOption) *schemaValidationSettings {
settings := &schemaValidationSettings{}
for _, opt := range opts {
opt(settings)
}
return settings
}

View file

@ -15,9 +15,9 @@ func (srs *SecurityRequirements) With(securityRequirement SecurityRequirement) *
return srs
}
func (srs SecurityRequirements) Validate(c context.Context) error {
for _, item := range srs {
if err := item.Validate(c); err != nil {
func (value SecurityRequirements) Validate(ctx context.Context) error {
for _, item := range value {
if err := item.Validate(ctx); err != nil {
return err
}
}
@ -38,6 +38,6 @@ func (security SecurityRequirement) Authenticate(provider string, scopes ...stri
return security
}
func (security SecurityRequirement) Validate(c context.Context) error {
func (value SecurityRequirement) Validate(ctx context.Context) error {
return nil
}

View file

@ -6,18 +6,36 @@ import (
"fmt"
"github.com/getkin/kin-openapi/jsoninfo"
"github.com/go-openapi/jsonpointer"
)
type SecuritySchemes map[string]*SecuritySchemeRef
func (s SecuritySchemes) JSONLookup(token string) (interface{}, error) {
ref, ok := s[token]
if ref == nil || ok == false {
return nil, fmt.Errorf("object has no field %q", token)
}
if ref.Ref != "" {
return &Ref{Ref: ref.Ref}, nil
}
return ref.Value, nil
}
var _ jsonpointer.JSONPointable = (*SecuritySchemes)(nil)
type SecurityScheme struct {
ExtensionProps
Type string `json:"type,omitempty" yaml:"type,omitempty"`
Description string `json:"description,omitempty" yaml:"description,omitempty"`
Name string `json:"name,omitempty" yaml:"name,omitempty"`
In string `json:"in,omitempty" yaml:"in,omitempty"`
Scheme string `json:"scheme,omitempty" yaml:"scheme,omitempty"`
BearerFormat string `json:"bearerFormat,omitempty" yaml:"bearerFormat,omitempty"`
Flows *OAuthFlows `json:"flows,omitempty" yaml:"flows,omitempty"`
Type string `json:"type,omitempty" yaml:"type,omitempty"`
Description string `json:"description,omitempty" yaml:"description,omitempty"`
Name string `json:"name,omitempty" yaml:"name,omitempty"`
In string `json:"in,omitempty" yaml:"in,omitempty"`
Scheme string `json:"scheme,omitempty" yaml:"scheme,omitempty"`
BearerFormat string `json:"bearerFormat,omitempty" yaml:"bearerFormat,omitempty"`
Flows *OAuthFlows `json:"flows,omitempty" yaml:"flows,omitempty"`
OpenIdConnectUrl string `json:"openIdConnectUrl,omitempty" yaml:"openIdConnectUrl,omitempty"`
}
func NewSecurityScheme() *SecurityScheme {
@ -32,6 +50,13 @@ func NewCSRFSecurityScheme() *SecurityScheme {
}
}
func NewOIDCSecurityScheme(oidcUrl string) *SecurityScheme {
return &SecurityScheme{
Type: "openIdConnect",
OpenIdConnectUrl: oidcUrl,
}
}
func NewJWTSecurityScheme() *SecurityScheme {
return &SecurityScheme{
Type: "http",
@ -78,63 +103,65 @@ func (ss *SecurityScheme) WithBearerFormat(value string) *SecurityScheme {
return ss
}
func (ss *SecurityScheme) Validate(c context.Context) error {
func (value *SecurityScheme) Validate(ctx context.Context) error {
hasIn := false
hasBearerFormat := false
hasFlow := false
switch ss.Type {
switch value.Type {
case "apiKey":
hasIn = true
case "http":
scheme := ss.Scheme
scheme := value.Scheme
switch scheme {
case "bearer":
hasBearerFormat = true
case "basic":
case "basic", "negotiate", "digest":
default:
return fmt.Errorf("Security scheme of type 'http' has invalid 'scheme' value '%s'", scheme)
return fmt.Errorf("security scheme of type 'http' has invalid 'scheme' value %q", scheme)
}
case "oauth2":
hasFlow = true
case "openIdConnect":
return fmt.Errorf("Support for security schemes with type '%v' has not been implemented", ss.Type)
if value.OpenIdConnectUrl == "" {
return fmt.Errorf("no OIDC URL found for openIdConnect security scheme %q", value.Name)
}
default:
return fmt.Errorf("Security scheme 'type' can't be '%v'", ss.Type)
return fmt.Errorf("security scheme 'type' can't be %q", value.Type)
}
// Validate "in" and "name"
if hasIn {
switch ss.In {
switch value.In {
case "query", "header", "cookie":
default:
return fmt.Errorf("Security scheme of type 'apiKey' should have 'in'. It can be 'query', 'header' or 'cookie', not '%s'", ss.In)
return fmt.Errorf("security scheme of type 'apiKey' should have 'in'. It can be 'query', 'header' or 'cookie', not %q", value.In)
}
if ss.Name == "" {
return errors.New("Security scheme of type 'apiKey' should have 'name'")
if value.Name == "" {
return errors.New("security scheme of type 'apiKey' should have 'name'")
}
} else if len(ss.In) > 0 {
return fmt.Errorf("Security scheme of type '%s' can't have 'in'", ss.Type)
} else if len(ss.Name) > 0 {
return errors.New("Security scheme of type 'apiKey' can't have 'name'")
} else if len(value.In) > 0 {
return fmt.Errorf("security scheme of type %q can't have 'in'", value.Type)
} else if len(value.Name) > 0 {
return errors.New("security scheme of type 'apiKey' can't have 'name'")
}
// Validate "format"
// "bearerFormat" is an arbitrary string so we only check if the scheme supports it
if !hasBearerFormat && len(ss.BearerFormat) > 0 {
return fmt.Errorf("Security scheme of type '%v' can't have 'bearerFormat'", ss.Type)
if !hasBearerFormat && len(value.BearerFormat) > 0 {
return fmt.Errorf("security scheme of type %q can't have 'bearerFormat'", value.Type)
}
// Validate "flow"
if hasFlow {
flow := ss.Flows
flow := value.Flows
if flow == nil {
return fmt.Errorf("Security scheme of type '%v' should have 'flows'", ss.Type)
return fmt.Errorf("security scheme of type %q should have 'flows'", value.Type)
}
if err := flow.Validate(c); err != nil {
return fmt.Errorf("Security scheme 'flow' is invalid: %v", err)
if err := flow.Validate(ctx); err != nil {
return fmt.Errorf("security scheme 'flow' is invalid: %v", err)
}
} else if ss.Flows != nil {
return fmt.Errorf("Security scheme of type '%s' can't have 'flows'", ss.Type)
} else if value.Flows != nil {
return fmt.Errorf("security scheme of type %q can't have 'flows'", value.Type)
}
return nil
}
@ -164,20 +191,20 @@ func (flows *OAuthFlows) UnmarshalJSON(data []byte) error {
return jsoninfo.UnmarshalStrictStruct(data, flows)
}
func (flows *OAuthFlows) Validate(c context.Context) error {
func (flows *OAuthFlows) Validate(ctx context.Context) error {
if v := flows.Implicit; v != nil {
return v.Validate(c, oAuthFlowTypeImplicit)
return v.Validate(ctx, oAuthFlowTypeImplicit)
}
if v := flows.Password; v != nil {
return v.Validate(c, oAuthFlowTypePassword)
return v.Validate(ctx, oAuthFlowTypePassword)
}
if v := flows.ClientCredentials; v != nil {
return v.Validate(c, oAuthFlowTypeClientCredentials)
return v.Validate(ctx, oAuthFlowTypeClientCredentials)
}
if v := flows.AuthorizationCode; v != nil {
return v.Validate(c, oAuthFlowAuthorizationCode)
return v.Validate(ctx, oAuthFlowAuthorizationCode)
}
return errors.New("No OAuth flow is defined")
return errors.New("no OAuth flow is defined")
}
type OAuthFlow struct {
@ -196,19 +223,19 @@ func (flow *OAuthFlow) UnmarshalJSON(data []byte) error {
return jsoninfo.UnmarshalStrictStruct(data, flow)
}
func (flow *OAuthFlow) Validate(c context.Context, typ oAuthFlowType) error {
func (flow *OAuthFlow) Validate(ctx context.Context, typ oAuthFlowType) error {
if typ == oAuthFlowAuthorizationCode || typ == oAuthFlowTypeImplicit {
if v := flow.AuthorizationURL; v == "" {
return errors.New("An OAuth flow is missing 'authorizationUrl in authorizationCode or implicit '")
return errors.New("an OAuth flow is missing 'authorizationUrl in authorizationCode or implicit '")
}
}
if typ != oAuthFlowTypeImplicit {
if v := flow.TokenURL; v == "" {
return errors.New("An OAuth flow is missing 'tokenUrl in not implicit'")
return errors.New("an OAuth flow is missing 'tokenUrl in not implicit'")
}
}
if v := flow.Scopes; v == nil {
return errors.New("An OAuth flow is missing 'scopes'")
return errors.New("an OAuth flow is missing 'scopes'")
}
return nil
}

View file

@ -3,17 +3,21 @@ package openapi3
import (
"context"
"errors"
"fmt"
"math"
"net/url"
"strings"
"github.com/getkin/kin-openapi/jsoninfo"
)
// Servers is specified by OpenAPI/Swagger standard version 3.0.
type Servers []*Server
func (servers Servers) Validate(c context.Context) error {
for _, v := range servers {
if err := v.Validate(c); err != nil {
// Validate ensures servers are per the OpenAPIv3 specification.
func (value Servers) Validate(ctx context.Context) error {
for _, v := range value {
if err := v.Validate(ctx); err != nil {
return err
}
}
@ -36,11 +40,20 @@ func (servers Servers) MatchURL(parsedURL *url.URL) (*Server, []string, string)
// Server is specified by OpenAPI/Swagger standard version 3.0.
type Server struct {
ExtensionProps
URL string `json:"url" yaml:"url"`
Description string `json:"description,omitempty" yaml:"description,omitempty"`
Variables map[string]*ServerVariable `json:"variables,omitempty" yaml:"variables,omitempty"`
}
func (server *Server) MarshalJSON() ([]byte, error) {
return jsoninfo.MarshalStrictStruct(server)
}
func (server *Server) UnmarshalJSON(data []byte) error {
return jsoninfo.UnmarshalStrictStruct(data, server)
}
func (server Server) ParameterNames() ([]string, error) {
pattern := server.URL
var params []string
@ -52,7 +65,7 @@ func (server Server) ParameterNames() ([]string, error) {
pattern = pattern[i+1:]
i = strings.IndexByte(pattern, '}')
if i < 0 {
return nil, errors.New("Missing '}'")
return nil, errors.New("missing '}'")
}
params = append(params, strings.TrimSpace(pattern[:i]))
pattern = pattern[i+1:]
@ -112,12 +125,22 @@ func (server Server) MatchRawURL(input string) ([]string, string, bool) {
return params, input, true
}
func (server *Server) Validate(c context.Context) (err error) {
if server.URL == "" {
return errors.New("value of url must be a non-empty JSON string")
func (value *Server) Validate(ctx context.Context) (err error) {
if value.URL == "" {
return errors.New("value of url must be a non-empty string")
}
for _, v := range server.Variables {
if err = v.Validate(c); err != nil {
opening, closing := strings.Count(value.URL, "{"), strings.Count(value.URL, "}")
if opening != closing {
return errors.New("server URL has mismatched { and }")
}
if opening != len(value.Variables) {
return errors.New("server has undeclared variables")
}
for name, v := range value.Variables {
if !strings.Contains(value.URL, fmt.Sprintf("{%s}", name)) {
return errors.New("server has undeclared variables")
}
if err = v.Validate(ctx); err != nil {
return
}
}
@ -126,23 +149,27 @@ func (server *Server) Validate(c context.Context) (err error) {
// ServerVariable is specified by OpenAPI/Swagger standard version 3.0.
type ServerVariable struct {
Enum []interface{} `json:"enum,omitempty" yaml:"enum,omitempty"`
Default interface{} `json:"default,omitempty" yaml:"default,omitempty"`
Description string `json:"description,omitempty" yaml:"description,omitempty"`
ExtensionProps
Enum []string `json:"enum,omitempty" yaml:"enum,omitempty"`
Default string `json:"default,omitempty" yaml:"default,omitempty"`
Description string `json:"description,omitempty" yaml:"description,omitempty"`
}
func (serverVariable *ServerVariable) Validate(c context.Context) error {
switch serverVariable.Default.(type) {
case float64, string:
default:
return errors.New("value of default must be either JSON number or JSON string")
}
for _, item := range serverVariable.Enum {
switch item.(type) {
case float64, string:
default:
return errors.New("Every variable 'enum' item must be number of string")
func (serverVariable *ServerVariable) MarshalJSON() ([]byte, error) {
return jsoninfo.MarshalStrictStruct(serverVariable)
}
func (serverVariable *ServerVariable) UnmarshalJSON(data []byte) error {
return jsoninfo.UnmarshalStrictStruct(data, serverVariable)
}
func (value *ServerVariable) Validate(ctx context.Context) error {
if value.Default == "" {
data, err := value.MarshalJSON()
if err != nil {
return err
}
return fmt.Errorf("field default is required in %s", data)
}
return nil
}

View file

@ -1,887 +0,0 @@
package openapi3
import (
"context"
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"net/http"
"net/url"
"path"
"reflect"
"strconv"
"strings"
"github.com/ghodss/yaml"
)
func foundUnresolvedRef(ref string) error {
return fmt.Errorf("Found unresolved ref: '%s'", ref)
}
func failedToResolveRefFragment(value string) error {
return fmt.Errorf("Failed to resolve fragment in URI: '%s'", value)
}
func failedToResolveRefFragmentPart(value string, what string) error {
return fmt.Errorf("Failed to resolve '%s' in fragment in URI: '%s'", what, value)
}
type SwaggerLoader struct {
IsExternalRefsAllowed bool
Context context.Context
LoadSwaggerFromURIFunc func(loader *SwaggerLoader, url *url.URL) (*Swagger, error)
visited map[interface{}]struct{}
visitedFiles map[string]struct{}
}
func NewSwaggerLoader() *SwaggerLoader {
return &SwaggerLoader{}
}
func (swaggerLoader *SwaggerLoader) reset() {
swaggerLoader.visitedFiles = make(map[string]struct{})
}
func (swaggerLoader *SwaggerLoader) LoadSwaggerFromURI(location *url.URL) (*Swagger, error) {
swaggerLoader.reset()
return swaggerLoader.loadSwaggerFromURIInternal(location)
}
func (swaggerLoader *SwaggerLoader) loadSwaggerFromURIInternal(location *url.URL) (*Swagger, error) {
f := swaggerLoader.LoadSwaggerFromURIFunc
if f != nil {
return f(swaggerLoader, location)
}
data, err := readURL(location)
if err != nil {
return nil, err
}
return swaggerLoader.loadSwaggerFromDataWithPathInternal(data, location)
}
// loadSingleElementFromURI read the data from ref and unmarshal to JSON to the
// passed element.
func (swaggerLoader *SwaggerLoader) loadSingleElementFromURI(ref string, rootPath *url.URL, element json.Unmarshaler) error {
if !swaggerLoader.IsExternalRefsAllowed {
return fmt.Errorf("encountered non-allowed external reference: '%s'", ref)
}
parsedURL, err := url.Parse(ref)
if err != nil {
return err
}
if parsedURL.Fragment != "" {
return errors.New("references to files which contain more than one element definition are not supported")
}
resolvedPath, err := resolvePath(rootPath, parsedURL)
if err != nil {
return fmt.Errorf("could not resolve path: %v", err)
}
data, err := readURL(resolvedPath)
if err != nil {
return err
}
if err := yaml.Unmarshal(data, element); err != nil {
return err
}
return nil
}
func readURL(location *url.URL) ([]byte, error) {
if location.Scheme != "" && location.Host != "" {
resp, err := http.Get(location.String())
if err != nil {
return nil, err
}
data, err := ioutil.ReadAll(resp.Body)
defer resp.Body.Close()
if err != nil {
return nil, err
}
return data, nil
}
if location.Scheme != "" || location.Host != "" || location.RawQuery != "" {
return nil, fmt.Errorf("Unsupported URI: '%s'", location.String())
}
data, err := ioutil.ReadFile(location.Path)
if err != nil {
return nil, err
}
return data, nil
}
func (swaggerLoader *SwaggerLoader) LoadSwaggerFromFile(path string) (*Swagger, error) {
swaggerLoader.reset()
return swaggerLoader.loadSwaggerFromFileInternal(path)
}
func (swaggerLoader *SwaggerLoader) loadSwaggerFromFileInternal(path string) (*Swagger, error) {
f := swaggerLoader.LoadSwaggerFromURIFunc
if f != nil {
return f(swaggerLoader, &url.URL{
Path: path,
})
}
data, err := ioutil.ReadFile(path)
if err != nil {
return nil, err
}
return swaggerLoader.loadSwaggerFromDataWithPathInternal(data, &url.URL{
Path: path,
})
}
func (swaggerLoader *SwaggerLoader) LoadSwaggerFromData(data []byte) (*Swagger, error) {
swaggerLoader.reset()
return swaggerLoader.loadSwaggerFromDataInternal(data)
}
func (swaggerLoader *SwaggerLoader) loadSwaggerFromDataInternal(data []byte) (*Swagger, error) {
swagger := &Swagger{}
if err := yaml.Unmarshal(data, swagger); err != nil {
return nil, err
}
return swagger, swaggerLoader.ResolveRefsIn(swagger, nil)
}
// LoadSwaggerFromDataWithPath takes the OpenApi spec data in bytes and a path where the resolver can find referred
// elements and returns a *Swagger with all resolved data or an error if unable to load data or resolve refs.
func (swaggerLoader *SwaggerLoader) LoadSwaggerFromDataWithPath(data []byte, path *url.URL) (*Swagger, error) {
swaggerLoader.reset()
return swaggerLoader.loadSwaggerFromDataWithPathInternal(data, path)
}
func (swaggerLoader *SwaggerLoader) loadSwaggerFromDataWithPathInternal(data []byte, path *url.URL) (*Swagger, error) {
swagger := &Swagger{}
if err := yaml.Unmarshal(data, swagger); err != nil {
return nil, err
}
return swagger, swaggerLoader.ResolveRefsIn(swagger, path)
}
func (swaggerLoader *SwaggerLoader) ResolveRefsIn(swagger *Swagger, path *url.URL) (err error) {
swaggerLoader.visited = make(map[interface{}]struct{})
if swaggerLoader.visitedFiles == nil {
swaggerLoader.visitedFiles = make(map[string]struct{})
}
// Visit all components
components := swagger.Components
for _, component := range components.Headers {
if err = swaggerLoader.resolveHeaderRef(swagger, component, path); err != nil {
return
}
}
for _, component := range components.Parameters {
if err = swaggerLoader.resolveParameterRef(swagger, component, path); err != nil {
return
}
}
for _, component := range components.RequestBodies {
if err = swaggerLoader.resolveRequestBodyRef(swagger, component, path); err != nil {
return
}
}
for _, component := range components.Responses {
if err = swaggerLoader.resolveResponseRef(swagger, component, path); err != nil {
return
}
}
for _, component := range components.Schemas {
if err = swaggerLoader.resolveSchemaRef(swagger, component, path); err != nil {
return
}
}
for _, component := range components.SecuritySchemes {
if err = swaggerLoader.resolveSecuritySchemeRef(swagger, component, path); err != nil {
return
}
}
for _, component := range components.Examples {
if err = swaggerLoader.resolveExampleRef(swagger, component, path); err != nil {
return
}
}
// Visit all operations
for entrypoint, pathItem := range swagger.Paths {
if pathItem == nil {
continue
}
if err = swaggerLoader.resolvePathItemRef(swagger, entrypoint, pathItem, path); err != nil {
return
}
}
return
}
func copyURL(basePath *url.URL) (*url.URL, error) {
return url.Parse(basePath.String())
}
func join(basePath *url.URL, relativePath *url.URL) (*url.URL, error) {
if basePath == nil {
return relativePath, nil
}
newPath, err := copyURL(basePath)
if err != nil {
return nil, fmt.Errorf("Can't copy path: '%s'", basePath.String())
}
newPath.Path = path.Join(path.Dir(newPath.Path), relativePath.Path)
return newPath, nil
}
func resolvePath(basePath *url.URL, componentPath *url.URL) (*url.URL, error) {
if componentPath.Scheme == "" && componentPath.Host == "" {
return join(basePath, componentPath)
}
return componentPath, nil
}
func isSingleRefElement(ref string) bool {
return !strings.Contains(ref, "#")
}
func (swaggerLoader *SwaggerLoader) resolveComponent(swagger *Swagger, ref string, path *url.URL) (
cursor interface{},
componentPath *url.URL,
err error,
) {
if swagger, ref, componentPath, err = swaggerLoader.resolveRefSwagger(swagger, ref, path); err != nil {
return nil, nil, err
}
parsedURL, err := url.Parse(ref)
if err != nil {
return nil, nil, fmt.Errorf("Can't parse reference: '%s': %v", ref, parsedURL)
}
fragment := parsedURL.Fragment
if !strings.HasPrefix(fragment, "/") {
err := fmt.Errorf("expected fragment prefix '#/' in URI '%s'", ref)
return nil, nil, err
}
cursor = swagger
for _, pathPart := range strings.Split(fragment[1:], "/") {
pathPart = strings.Replace(pathPart, "~1", "/", -1)
pathPart = strings.Replace(pathPart, "~0", "~", -1)
if cursor, err = drillIntoSwaggerField(cursor, pathPart); err != nil {
return nil, nil, fmt.Errorf("Failed to resolve '%s' in fragment in URI: '%s': %v", ref, pathPart, err.Error())
}
if cursor == nil {
return nil, nil, failedToResolveRefFragmentPart(ref, pathPart)
}
}
return cursor, componentPath, nil
}
func drillIntoSwaggerField(cursor interface{}, fieldName string) (interface{}, error) {
switch val := reflect.Indirect(reflect.ValueOf(cursor)); val.Kind() {
case reflect.Map:
elementValue := val.MapIndex(reflect.ValueOf(fieldName))
if !elementValue.IsValid() {
return nil, fmt.Errorf("Map key not found: %v", fieldName)
}
return elementValue.Interface(), nil
case reflect.Slice:
i, err := strconv.ParseUint(fieldName, 10, 32)
if err != nil {
return nil, err
}
index := int(i)
if index >= val.Len() {
return nil, errors.New("slice index out of bounds")
}
return val.Index(index).Interface(), nil
case reflect.Struct:
for i := 0; i < val.NumField(); i++ {
field := val.Type().Field(i)
tagValue := field.Tag.Get("yaml")
yamlKey := strings.Split(tagValue, ",")[0]
if yamlKey == fieldName {
return val.Field(i).Interface(), nil
}
}
// if cursor if a "ref wrapper" struct (e.g. RequestBodyRef), try digging into its Value field
_, ok := val.Type().FieldByName("Value")
if ok {
return drillIntoSwaggerField(val.FieldByName("Value").Interface(), fieldName) // recurse into .Value
}
// give up
return nil, fmt.Errorf("Struct field not found: %v", fieldName)
default:
return nil, errors.New("not a map, slice nor struct")
}
}
func (swaggerLoader *SwaggerLoader) resolveRefSwagger(swagger *Swagger, ref string, path *url.URL) (*Swagger, string, *url.URL, error) {
componentPath := path
if !strings.HasPrefix(ref, "#") {
if !swaggerLoader.IsExternalRefsAllowed {
return nil, "", nil, fmt.Errorf("Encountered non-allowed external reference: '%s'", ref)
}
parsedURL, err := url.Parse(ref)
if err != nil {
return nil, "", nil, fmt.Errorf("Can't parse reference: '%s': %v", ref, parsedURL)
}
fragment := parsedURL.Fragment
parsedURL.Fragment = ""
resolvedPath, err := resolvePath(path, parsedURL)
if err != nil {
return nil, "", nil, fmt.Errorf("Error while resolving path: %v", err)
}
if swagger, err = swaggerLoader.loadSwaggerFromURIInternal(resolvedPath); err != nil {
return nil, "", nil, fmt.Errorf("Error while resolving reference '%s': %v", ref, err)
}
ref = fmt.Sprintf("#%s", fragment)
componentPath = resolvedPath
}
return swagger, ref, componentPath, nil
}
func (swaggerLoader *SwaggerLoader) resolveHeaderRef(swagger *Swagger, component *HeaderRef, path *url.URL) error {
visited := swaggerLoader.visited
if _, isVisited := visited[component]; isVisited {
return nil
}
visited[component] = struct{}{}
const prefix = "#/components/headers/"
if component == nil {
return errors.New("invalid header: value MUST be a JSON object")
}
if ref := component.Ref; len(ref) > 0 {
if isSingleRefElement(ref) {
var header Header
if err := swaggerLoader.loadSingleElementFromURI(ref, path, &header); err != nil {
return err
}
component.Value = &header
} else {
untypedResolved, componentPath, err := swaggerLoader.resolveComponent(swagger, ref, path)
if err != nil {
return err
}
resolved, ok := untypedResolved.(*HeaderRef)
if !ok {
return failedToResolveRefFragment(ref)
}
if err := swaggerLoader.resolveHeaderRef(swagger, resolved, componentPath); err != nil {
return err
}
component.Value = resolved.Value
}
}
value := component.Value
if value == nil {
return nil
}
if schema := value.Schema; schema != nil {
if err := swaggerLoader.resolveSchemaRef(swagger, schema, path); err != nil {
return err
}
}
return nil
}
func (swaggerLoader *SwaggerLoader) resolveParameterRef(swagger *Swagger, component *ParameterRef, documentPath *url.URL) error {
visited := swaggerLoader.visited
if _, isVisited := visited[component]; isVisited {
return nil
}
visited[component] = struct{}{}
const prefix = "#/components/parameters/"
if component == nil {
return errors.New("invalid parameter: value MUST be a JSON object")
}
ref := component.Ref
if len(ref) > 0 {
if isSingleRefElement(ref) {
var param Parameter
if err := swaggerLoader.loadSingleElementFromURI(ref, documentPath, &param); err != nil {
return err
}
component.Value = &param
} else {
untypedResolved, componentPath, err := swaggerLoader.resolveComponent(swagger, ref, documentPath)
if err != nil {
return err
}
resolved, ok := untypedResolved.(*ParameterRef)
if !ok {
return failedToResolveRefFragment(ref)
}
if err := swaggerLoader.resolveParameterRef(swagger, resolved, componentPath); err != nil {
return err
}
component.Value = resolved.Value
}
}
value := component.Value
if value == nil {
return nil
}
refDocumentPath, err := referencedDocumentPath(documentPath, ref)
if err != nil {
return err
}
if value.Content != nil && value.Schema != nil {
return errors.New("Cannot contain both schema and content in a parameter")
}
for _, contentType := range value.Content {
if schema := contentType.Schema; schema != nil {
if err := swaggerLoader.resolveSchemaRef(swagger, schema, refDocumentPath); err != nil {
return err
}
}
}
if schema := value.Schema; schema != nil {
if err := swaggerLoader.resolveSchemaRef(swagger, schema, refDocumentPath); err != nil {
return err
}
}
return nil
}
func (swaggerLoader *SwaggerLoader) resolveRequestBodyRef(swagger *Swagger, component *RequestBodyRef, path *url.URL) error {
visited := swaggerLoader.visited
if _, isVisited := visited[component]; isVisited {
return nil
}
visited[component] = struct{}{}
const prefix = "#/components/requestBodies/"
if component == nil {
return errors.New("invalid requestBody: value MUST be a JSON object")
}
if ref := component.Ref; len(ref) > 0 {
if isSingleRefElement(ref) {
var requestBody RequestBody
if err := swaggerLoader.loadSingleElementFromURI(ref, path, &requestBody); err != nil {
return err
}
component.Value = &requestBody
} else {
untypedResolved, componentPath, err := swaggerLoader.resolveComponent(swagger, ref, path)
if err != nil {
return err
}
resolved, ok := untypedResolved.(*RequestBodyRef)
if !ok {
return failedToResolveRefFragment(ref)
}
if err = swaggerLoader.resolveRequestBodyRef(swagger, resolved, componentPath); err != nil {
return err
}
component.Value = resolved.Value
}
}
value := component.Value
if value == nil {
return nil
}
for _, contentType := range value.Content {
for name, example := range contentType.Examples {
if err := swaggerLoader.resolveExampleRef(swagger, example, path); err != nil {
return err
}
contentType.Examples[name] = example
}
if schema := contentType.Schema; schema != nil {
if err := swaggerLoader.resolveSchemaRef(swagger, schema, path); err != nil {
return err
}
}
}
return nil
}
func (swaggerLoader *SwaggerLoader) resolveResponseRef(swagger *Swagger, component *ResponseRef, documentPath *url.URL) error {
visited := swaggerLoader.visited
if _, isVisited := visited[component]; isVisited {
return nil
}
visited[component] = struct{}{}
const prefix = "#/components/responses/"
if component == nil {
return errors.New("invalid response: value MUST be a JSON object")
}
ref := component.Ref
if len(ref) > 0 {
if isSingleRefElement(ref) {
var resp Response
if err := swaggerLoader.loadSingleElementFromURI(ref, documentPath, &resp); err != nil {
return err
}
component.Value = &resp
} else {
untypedResolved, componentPath, err := swaggerLoader.resolveComponent(swagger, ref, documentPath)
if err != nil {
return err
}
resolved, ok := untypedResolved.(*ResponseRef)
if !ok {
return failedToResolveRefFragment(ref)
}
if err := swaggerLoader.resolveResponseRef(swagger, resolved, componentPath); err != nil {
return err
}
component.Value = resolved.Value
}
}
refDocumentPath, err := referencedDocumentPath(documentPath, ref)
if err != nil {
return err
}
value := component.Value
if value == nil {
return nil
}
for _, header := range value.Headers {
if err := swaggerLoader.resolveHeaderRef(swagger, header, refDocumentPath); err != nil {
return err
}
}
for _, contentType := range value.Content {
if contentType == nil {
continue
}
for name, example := range contentType.Examples {
if err := swaggerLoader.resolveExampleRef(swagger, example, refDocumentPath); err != nil {
return err
}
contentType.Examples[name] = example
}
if schema := contentType.Schema; schema != nil {
if err := swaggerLoader.resolveSchemaRef(swagger, schema, refDocumentPath); err != nil {
return err
}
contentType.Schema = schema
}
}
for _, link := range value.Links {
if err := swaggerLoader.resolveLinkRef(swagger, link, refDocumentPath); err != nil {
return err
}
}
return nil
}
func (swaggerLoader *SwaggerLoader) resolveSchemaRef(swagger *Swagger, component *SchemaRef, documentPath *url.URL) error {
visited := swaggerLoader.visited
if _, isVisited := visited[component]; isVisited {
return nil
}
visited[component] = struct{}{}
const prefix = "#/components/schemas/"
if component == nil {
return errors.New("invalid schema: value MUST be a JSON object")
}
ref := component.Ref
if len(ref) > 0 {
if isSingleRefElement(ref) {
var schema Schema
if err := swaggerLoader.loadSingleElementFromURI(ref, documentPath, &schema); err != nil {
return err
}
component.Value = &schema
} else {
untypedResolved, componentPath, err := swaggerLoader.resolveComponent(swagger, ref, documentPath)
if err != nil {
return err
}
resolved, ok := untypedResolved.(*SchemaRef)
if !ok {
return failedToResolveRefFragment(ref)
}
if err := swaggerLoader.resolveSchemaRef(swagger, resolved, componentPath); err != nil {
return err
}
component.Value = resolved.Value
}
}
refDocumentPath, err := referencedDocumentPath(documentPath, ref)
if err != nil {
return err
}
value := component.Value
if value == nil {
return nil
}
// ResolveRefs referred schemas
if v := value.Items; v != nil {
if err := swaggerLoader.resolveSchemaRef(swagger, v, refDocumentPath); err != nil {
return err
}
}
for _, v := range value.Properties {
if err := swaggerLoader.resolveSchemaRef(swagger, v, refDocumentPath); err != nil {
return err
}
}
if v := value.AdditionalProperties; v != nil {
if err := swaggerLoader.resolveSchemaRef(swagger, v, refDocumentPath); err != nil {
return err
}
}
if v := value.Not; v != nil {
if err := swaggerLoader.resolveSchemaRef(swagger, v, refDocumentPath); err != nil {
return err
}
}
for _, v := range value.AllOf {
if err := swaggerLoader.resolveSchemaRef(swagger, v, refDocumentPath); err != nil {
return err
}
}
for _, v := range value.AnyOf {
if err := swaggerLoader.resolveSchemaRef(swagger, v, refDocumentPath); err != nil {
return err
}
}
for _, v := range value.OneOf {
if err := swaggerLoader.resolveSchemaRef(swagger, v, refDocumentPath); err != nil {
return err
}
}
return nil
}
func (swaggerLoader *SwaggerLoader) resolveSecuritySchemeRef(swagger *Swagger, component *SecuritySchemeRef, path *url.URL) error {
visited := swaggerLoader.visited
if _, isVisited := visited[component]; isVisited {
return nil
}
visited[component] = struct{}{}
const prefix = "#/components/securitySchemes/"
if component == nil {
return errors.New("invalid securityScheme: value MUST be a JSON object")
}
if ref := component.Ref; len(ref) > 0 {
if isSingleRefElement(ref) {
var scheme SecurityScheme
if err := swaggerLoader.loadSingleElementFromURI(ref, path, &scheme); err != nil {
return err
}
component.Value = &scheme
} else {
untypedResolved, componentPath, err := swaggerLoader.resolveComponent(swagger, ref, path)
if err != nil {
return err
}
resolved, ok := untypedResolved.(*SecuritySchemeRef)
if !ok {
return failedToResolveRefFragment(ref)
}
if err := swaggerLoader.resolveSecuritySchemeRef(swagger, resolved, componentPath); err != nil {
return err
}
component.Value = resolved.Value
}
}
return nil
}
func (swaggerLoader *SwaggerLoader) resolveExampleRef(swagger *Swagger, component *ExampleRef, path *url.URL) error {
visited := swaggerLoader.visited
if _, isVisited := visited[component]; isVisited {
return nil
}
visited[component] = struct{}{}
const prefix = "#/components/examples/"
if component == nil {
return errors.New("invalid example: value MUST be a JSON object")
}
if ref := component.Ref; len(ref) > 0 {
if isSingleRefElement(ref) {
var example Example
if err := swaggerLoader.loadSingleElementFromURI(ref, path, &example); err != nil {
return err
}
component.Value = &example
} else {
untypedResolved, componentPath, err := swaggerLoader.resolveComponent(swagger, ref, path)
if err != nil {
return err
}
resolved, ok := untypedResolved.(*ExampleRef)
if !ok {
return failedToResolveRefFragment(ref)
}
if err := swaggerLoader.resolveExampleRef(swagger, resolved, componentPath); err != nil {
return err
}
component.Value = resolved.Value
}
}
return nil
}
func (swaggerLoader *SwaggerLoader) resolveLinkRef(swagger *Swagger, component *LinkRef, path *url.URL) error {
visited := swaggerLoader.visited
if _, isVisited := visited[component]; isVisited {
return nil
}
visited[component] = struct{}{}
const prefix = "#/components/links/"
if component == nil {
return errors.New("invalid link: value MUST be a JSON object")
}
if ref := component.Ref; len(ref) > 0 {
if isSingleRefElement(ref) {
var link Link
if err := swaggerLoader.loadSingleElementFromURI(ref, path, &link); err != nil {
return err
}
component.Value = &link
} else {
untypedResolved, componentPath, err := swaggerLoader.resolveComponent(swagger, ref, path)
if err != nil {
return err
}
resolved, ok := untypedResolved.(*LinkRef)
if !ok {
return failedToResolveRefFragment(ref)
}
if err := swaggerLoader.resolveLinkRef(swagger, resolved, componentPath); err != nil {
return err
}
component.Value = resolved.Value
}
}
return nil
}
func (swaggerLoader *SwaggerLoader) resolvePathItemRef(swagger *Swagger, entrypoint string, pathItem *PathItem, documentPath *url.URL) (err error) {
visited := swaggerLoader.visitedFiles
key := "_"
if documentPath != nil {
key = documentPath.EscapedPath()
}
key += entrypoint
if _, isVisited := visited[key]; isVisited {
return nil
}
visited[key] = struct{}{}
const prefix = "#/paths/"
if pathItem == nil {
return errors.New("invalid path item: value MUST be a JSON object")
}
ref := pathItem.Ref
if ref != "" {
if isSingleRefElement(ref) {
var p PathItem
if err := swaggerLoader.loadSingleElementFromURI(ref, documentPath, &p); err != nil {
return err
}
*pathItem = p
} else {
if swagger, ref, documentPath, err = swaggerLoader.resolveRefSwagger(swagger, ref, documentPath); err != nil {
return
}
if !strings.HasPrefix(ref, prefix) {
err = fmt.Errorf("expected prefix '%s' in URI '%s'", prefix, ref)
return
}
id := unescapeRefString(ref[len(prefix):])
definitions := swagger.Paths
if definitions == nil {
return failedToResolveRefFragmentPart(ref, "paths")
}
resolved := definitions[id]
if resolved == nil {
return failedToResolveRefFragmentPart(ref, id)
}
*pathItem = *resolved
}
}
refDocumentPath, err := referencedDocumentPath(documentPath, ref)
if err != nil {
return err
}
for _, parameter := range pathItem.Parameters {
if err = swaggerLoader.resolveParameterRef(swagger, parameter, refDocumentPath); err != nil {
return
}
}
for _, operation := range pathItem.Operations() {
for _, parameter := range operation.Parameters {
if err = swaggerLoader.resolveParameterRef(swagger, parameter, refDocumentPath); err != nil {
return
}
}
if requestBody := operation.RequestBody; requestBody != nil {
if err = swaggerLoader.resolveRequestBodyRef(swagger, requestBody, refDocumentPath); err != nil {
return
}
}
for _, response := range operation.Responses {
if err = swaggerLoader.resolveResponseRef(swagger, response, refDocumentPath); err != nil {
return
}
}
}
return nil
}
func unescapeRefString(ref string) string {
return strings.Replace(strings.Replace(ref, "~1", "/", -1), "~0", "~", -1)
}
func referencedDocumentPath(documentPath *url.URL, ref string) (*url.URL, error) {
newDocumentPath := documentPath
if documentPath != nil {
refDirectory, err := url.Parse(path.Dir(ref))
if err != nil {
return nil, err
}
joinedDirectory := path.Join(path.Dir(documentPath.String()), refDirectory.String())
if newDocumentPath, err = url.Parse(joinedDirectory + "/"); err != nil {
return nil, err
}
}
return newDocumentPath, nil
}

View file

@ -1,5 +1,7 @@
package openapi3
import "github.com/getkin/kin-openapi/jsoninfo"
// Tags is specified by OpenAPI/Swagger 3.0 standard.
type Tags []*Tag
@ -14,7 +16,16 @@ func (tags Tags) Get(name string) *Tag {
// Tag is specified by OpenAPI/Swagger 3.0 standard.
type Tag struct {
ExtensionProps
Name string `json:"name,omitempty" yaml:"name,omitempty"`
Description string `json:"description,omitempty" yaml:"description,omitempty"`
ExternalDocs *ExternalDocs `json:"externalDocs,omitempty" yaml:"externalDocs,omitempty"`
}
func (t *Tag) MarshalJSON() ([]byte, error) {
return jsoninfo.MarshalStrictStruct(t)
}
func (t *Tag) UnmarshalJSON(data []byte) error {
return jsoninfo.UnmarshalStrictStruct(data, t)
}

26
vendor/github.com/go-openapi/jsonpointer/.editorconfig generated vendored Normal file
View file

@ -0,0 +1,26 @@
# top-most EditorConfig file
root = true
# Unix-style newlines with a newline ending every file
[*]
end_of_line = lf
insert_final_newline = true
indent_style = space
indent_size = 2
trim_trailing_whitespace = true
# Set default charset
[*.{js,py,go,scala,rb,java,html,css,less,sass,md}]
charset = utf-8
# Tab indentation (no size specified)
[*.go]
indent_style = tab
[*.md]
trim_trailing_whitespace = false
# Matches the exact files either package.json or .travis.yml
[{package.json,.travis.yml}]
indent_style = space
indent_size = 2

1
vendor/github.com/go-openapi/jsonpointer/.gitignore generated vendored Normal file
View file

@ -0,0 +1 @@
secrets.yml

15
vendor/github.com/go-openapi/jsonpointer/.travis.yml generated vendored Normal file
View file

@ -0,0 +1,15 @@
after_success:
- bash <(curl -s https://codecov.io/bash)
go:
- 1.14.x
- 1.15.x
install:
- GO111MODULE=off go get -u gotest.tools/gotestsum
env:
- GO111MODULE=on
language: go
notifications:
slack:
secure: a5VgoiwB1G/AZqzmephPZIhEB9avMlsWSlVnM1dSAtYAwdrQHGTQxAmpOxYIoSPDhWNN5bfZmjd29++UlTwLcHSR+e0kJhH6IfDlsHj/HplNCJ9tyI0zYc7XchtdKgeMxMzBKCzgwFXGSbQGydXTliDNBo0HOzmY3cou/daMFTP60K+offcjS+3LRAYb1EroSRXZqrk1nuF/xDL3792DZUdPMiFR/L/Df6y74D6/QP4sTkTDFQitz4Wy/7jbsfj8dG6qK2zivgV6/l+w4OVjFkxVpPXogDWY10vVXNVynqxfJ7to2d1I9lNCHE2ilBCkWMIPdyJF7hjF8pKW+82yP4EzRh0vu8Xn0HT5MZpQxdRY/YMxNrWaG7SxsoEaO4q5uhgdzAqLYY3TRa7MjIK+7Ur+aqOeTXn6OKwVi0CjvZ6mIU3WUKSwiwkFZMbjRAkSb5CYwMEfGFO/z964xz83qGt6WAtBXNotqCQpTIiKtDHQeLOMfksHImCg6JLhQcWBVxamVgu0G3Pdh8Y6DyPnxraXY95+QDavbjqv7TeYT9T/FNnrkXaTTK0s4iWE5H4ACU0Qvz0wUYgfQrZv0/Hp7V17+rabUwnzYySHCy9SWX/7OV9Cfh31iMp9ZIffr76xmmThtOEqs8TrTtU6BWI3rWwvA9cXQipZTVtL0oswrGw=
script:
- gotestsum -f short-verbose -- -race -coverprofile=coverage.txt -covermode=atomic ./...

View file

@ -0,0 +1,74 @@
# Contributor Covenant Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to making participation in our project and
our community a harassment-free experience for everyone, regardless of age, body
size, disability, ethnicity, gender identity and expression, level of experience,
nationality, personal appearance, race, religion, or sexual identity and
orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment
include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or
advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic
address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in
response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.
## Scope
This Code of Conduct applies both within project spaces and in public spaces
when an individual is representing the project or its community. Examples of
representing a project or community include using an official project e-mail
address, posting via an official social media account, or acting as an appointed
representative at an online or offline event. Representation of a project may be
further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting the project team at ivan+abuse@flanders.co.nz. All
complaints will be reviewed and investigated and will result in a response that
is deemed necessary and appropriate to the circumstances. The project team is
obligated to maintain confidentiality with regard to the reporter of an incident.
Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good
faith may face temporary or permanent repercussions as determined by other
members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
available at [http://contributor-covenant.org/version/1/4][version]
[homepage]: http://contributor-covenant.org
[version]: http://contributor-covenant.org/version/1/4/

202
vendor/github.com/go-openapi/jsonpointer/LICENSE generated vendored Normal file
View file

@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

15
vendor/github.com/go-openapi/jsonpointer/README.md generated vendored Normal file
View file

@ -0,0 +1,15 @@
# gojsonpointer [![Build Status](https://travis-ci.org/go-openapi/jsonpointer.svg?branch=master)](https://travis-ci.org/go-openapi/jsonpointer) [![codecov](https://codecov.io/gh/go-openapi/jsonpointer/branch/master/graph/badge.svg)](https://codecov.io/gh/go-openapi/jsonpointer) [![Slack Status](https://slackin.goswagger.io/badge.svg)](https://slackin.goswagger.io)
[![license](http://img.shields.io/badge/license-Apache%20v2-orange.svg)](https://raw.githubusercontent.com/go-openapi/jsonpointer/master/LICENSE) [![GoDoc](https://godoc.org/github.com/go-openapi/jsonpointer?status.svg)](http://godoc.org/github.com/go-openapi/jsonpointer)
An implementation of JSON Pointer - Go language
## Status
Completed YES
Tested YES
## References
http://tools.ietf.org/html/draft-ietf-appsawg-json-pointer-07
### Note
The 4.Evaluation part of the previous reference, starting with 'If the currently referenced value is a JSON array, the reference token MUST contain either...' is not implemented.

9
vendor/github.com/go-openapi/jsonpointer/go.mod generated vendored Normal file
View file

@ -0,0 +1,9 @@
module github.com/go-openapi/jsonpointer
require (
github.com/go-openapi/swag v0.19.5
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e // indirect
github.com/stretchr/testify v1.3.0
)
go 1.13

24
vendor/github.com/go-openapi/jsonpointer/go.sum generated vendored Normal file
View file

@ -0,0 +1,24 @@
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/go-openapi/swag v0.19.5 h1:lTz6Ys4CmqqCQmZPBlbQENR1/GucA2bzYTE12Pw4tFY=
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63 h1:nTT4s92Dgz2HlrB2NaMgvlfqHH39OgMhA7z3PK7PGD4=
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e h1:hB2xlXdHp/pmPZq0y3QnmWAArdw9PqbmotexnWx/FU8=
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
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.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

390
vendor/github.com/go-openapi/jsonpointer/pointer.go generated vendored Normal file
View file

@ -0,0 +1,390 @@
// Copyright 2013 sigu-399 ( https://github.com/sigu-399 )
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// author sigu-399
// author-github https://github.com/sigu-399
// author-mail sigu.399@gmail.com
//
// repository-name jsonpointer
// repository-desc An implementation of JSON Pointer - Go language
//
// description Main and unique file.
//
// created 25-02-2013
package jsonpointer
import (
"errors"
"fmt"
"reflect"
"strconv"
"strings"
"github.com/go-openapi/swag"
)
const (
emptyPointer = ``
pointerSeparator = `/`
invalidStart = `JSON pointer must be empty or start with a "` + pointerSeparator
)
var jsonPointableType = reflect.TypeOf(new(JSONPointable)).Elem()
var jsonSetableType = reflect.TypeOf(new(JSONSetable)).Elem()
// JSONPointable is an interface for structs to implement when they need to customize the
// json pointer process
type JSONPointable interface {
JSONLookup(string) (interface{}, error)
}
// JSONSetable is an interface for structs to implement when they need to customize the
// json pointer process
type JSONSetable interface {
JSONSet(string, interface{}) error
}
// New creates a new json pointer for the given string
func New(jsonPointerString string) (Pointer, error) {
var p Pointer
err := p.parse(jsonPointerString)
return p, err
}
// Pointer the json pointer reprsentation
type Pointer struct {
referenceTokens []string
}
// "Constructor", parses the given string JSON pointer
func (p *Pointer) parse(jsonPointerString string) error {
var err error
if jsonPointerString != emptyPointer {
if !strings.HasPrefix(jsonPointerString, pointerSeparator) {
err = errors.New(invalidStart)
} else {
referenceTokens := strings.Split(jsonPointerString, pointerSeparator)
for _, referenceToken := range referenceTokens[1:] {
p.referenceTokens = append(p.referenceTokens, referenceToken)
}
}
}
return err
}
// Get uses the pointer to retrieve a value from a JSON document
func (p *Pointer) Get(document interface{}) (interface{}, reflect.Kind, error) {
return p.get(document, swag.DefaultJSONNameProvider)
}
// Set uses the pointer to set a value from a JSON document
func (p *Pointer) Set(document interface{}, value interface{}) (interface{}, error) {
return document, p.set(document, value, swag.DefaultJSONNameProvider)
}
// GetForToken gets a value for a json pointer token 1 level deep
func GetForToken(document interface{}, decodedToken string) (interface{}, reflect.Kind, error) {
return getSingleImpl(document, decodedToken, swag.DefaultJSONNameProvider)
}
// SetForToken gets a value for a json pointer token 1 level deep
func SetForToken(document interface{}, decodedToken string, value interface{}) (interface{}, error) {
return document, setSingleImpl(document, value, decodedToken, swag.DefaultJSONNameProvider)
}
func getSingleImpl(node interface{}, decodedToken string, nameProvider *swag.NameProvider) (interface{}, reflect.Kind, error) {
rValue := reflect.Indirect(reflect.ValueOf(node))
kind := rValue.Kind()
if rValue.Type().Implements(jsonPointableType) {
r, err := node.(JSONPointable).JSONLookup(decodedToken)
if err != nil {
return nil, kind, err
}
return r, kind, nil
}
switch kind {
case reflect.Struct:
nm, ok := nameProvider.GetGoNameForType(rValue.Type(), decodedToken)
if !ok {
return nil, kind, fmt.Errorf("object has no field %q", decodedToken)
}
fld := rValue.FieldByName(nm)
return fld.Interface(), kind, nil
case reflect.Map:
kv := reflect.ValueOf(decodedToken)
mv := rValue.MapIndex(kv)
if mv.IsValid() {
return mv.Interface(), kind, nil
}
return nil, kind, fmt.Errorf("object has no key %q", decodedToken)
case reflect.Slice:
tokenIndex, err := strconv.Atoi(decodedToken)
if err != nil {
return nil, kind, err
}
sLength := rValue.Len()
if tokenIndex < 0 || tokenIndex >= sLength {
return nil, kind, fmt.Errorf("index out of bounds array[0,%d] index '%d'", sLength-1, tokenIndex)
}
elem := rValue.Index(tokenIndex)
return elem.Interface(), kind, nil
default:
return nil, kind, fmt.Errorf("invalid token reference %q", decodedToken)
}
}
func setSingleImpl(node, data interface{}, decodedToken string, nameProvider *swag.NameProvider) error {
rValue := reflect.Indirect(reflect.ValueOf(node))
if ns, ok := node.(JSONSetable); ok { // pointer impl
return ns.JSONSet(decodedToken, data)
}
if rValue.Type().Implements(jsonSetableType) {
return node.(JSONSetable).JSONSet(decodedToken, data)
}
switch rValue.Kind() {
case reflect.Struct:
nm, ok := nameProvider.GetGoNameForType(rValue.Type(), decodedToken)
if !ok {
return fmt.Errorf("object has no field %q", decodedToken)
}
fld := rValue.FieldByName(nm)
if fld.IsValid() {
fld.Set(reflect.ValueOf(data))
}
return nil
case reflect.Map:
kv := reflect.ValueOf(decodedToken)
rValue.SetMapIndex(kv, reflect.ValueOf(data))
return nil
case reflect.Slice:
tokenIndex, err := strconv.Atoi(decodedToken)
if err != nil {
return err
}
sLength := rValue.Len()
if tokenIndex < 0 || tokenIndex >= sLength {
return fmt.Errorf("index out of bounds array[0,%d] index '%d'", sLength, tokenIndex)
}
elem := rValue.Index(tokenIndex)
if !elem.CanSet() {
return fmt.Errorf("can't set slice index %s to %v", decodedToken, data)
}
elem.Set(reflect.ValueOf(data))
return nil
default:
return fmt.Errorf("invalid token reference %q", decodedToken)
}
}
func (p *Pointer) get(node interface{}, nameProvider *swag.NameProvider) (interface{}, reflect.Kind, error) {
if nameProvider == nil {
nameProvider = swag.DefaultJSONNameProvider
}
kind := reflect.Invalid
// Full document when empty
if len(p.referenceTokens) == 0 {
return node, kind, nil
}
for _, token := range p.referenceTokens {
decodedToken := Unescape(token)
r, knd, err := getSingleImpl(node, decodedToken, nameProvider)
if err != nil {
return nil, knd, err
}
node, kind = r, knd
}
rValue := reflect.ValueOf(node)
kind = rValue.Kind()
return node, kind, nil
}
func (p *Pointer) set(node, data interface{}, nameProvider *swag.NameProvider) error {
knd := reflect.ValueOf(node).Kind()
if knd != reflect.Ptr && knd != reflect.Struct && knd != reflect.Map && knd != reflect.Slice && knd != reflect.Array {
return fmt.Errorf("only structs, pointers, maps and slices are supported for setting values")
}
if nameProvider == nil {
nameProvider = swag.DefaultJSONNameProvider
}
// Full document when empty
if len(p.referenceTokens) == 0 {
return nil
}
lastI := len(p.referenceTokens) - 1
for i, token := range p.referenceTokens {
isLastToken := i == lastI
decodedToken := Unescape(token)
if isLastToken {
return setSingleImpl(node, data, decodedToken, nameProvider)
}
rValue := reflect.Indirect(reflect.ValueOf(node))
kind := rValue.Kind()
if rValue.Type().Implements(jsonPointableType) {
r, err := node.(JSONPointable).JSONLookup(decodedToken)
if err != nil {
return err
}
fld := reflect.ValueOf(r)
if fld.CanAddr() && fld.Kind() != reflect.Interface && fld.Kind() != reflect.Map && fld.Kind() != reflect.Slice && fld.Kind() != reflect.Ptr {
node = fld.Addr().Interface()
continue
}
node = r
continue
}
switch kind {
case reflect.Struct:
nm, ok := nameProvider.GetGoNameForType(rValue.Type(), decodedToken)
if !ok {
return fmt.Errorf("object has no field %q", decodedToken)
}
fld := rValue.FieldByName(nm)
if fld.CanAddr() && fld.Kind() != reflect.Interface && fld.Kind() != reflect.Map && fld.Kind() != reflect.Slice && fld.Kind() != reflect.Ptr {
node = fld.Addr().Interface()
continue
}
node = fld.Interface()
case reflect.Map:
kv := reflect.ValueOf(decodedToken)
mv := rValue.MapIndex(kv)
if !mv.IsValid() {
return fmt.Errorf("object has no key %q", decodedToken)
}
if mv.CanAddr() && mv.Kind() != reflect.Interface && mv.Kind() != reflect.Map && mv.Kind() != reflect.Slice && mv.Kind() != reflect.Ptr {
node = mv.Addr().Interface()
continue
}
node = mv.Interface()
case reflect.Slice:
tokenIndex, err := strconv.Atoi(decodedToken)
if err != nil {
return err
}
sLength := rValue.Len()
if tokenIndex < 0 || tokenIndex >= sLength {
return fmt.Errorf("index out of bounds array[0,%d] index '%d'", sLength, tokenIndex)
}
elem := rValue.Index(tokenIndex)
if elem.CanAddr() && elem.Kind() != reflect.Interface && elem.Kind() != reflect.Map && elem.Kind() != reflect.Slice && elem.Kind() != reflect.Ptr {
node = elem.Addr().Interface()
continue
}
node = elem.Interface()
default:
return fmt.Errorf("invalid token reference %q", decodedToken)
}
}
return nil
}
// DecodedTokens returns the decoded tokens
func (p *Pointer) DecodedTokens() []string {
result := make([]string, 0, len(p.referenceTokens))
for _, t := range p.referenceTokens {
result = append(result, Unescape(t))
}
return result
}
// IsEmpty returns true if this is an empty json pointer
// this indicates that it points to the root document
func (p *Pointer) IsEmpty() bool {
return len(p.referenceTokens) == 0
}
// Pointer to string representation function
func (p *Pointer) String() string {
if len(p.referenceTokens) == 0 {
return emptyPointer
}
pointerString := pointerSeparator + strings.Join(p.referenceTokens, pointerSeparator)
return pointerString
}
// Specific JSON pointer encoding here
// ~0 => ~
// ~1 => /
// ... and vice versa
const (
encRefTok0 = `~0`
encRefTok1 = `~1`
decRefTok0 = `~`
decRefTok1 = `/`
)
// Unescape unescapes a json pointer reference token string to the original representation
func Unescape(token string) string {
step1 := strings.Replace(token, encRefTok1, decRefTok1, -1)
step2 := strings.Replace(step1, encRefTok0, decRefTok0, -1)
return step2
}
// Escape escapes a pointer reference token string
func Escape(token string) string {
step1 := strings.Replace(token, decRefTok0, encRefTok0, -1)
step2 := strings.Replace(step1, decRefTok1, encRefTok1, -1)
return step2
}

26
vendor/github.com/go-openapi/swag/.editorconfig generated vendored Normal file
View file

@ -0,0 +1,26 @@
# top-most EditorConfig file
root = true
# Unix-style newlines with a newline ending every file
[*]
end_of_line = lf
insert_final_newline = true
indent_style = space
indent_size = 2
trim_trailing_whitespace = true
# Set default charset
[*.{js,py,go,scala,rb,java,html,css,less,sass,md}]
charset = utf-8
# Tab indentation (no size specified)
[*.go]
indent_style = tab
[*.md]
trim_trailing_whitespace = false
# Matches the exact files either package.json or .travis.yml
[{package.json,.travis.yml}]
indent_style = space
indent_size = 2

4
vendor/github.com/go-openapi/swag/.gitignore generated vendored Normal file
View file

@ -0,0 +1,4 @@
secrets.yml
vendor
Godeps
.idea

22
vendor/github.com/go-openapi/swag/.golangci.yml generated vendored Normal file
View file

@ -0,0 +1,22 @@
linters-settings:
govet:
check-shadowing: true
golint:
min-confidence: 0
gocyclo:
min-complexity: 25
maligned:
suggest-new: true
dupl:
threshold: 100
goconst:
min-len: 3
min-occurrences: 2
linters:
enable-all: true
disable:
- maligned
- lll
- gochecknoinits
- gochecknoglobals

15
vendor/github.com/go-openapi/swag/.travis.yml generated vendored Normal file
View file

@ -0,0 +1,15 @@
after_success:
- bash <(curl -s https://codecov.io/bash)
go:
- 1.11.x
- 1.12.x
install:
- GO111MODULE=off go get -u gotest.tools/gotestsum
env:
- GO111MODULE=on
language: go
notifications:
slack:
secure: QUWvCkBBK09GF7YtEvHHVt70JOkdlNBG0nIKu/5qc4/nW5HP8I2w0SEf/XR2je0eED1Qe3L/AfMCWwrEj+IUZc3l4v+ju8X8R3Lomhme0Eb0jd1MTMCuPcBT47YCj0M7RON7vXtbFfm1hFJ/jLe5+9FXz0hpXsR24PJc5ZIi/ogNwkaPqG4BmndzecpSh0vc2FJPZUD9LT0I09REY/vXR0oQAalLkW0asGD5taHZTUZq/kBpsNxaAFrLM23i4mUcf33M5fjLpvx5LRICrX/57XpBrDh2TooBU6Qj3CgoY0uPRYUmSNxbVx1czNzl2JtEpb5yjoxfVPQeg0BvQM00G8LJINISR+ohrjhkZmAqchDupAX+yFrxTtORa78CtnIL6z/aTNlgwwVD8kvL/1pFA/JWYmKDmz93mV/+6wubGzNSQCstzjkFA4/iZEKewKUoRIAi/fxyscP6L/rCpmY/4llZZvrnyTqVbt6URWpopUpH4rwYqreXAtJxJsfBJIeSmUIiDIOMGkCTvyTEW3fWGmGoqWtSHLoaWDyAIGb7azb+KvfpWtEcoPFWfSWU+LGee0A/YsUhBl7ADB9A0CJEuR8q4BPpKpfLwPKSiKSAXL7zDkyjExyhtgqbSl2jS+rKIHOZNL8JkCcTP2MKMVd563C5rC5FMKqu3S9m2b6380E=
script:
- gotestsum -f short-verbose -- -race -coverprofile=coverage.txt -covermode=atomic ./...

74
vendor/github.com/go-openapi/swag/CODE_OF_CONDUCT.md generated vendored Normal file
View file

@ -0,0 +1,74 @@
# Contributor Covenant Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to making participation in our project and
our community a harassment-free experience for everyone, regardless of age, body
size, disability, ethnicity, gender identity and expression, level of experience,
nationality, personal appearance, race, religion, or sexual identity and
orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment
include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or
advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic
address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in
response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.
## Scope
This Code of Conduct applies both within project spaces and in public spaces
when an individual is representing the project or its community. Examples of
representing a project or community include using an official project e-mail
address, posting via an official social media account, or acting as an appointed
representative at an online or offline event. Representation of a project may be
further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting the project team at ivan+abuse@flanders.co.nz. All
complaints will be reviewed and investigated and will result in a response that
is deemed necessary and appropriate to the circumstances. The project team is
obligated to maintain confidentiality with regard to the reporter of an incident.
Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good
faith may face temporary or permanent repercussions as determined by other
members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
available at [http://contributor-covenant.org/version/1/4][version]
[homepage]: http://contributor-covenant.org
[version]: http://contributor-covenant.org/version/1/4/

202
vendor/github.com/go-openapi/swag/LICENSE generated vendored Normal file
View file

@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

22
vendor/github.com/go-openapi/swag/README.md generated vendored Normal file
View file

@ -0,0 +1,22 @@
# Swag [![Build Status](https://travis-ci.org/go-openapi/swag.svg?branch=master)](https://travis-ci.org/go-openapi/swag) [![codecov](https://codecov.io/gh/go-openapi/swag/branch/master/graph/badge.svg)](https://codecov.io/gh/go-openapi/swag) [![Slack Status](https://slackin.goswagger.io/badge.svg)](https://slackin.goswagger.io)
[![license](http://img.shields.io/badge/license-Apache%20v2-orange.svg)](https://raw.githubusercontent.com/go-openapi/swag/master/LICENSE)
[![GoDoc](https://godoc.org/github.com/go-openapi/swag?status.svg)](http://godoc.org/github.com/go-openapi/swag)
[![GolangCI](https://golangci.com/badges/github.com/go-openapi/swag.svg)](https://golangci.com)
[![Go Report Card](https://goreportcard.com/badge/github.com/go-openapi/swag)](https://goreportcard.com/report/github.com/go-openapi/swag)
Contains a bunch of helper functions for go-openapi and go-swagger projects.
You may also use it standalone for your projects.
* convert between value and pointers for builtin types
* convert from string to builtin types (wraps strconv)
* fast json concatenation
* search in path
* load from file or http
* name mangling
This repo has only few dependencies outside of the standard library:
* YAML utilities depend on gopkg.in/yaml.v2

208
vendor/github.com/go-openapi/swag/convert.go generated vendored Normal file
View file

@ -0,0 +1,208 @@
// Copyright 2015 go-swagger maintainers
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package swag
import (
"math"
"strconv"
"strings"
)
// same as ECMA Number.MAX_SAFE_INTEGER and Number.MIN_SAFE_INTEGER
const (
maxJSONFloat = float64(1<<53 - 1) // 9007199254740991.0 2^53 - 1
minJSONFloat = -float64(1<<53 - 1) //-9007199254740991.0 -2^53 - 1
epsilon float64 = 1e-9
)
// IsFloat64AJSONInteger allow for integers [-2^53, 2^53-1] inclusive
func IsFloat64AJSONInteger(f float64) bool {
if math.IsNaN(f) || math.IsInf(f, 0) || f < minJSONFloat || f > maxJSONFloat {
return false
}
fa := math.Abs(f)
g := float64(uint64(f))
ga := math.Abs(g)
diff := math.Abs(f - g)
// more info: https://floating-point-gui.de/errors/comparison/#look-out-for-edge-cases
switch {
case f == g: // best case
return true
case f == float64(int64(f)) || f == float64(uint64(f)): // optimistic case
return true
case f == 0 || g == 0 || diff < math.SmallestNonzeroFloat64: // very close to 0 values
return diff < (epsilon * math.SmallestNonzeroFloat64)
}
// check the relative error
return diff/math.Min(fa+ga, math.MaxFloat64) < epsilon
}
var evaluatesAsTrue map[string]struct{}
func init() {
evaluatesAsTrue = map[string]struct{}{
"true": {},
"1": {},
"yes": {},
"ok": {},
"y": {},
"on": {},
"selected": {},
"checked": {},
"t": {},
"enabled": {},
}
}
// ConvertBool turn a string into a boolean
func ConvertBool(str string) (bool, error) {
_, ok := evaluatesAsTrue[strings.ToLower(str)]
return ok, nil
}
// ConvertFloat32 turn a string into a float32
func ConvertFloat32(str string) (float32, error) {
f, err := strconv.ParseFloat(str, 32)
if err != nil {
return 0, err
}
return float32(f), nil
}
// ConvertFloat64 turn a string into a float64
func ConvertFloat64(str string) (float64, error) {
return strconv.ParseFloat(str, 64)
}
// ConvertInt8 turn a string into int8 boolean
func ConvertInt8(str string) (int8, error) {
i, err := strconv.ParseInt(str, 10, 8)
if err != nil {
return 0, err
}
return int8(i), nil
}
// ConvertInt16 turn a string into a int16
func ConvertInt16(str string) (int16, error) {
i, err := strconv.ParseInt(str, 10, 16)
if err != nil {
return 0, err
}
return int16(i), nil
}
// ConvertInt32 turn a string into a int32
func ConvertInt32(str string) (int32, error) {
i, err := strconv.ParseInt(str, 10, 32)
if err != nil {
return 0, err
}
return int32(i), nil
}
// ConvertInt64 turn a string into a int64
func ConvertInt64(str string) (int64, error) {
return strconv.ParseInt(str, 10, 64)
}
// ConvertUint8 turn a string into a uint8
func ConvertUint8(str string) (uint8, error) {
i, err := strconv.ParseUint(str, 10, 8)
if err != nil {
return 0, err
}
return uint8(i), nil
}
// ConvertUint16 turn a string into a uint16
func ConvertUint16(str string) (uint16, error) {
i, err := strconv.ParseUint(str, 10, 16)
if err != nil {
return 0, err
}
return uint16(i), nil
}
// ConvertUint32 turn a string into a uint32
func ConvertUint32(str string) (uint32, error) {
i, err := strconv.ParseUint(str, 10, 32)
if err != nil {
return 0, err
}
return uint32(i), nil
}
// ConvertUint64 turn a string into a uint64
func ConvertUint64(str string) (uint64, error) {
return strconv.ParseUint(str, 10, 64)
}
// FormatBool turns a boolean into a string
func FormatBool(value bool) string {
return strconv.FormatBool(value)
}
// FormatFloat32 turns a float32 into a string
func FormatFloat32(value float32) string {
return strconv.FormatFloat(float64(value), 'f', -1, 32)
}
// FormatFloat64 turns a float64 into a string
func FormatFloat64(value float64) string {
return strconv.FormatFloat(value, 'f', -1, 64)
}
// FormatInt8 turns an int8 into a string
func FormatInt8(value int8) string {
return strconv.FormatInt(int64(value), 10)
}
// FormatInt16 turns an int16 into a string
func FormatInt16(value int16) string {
return strconv.FormatInt(int64(value), 10)
}
// FormatInt32 turns an int32 into a string
func FormatInt32(value int32) string {
return strconv.Itoa(int(value))
}
// FormatInt64 turns an int64 into a string
func FormatInt64(value int64) string {
return strconv.FormatInt(value, 10)
}
// FormatUint8 turns an uint8 into a string
func FormatUint8(value uint8) string {
return strconv.FormatUint(uint64(value), 10)
}
// FormatUint16 turns an uint16 into a string
func FormatUint16(value uint16) string {
return strconv.FormatUint(uint64(value), 10)
}
// FormatUint32 turns an uint32 into a string
func FormatUint32(value uint32) string {
return strconv.FormatUint(uint64(value), 10)
}
// FormatUint64 turns an uint64 into a string
func FormatUint64(value uint64) string {
return strconv.FormatUint(value, 10)
}

595
vendor/github.com/go-openapi/swag/convert_types.go generated vendored Normal file
View file

@ -0,0 +1,595 @@
package swag
import "time"
// This file was taken from the aws go sdk
// String returns a pointer to of the string value passed in.
func String(v string) *string {
return &v
}
// StringValue returns the value of the string pointer passed in or
// "" if the pointer is nil.
func StringValue(v *string) string {
if v != nil {
return *v
}
return ""
}
// StringSlice converts a slice of string values into a slice of
// string pointers
func StringSlice(src []string) []*string {
dst := make([]*string, len(src))
for i := 0; i < len(src); i++ {
dst[i] = &(src[i])
}
return dst
}
// StringValueSlice converts a slice of string pointers into a slice of
// string values
func StringValueSlice(src []*string) []string {
dst := make([]string, len(src))
for i := 0; i < len(src); i++ {
if src[i] != nil {
dst[i] = *(src[i])
}
}
return dst
}
// StringMap converts a string map of string values into a string
// map of string pointers
func StringMap(src map[string]string) map[string]*string {
dst := make(map[string]*string)
for k, val := range src {
v := val
dst[k] = &v
}
return dst
}
// StringValueMap converts a string map of string pointers into a string
// map of string values
func StringValueMap(src map[string]*string) map[string]string {
dst := make(map[string]string)
for k, val := range src {
if val != nil {
dst[k] = *val
}
}
return dst
}
// Bool returns a pointer to of the bool value passed in.
func Bool(v bool) *bool {
return &v
}
// BoolValue returns the value of the bool pointer passed in or
// false if the pointer is nil.
func BoolValue(v *bool) bool {
if v != nil {
return *v
}
return false
}
// BoolSlice converts a slice of bool values into a slice of
// bool pointers
func BoolSlice(src []bool) []*bool {
dst := make([]*bool, len(src))
for i := 0; i < len(src); i++ {
dst[i] = &(src[i])
}
return dst
}
// BoolValueSlice converts a slice of bool pointers into a slice of
// bool values
func BoolValueSlice(src []*bool) []bool {
dst := make([]bool, len(src))
for i := 0; i < len(src); i++ {
if src[i] != nil {
dst[i] = *(src[i])
}
}
return dst
}
// BoolMap converts a string map of bool values into a string
// map of bool pointers
func BoolMap(src map[string]bool) map[string]*bool {
dst := make(map[string]*bool)
for k, val := range src {
v := val
dst[k] = &v
}
return dst
}
// BoolValueMap converts a string map of bool pointers into a string
// map of bool values
func BoolValueMap(src map[string]*bool) map[string]bool {
dst := make(map[string]bool)
for k, val := range src {
if val != nil {
dst[k] = *val
}
}
return dst
}
// Int returns a pointer to of the int value passed in.
func Int(v int) *int {
return &v
}
// IntValue returns the value of the int pointer passed in or
// 0 if the pointer is nil.
func IntValue(v *int) int {
if v != nil {
return *v
}
return 0
}
// IntSlice converts a slice of int values into a slice of
// int pointers
func IntSlice(src []int) []*int {
dst := make([]*int, len(src))
for i := 0; i < len(src); i++ {
dst[i] = &(src[i])
}
return dst
}
// IntValueSlice converts a slice of int pointers into a slice of
// int values
func IntValueSlice(src []*int) []int {
dst := make([]int, len(src))
for i := 0; i < len(src); i++ {
if src[i] != nil {
dst[i] = *(src[i])
}
}
return dst
}
// IntMap converts a string map of int values into a string
// map of int pointers
func IntMap(src map[string]int) map[string]*int {
dst := make(map[string]*int)
for k, val := range src {
v := val
dst[k] = &v
}
return dst
}
// IntValueMap converts a string map of int pointers into a string
// map of int values
func IntValueMap(src map[string]*int) map[string]int {
dst := make(map[string]int)
for k, val := range src {
if val != nil {
dst[k] = *val
}
}
return dst
}
// Int32 returns a pointer to of the int64 value passed in.
func Int32(v int32) *int32 {
return &v
}
// Int32Value returns the value of the int64 pointer passed in or
// 0 if the pointer is nil.
func Int32Value(v *int32) int32 {
if v != nil {
return *v
}
return 0
}
// Int32Slice converts a slice of int64 values into a slice of
// int32 pointers
func Int32Slice(src []int32) []*int32 {
dst := make([]*int32, len(src))
for i := 0; i < len(src); i++ {
dst[i] = &(src[i])
}
return dst
}
// Int32ValueSlice converts a slice of int32 pointers into a slice of
// int32 values
func Int32ValueSlice(src []*int32) []int32 {
dst := make([]int32, len(src))
for i := 0; i < len(src); i++ {
if src[i] != nil {
dst[i] = *(src[i])
}
}
return dst
}
// Int32Map converts a string map of int32 values into a string
// map of int32 pointers
func Int32Map(src map[string]int32) map[string]*int32 {
dst := make(map[string]*int32)
for k, val := range src {
v := val
dst[k] = &v
}
return dst
}
// Int32ValueMap converts a string map of int32 pointers into a string
// map of int32 values
func Int32ValueMap(src map[string]*int32) map[string]int32 {
dst := make(map[string]int32)
for k, val := range src {
if val != nil {
dst[k] = *val
}
}
return dst
}
// Int64 returns a pointer to of the int64 value passed in.
func Int64(v int64) *int64 {
return &v
}
// Int64Value returns the value of the int64 pointer passed in or
// 0 if the pointer is nil.
func Int64Value(v *int64) int64 {
if v != nil {
return *v
}
return 0
}
// Int64Slice converts a slice of int64 values into a slice of
// int64 pointers
func Int64Slice(src []int64) []*int64 {
dst := make([]*int64, len(src))
for i := 0; i < len(src); i++ {
dst[i] = &(src[i])
}
return dst
}
// Int64ValueSlice converts a slice of int64 pointers into a slice of
// int64 values
func Int64ValueSlice(src []*int64) []int64 {
dst := make([]int64, len(src))
for i := 0; i < len(src); i++ {
if src[i] != nil {
dst[i] = *(src[i])
}
}
return dst
}
// Int64Map converts a string map of int64 values into a string
// map of int64 pointers
func Int64Map(src map[string]int64) map[string]*int64 {
dst := make(map[string]*int64)
for k, val := range src {
v := val
dst[k] = &v
}
return dst
}
// Int64ValueMap converts a string map of int64 pointers into a string
// map of int64 values
func Int64ValueMap(src map[string]*int64) map[string]int64 {
dst := make(map[string]int64)
for k, val := range src {
if val != nil {
dst[k] = *val
}
}
return dst
}
// Uint returns a pouinter to of the uint value passed in.
func Uint(v uint) *uint {
return &v
}
// UintValue returns the value of the uint pouinter passed in or
// 0 if the pouinter is nil.
func UintValue(v *uint) uint {
if v != nil {
return *v
}
return 0
}
// UintSlice converts a slice of uint values uinto a slice of
// uint pouinters
func UintSlice(src []uint) []*uint {
dst := make([]*uint, len(src))
for i := 0; i < len(src); i++ {
dst[i] = &(src[i])
}
return dst
}
// UintValueSlice converts a slice of uint pouinters uinto a slice of
// uint values
func UintValueSlice(src []*uint) []uint {
dst := make([]uint, len(src))
for i := 0; i < len(src); i++ {
if src[i] != nil {
dst[i] = *(src[i])
}
}
return dst
}
// UintMap converts a string map of uint values uinto a string
// map of uint pouinters
func UintMap(src map[string]uint) map[string]*uint {
dst := make(map[string]*uint)
for k, val := range src {
v := val
dst[k] = &v
}
return dst
}
// UintValueMap converts a string map of uint pouinters uinto a string
// map of uint values
func UintValueMap(src map[string]*uint) map[string]uint {
dst := make(map[string]uint)
for k, val := range src {
if val != nil {
dst[k] = *val
}
}
return dst
}
// Uint32 returns a pouinter to of the uint64 value passed in.
func Uint32(v uint32) *uint32 {
return &v
}
// Uint32Value returns the value of the uint64 pouinter passed in or
// 0 if the pouinter is nil.
func Uint32Value(v *uint32) uint32 {
if v != nil {
return *v
}
return 0
}
// Uint32Slice converts a slice of uint64 values uinto a slice of
// uint32 pouinters
func Uint32Slice(src []uint32) []*uint32 {
dst := make([]*uint32, len(src))
for i := 0; i < len(src); i++ {
dst[i] = &(src[i])
}
return dst
}
// Uint32ValueSlice converts a slice of uint32 pouinters uinto a slice of
// uint32 values
func Uint32ValueSlice(src []*uint32) []uint32 {
dst := make([]uint32, len(src))
for i := 0; i < len(src); i++ {
if src[i] != nil {
dst[i] = *(src[i])
}
}
return dst
}
// Uint32Map converts a string map of uint32 values uinto a string
// map of uint32 pouinters
func Uint32Map(src map[string]uint32) map[string]*uint32 {
dst := make(map[string]*uint32)
for k, val := range src {
v := val
dst[k] = &v
}
return dst
}
// Uint32ValueMap converts a string map of uint32 pouinters uinto a string
// map of uint32 values
func Uint32ValueMap(src map[string]*uint32) map[string]uint32 {
dst := make(map[string]uint32)
for k, val := range src {
if val != nil {
dst[k] = *val
}
}
return dst
}
// Uint64 returns a pouinter to of the uint64 value passed in.
func Uint64(v uint64) *uint64 {
return &v
}
// Uint64Value returns the value of the uint64 pouinter passed in or
// 0 if the pouinter is nil.
func Uint64Value(v *uint64) uint64 {
if v != nil {
return *v
}
return 0
}
// Uint64Slice converts a slice of uint64 values uinto a slice of
// uint64 pouinters
func Uint64Slice(src []uint64) []*uint64 {
dst := make([]*uint64, len(src))
for i := 0; i < len(src); i++ {
dst[i] = &(src[i])
}
return dst
}
// Uint64ValueSlice converts a slice of uint64 pouinters uinto a slice of
// uint64 values
func Uint64ValueSlice(src []*uint64) []uint64 {
dst := make([]uint64, len(src))
for i := 0; i < len(src); i++ {
if src[i] != nil {
dst[i] = *(src[i])
}
}
return dst
}
// Uint64Map converts a string map of uint64 values uinto a string
// map of uint64 pouinters
func Uint64Map(src map[string]uint64) map[string]*uint64 {
dst := make(map[string]*uint64)
for k, val := range src {
v := val
dst[k] = &v
}
return dst
}
// Uint64ValueMap converts a string map of uint64 pouinters uinto a string
// map of uint64 values
func Uint64ValueMap(src map[string]*uint64) map[string]uint64 {
dst := make(map[string]uint64)
for k, val := range src {
if val != nil {
dst[k] = *val
}
}
return dst
}
// Float64 returns a pointer to of the float64 value passed in.
func Float64(v float64) *float64 {
return &v
}
// Float64Value returns the value of the float64 pointer passed in or
// 0 if the pointer is nil.
func Float64Value(v *float64) float64 {
if v != nil {
return *v
}
return 0
}
// Float64Slice converts a slice of float64 values into a slice of
// float64 pointers
func Float64Slice(src []float64) []*float64 {
dst := make([]*float64, len(src))
for i := 0; i < len(src); i++ {
dst[i] = &(src[i])
}
return dst
}
// Float64ValueSlice converts a slice of float64 pointers into a slice of
// float64 values
func Float64ValueSlice(src []*float64) []float64 {
dst := make([]float64, len(src))
for i := 0; i < len(src); i++ {
if src[i] != nil {
dst[i] = *(src[i])
}
}
return dst
}
// Float64Map converts a string map of float64 values into a string
// map of float64 pointers
func Float64Map(src map[string]float64) map[string]*float64 {
dst := make(map[string]*float64)
for k, val := range src {
v := val
dst[k] = &v
}
return dst
}
// Float64ValueMap converts a string map of float64 pointers into a string
// map of float64 values
func Float64ValueMap(src map[string]*float64) map[string]float64 {
dst := make(map[string]float64)
for k, val := range src {
if val != nil {
dst[k] = *val
}
}
return dst
}
// Time returns a pointer to of the time.Time value passed in.
func Time(v time.Time) *time.Time {
return &v
}
// TimeValue returns the value of the time.Time pointer passed in or
// time.Time{} if the pointer is nil.
func TimeValue(v *time.Time) time.Time {
if v != nil {
return *v
}
return time.Time{}
}
// TimeSlice converts a slice of time.Time values into a slice of
// time.Time pointers
func TimeSlice(src []time.Time) []*time.Time {
dst := make([]*time.Time, len(src))
for i := 0; i < len(src); i++ {
dst[i] = &(src[i])
}
return dst
}
// TimeValueSlice converts a slice of time.Time pointers into a slice of
// time.Time values
func TimeValueSlice(src []*time.Time) []time.Time {
dst := make([]time.Time, len(src))
for i := 0; i < len(src); i++ {
if src[i] != nil {
dst[i] = *(src[i])
}
}
return dst
}
// TimeMap converts a string map of time.Time values into a string
// map of time.Time pointers
func TimeMap(src map[string]time.Time) map[string]*time.Time {
dst := make(map[string]*time.Time)
for k, val := range src {
v := val
dst[k] = &v
}
return dst
}
// TimeValueMap converts a string map of time.Time pointers into a string
// map of time.Time values
func TimeValueMap(src map[string]*time.Time) map[string]time.Time {
dst := make(map[string]time.Time)
for k, val := range src {
if val != nil {
dst[k] = *val
}
}
return dst
}

32
vendor/github.com/go-openapi/swag/doc.go generated vendored Normal file
View file

@ -0,0 +1,32 @@
// Copyright 2015 go-swagger maintainers
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*
Package swag contains a bunch of helper functions for go-openapi and go-swagger projects.
You may also use it standalone for your projects.
* convert between value and pointers for builtin types
* convert from string to builtin types (wraps strconv)
* fast json concatenation
* search in path
* load from file or http
* name mangling
This repo has only few dependencies outside of the standard library:
* YAML utilities depend on gopkg.in/yaml.v2
*/
package swag

14
vendor/github.com/go-openapi/swag/go.mod generated vendored Normal file
View file

@ -0,0 +1,14 @@
module github.com/go-openapi/swag
require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/kr/pretty v0.1.0 // indirect
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63
github.com/stretchr/testify v1.3.0
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect
gopkg.in/yaml.v2 v2.2.2
)
replace github.com/golang/lint => golang.org/x/lint v0.0.0-20190409202823-959b441ac422
replace sourcegraph.com/sourcegraph/go-diff => github.com/sourcegraph/go-diff v0.5.1

20
vendor/github.com/go-openapi/swag/go.sum generated vendored Normal file
View file

@ -0,0 +1,20 @@
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/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63 h1:nTT4s92Dgz2HlrB2NaMgvlfqHH39OgMhA7z3PK7PGD4=
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
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.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

312
vendor/github.com/go-openapi/swag/json.go generated vendored Normal file
View file

@ -0,0 +1,312 @@
// Copyright 2015 go-swagger maintainers
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package swag
import (
"bytes"
"encoding/json"
"log"
"reflect"
"strings"
"sync"
"github.com/mailru/easyjson/jlexer"
"github.com/mailru/easyjson/jwriter"
)
// nullJSON represents a JSON object with null type
var nullJSON = []byte("null")
// DefaultJSONNameProvider the default cache for types
var DefaultJSONNameProvider = NewNameProvider()
const comma = byte(',')
var closers map[byte]byte
func init() {
closers = map[byte]byte{
'{': '}',
'[': ']',
}
}
type ejMarshaler interface {
MarshalEasyJSON(w *jwriter.Writer)
}
type ejUnmarshaler interface {
UnmarshalEasyJSON(w *jlexer.Lexer)
}
// WriteJSON writes json data, prefers finding an appropriate interface to short-circuit the marshaller
// so it takes the fastest option available.
func WriteJSON(data interface{}) ([]byte, error) {
if d, ok := data.(ejMarshaler); ok {
jw := new(jwriter.Writer)
d.MarshalEasyJSON(jw)
return jw.BuildBytes()
}
if d, ok := data.(json.Marshaler); ok {
return d.MarshalJSON()
}
return json.Marshal(data)
}
// ReadJSON reads json data, prefers finding an appropriate interface to short-circuit the unmarshaller
// so it takes the fastes option available
func ReadJSON(data []byte, value interface{}) error {
trimmedData := bytes.Trim(data, "\x00")
if d, ok := value.(ejUnmarshaler); ok {
jl := &jlexer.Lexer{Data: trimmedData}
d.UnmarshalEasyJSON(jl)
return jl.Error()
}
if d, ok := value.(json.Unmarshaler); ok {
return d.UnmarshalJSON(trimmedData)
}
return json.Unmarshal(trimmedData, value)
}
// DynamicJSONToStruct converts an untyped json structure into a struct
func DynamicJSONToStruct(data interface{}, target interface{}) error {
// TODO: convert straight to a json typed map (mergo + iterate?)
b, err := WriteJSON(data)
if err != nil {
return err
}
return ReadJSON(b, target)
}
// ConcatJSON concatenates multiple json objects efficiently
func ConcatJSON(blobs ...[]byte) []byte {
if len(blobs) == 0 {
return nil
}
last := len(blobs) - 1
for blobs[last] == nil || bytes.Equal(blobs[last], nullJSON) {
// strips trailing null objects
last--
if last < 0 {
// there was nothing but "null"s or nil...
return nil
}
}
if last == 0 {
return blobs[0]
}
var opening, closing byte
var idx, a int
buf := bytes.NewBuffer(nil)
for i, b := range blobs[:last+1] {
if b == nil || bytes.Equal(b, nullJSON) {
// a null object is in the list: skip it
continue
}
if len(b) > 0 && opening == 0 { // is this an array or an object?
opening, closing = b[0], closers[b[0]]
}
if opening != '{' && opening != '[' {
continue // don't know how to concatenate non container objects
}
if len(b) < 3 { // yep empty but also the last one, so closing this thing
if i == last && a > 0 {
if err := buf.WriteByte(closing); err != nil {
log.Println(err)
}
}
continue
}
idx = 0
if a > 0 { // we need to join with a comma for everything beyond the first non-empty item
if err := buf.WriteByte(comma); err != nil {
log.Println(err)
}
idx = 1 // this is not the first or the last so we want to drop the leading bracket
}
if i != last { // not the last one, strip brackets
if _, err := buf.Write(b[idx : len(b)-1]); err != nil {
log.Println(err)
}
} else { // last one, strip only the leading bracket
if _, err := buf.Write(b[idx:]); err != nil {
log.Println(err)
}
}
a++
}
// somehow it ended up being empty, so provide a default value
if buf.Len() == 0 {
if err := buf.WriteByte(opening); err != nil {
log.Println(err)
}
if err := buf.WriteByte(closing); err != nil {
log.Println(err)
}
}
return buf.Bytes()
}
// ToDynamicJSON turns an object into a properly JSON typed structure
func ToDynamicJSON(data interface{}) interface{} {
// TODO: convert straight to a json typed map (mergo + iterate?)
b, err := json.Marshal(data)
if err != nil {
log.Println(err)
}
var res interface{}
if err := json.Unmarshal(b, &res); err != nil {
log.Println(err)
}
return res
}
// FromDynamicJSON turns an object into a properly JSON typed structure
func FromDynamicJSON(data, target interface{}) error {
b, err := json.Marshal(data)
if err != nil {
log.Println(err)
}
return json.Unmarshal(b, target)
}
// NameProvider represents an object capabale of translating from go property names
// to json property names
// This type is thread-safe.
type NameProvider struct {
lock *sync.Mutex
index map[reflect.Type]nameIndex
}
type nameIndex struct {
jsonNames map[string]string
goNames map[string]string
}
// NewNameProvider creates a new name provider
func NewNameProvider() *NameProvider {
return &NameProvider{
lock: &sync.Mutex{},
index: make(map[reflect.Type]nameIndex),
}
}
func buildnameIndex(tpe reflect.Type, idx, reverseIdx map[string]string) {
for i := 0; i < tpe.NumField(); i++ {
targetDes := tpe.Field(i)
if targetDes.PkgPath != "" { // unexported
continue
}
if targetDes.Anonymous { // walk embedded structures tree down first
buildnameIndex(targetDes.Type, idx, reverseIdx)
continue
}
if tag := targetDes.Tag.Get("json"); tag != "" {
parts := strings.Split(tag, ",")
if len(parts) == 0 {
continue
}
nm := parts[0]
if nm == "-" {
continue
}
if nm == "" { // empty string means we want to use the Go name
nm = targetDes.Name
}
idx[nm] = targetDes.Name
reverseIdx[targetDes.Name] = nm
}
}
}
func newNameIndex(tpe reflect.Type) nameIndex {
var idx = make(map[string]string, tpe.NumField())
var reverseIdx = make(map[string]string, tpe.NumField())
buildnameIndex(tpe, idx, reverseIdx)
return nameIndex{jsonNames: idx, goNames: reverseIdx}
}
// GetJSONNames gets all the json property names for a type
func (n *NameProvider) GetJSONNames(subject interface{}) []string {
n.lock.Lock()
defer n.lock.Unlock()
tpe := reflect.Indirect(reflect.ValueOf(subject)).Type()
names, ok := n.index[tpe]
if !ok {
names = n.makeNameIndex(tpe)
}
res := make([]string, 0, len(names.jsonNames))
for k := range names.jsonNames {
res = append(res, k)
}
return res
}
// GetJSONName gets the json name for a go property name
func (n *NameProvider) GetJSONName(subject interface{}, name string) (string, bool) {
tpe := reflect.Indirect(reflect.ValueOf(subject)).Type()
return n.GetJSONNameForType(tpe, name)
}
// GetJSONNameForType gets the json name for a go property name on a given type
func (n *NameProvider) GetJSONNameForType(tpe reflect.Type, name string) (string, bool) {
n.lock.Lock()
defer n.lock.Unlock()
names, ok := n.index[tpe]
if !ok {
names = n.makeNameIndex(tpe)
}
nme, ok := names.goNames[name]
return nme, ok
}
func (n *NameProvider) makeNameIndex(tpe reflect.Type) nameIndex {
names := newNameIndex(tpe)
n.index[tpe] = names
return names
}
// GetGoName gets the go name for a json property name
func (n *NameProvider) GetGoName(subject interface{}, name string) (string, bool) {
tpe := reflect.Indirect(reflect.ValueOf(subject)).Type()
return n.GetGoNameForType(tpe, name)
}
// GetGoNameForType gets the go name for a given type for a json property name
func (n *NameProvider) GetGoNameForType(tpe reflect.Type, name string) (string, bool) {
n.lock.Lock()
defer n.lock.Unlock()
names, ok := n.index[tpe]
if !ok {
names = n.makeNameIndex(tpe)
}
nme, ok := names.jsonNames[name]
return nme, ok
}

80
vendor/github.com/go-openapi/swag/loading.go generated vendored Normal file
View file

@ -0,0 +1,80 @@
// Copyright 2015 go-swagger maintainers
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package swag
import (
"fmt"
"io/ioutil"
"log"
"net/http"
"path/filepath"
"strings"
"time"
)
// LoadHTTPTimeout the default timeout for load requests
var LoadHTTPTimeout = 30 * time.Second
// LoadFromFileOrHTTP loads the bytes from a file or a remote http server based on the path passed in
func LoadFromFileOrHTTP(path string) ([]byte, error) {
return LoadStrategy(path, ioutil.ReadFile, loadHTTPBytes(LoadHTTPTimeout))(path)
}
// LoadFromFileOrHTTPWithTimeout loads the bytes from a file or a remote http server based on the path passed in
// timeout arg allows for per request overriding of the request timeout
func LoadFromFileOrHTTPWithTimeout(path string, timeout time.Duration) ([]byte, error) {
return LoadStrategy(path, ioutil.ReadFile, loadHTTPBytes(timeout))(path)
}
// LoadStrategy returns a loader function for a given path or uri
func LoadStrategy(path string, local, remote func(string) ([]byte, error)) func(string) ([]byte, error) {
if strings.HasPrefix(path, "http") {
return remote
}
return func(pth string) ([]byte, error) {
upth, err := pathUnescape(pth)
if err != nil {
return nil, err
}
return local(filepath.FromSlash(upth))
}
}
func loadHTTPBytes(timeout time.Duration) func(path string) ([]byte, error) {
return func(path string) ([]byte, error) {
client := &http.Client{Timeout: timeout}
req, err := http.NewRequest("GET", path, nil)
if err != nil {
return nil, err
}
resp, err := client.Do(req)
defer func() {
if resp != nil {
if e := resp.Body.Close(); e != nil {
log.Println(e)
}
}
}()
if err != nil {
return nil, err
}
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("could not access document at %q [%s] ", path, resp.Status)
}
return ioutil.ReadAll(resp.Body)
}
}

87
vendor/github.com/go-openapi/swag/name_lexem.go generated vendored Normal file
View file

@ -0,0 +1,87 @@
// Copyright 2015 go-swagger maintainers
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package swag
import "unicode"
type (
nameLexem interface {
GetUnsafeGoName() string
GetOriginal() string
IsInitialism() bool
}
initialismNameLexem struct {
original string
matchedInitialism string
}
casualNameLexem struct {
original string
}
)
func newInitialismNameLexem(original, matchedInitialism string) *initialismNameLexem {
return &initialismNameLexem{
original: original,
matchedInitialism: matchedInitialism,
}
}
func newCasualNameLexem(original string) *casualNameLexem {
return &casualNameLexem{
original: original,
}
}
func (l *initialismNameLexem) GetUnsafeGoName() string {
return l.matchedInitialism
}
func (l *casualNameLexem) GetUnsafeGoName() string {
var first rune
var rest string
for i, orig := range l.original {
if i == 0 {
first = orig
continue
}
if i > 0 {
rest = l.original[i:]
break
}
}
if len(l.original) > 1 {
return string(unicode.ToUpper(first)) + lower(rest)
}
return l.original
}
func (l *initialismNameLexem) GetOriginal() string {
return l.original
}
func (l *casualNameLexem) GetOriginal() string {
return l.original
}
func (l *initialismNameLexem) IsInitialism() bool {
return true
}
func (l *casualNameLexem) IsInitialism() bool {
return false
}

38
vendor/github.com/go-openapi/swag/net.go generated vendored Normal file
View file

@ -0,0 +1,38 @@
// Copyright 2015 go-swagger maintainers
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package swag
import (
"net"
"strconv"
)
// SplitHostPort splits a network address into a host and a port.
// The port is -1 when there is no port to be found
func SplitHostPort(addr string) (host string, port int, err error) {
h, p, err := net.SplitHostPort(addr)
if err != nil {
return "", -1, err
}
if p == "" {
return "", -1, &net.AddrError{Err: "missing port in address", Addr: addr}
}
pi, err := strconv.Atoi(p)
if err != nil {
return "", -1, err
}
return h, pi, nil
}

59
vendor/github.com/go-openapi/swag/path.go generated vendored Normal file
View file

@ -0,0 +1,59 @@
// Copyright 2015 go-swagger maintainers
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package swag
import (
"os"
"path/filepath"
"runtime"
"strings"
)
const (
// GOPATHKey represents the env key for gopath
GOPATHKey = "GOPATH"
)
// FindInSearchPath finds a package in a provided lists of paths
func FindInSearchPath(searchPath, pkg string) string {
pathsList := filepath.SplitList(searchPath)
for _, path := range pathsList {
if evaluatedPath, err := filepath.EvalSymlinks(filepath.Join(path, "src", pkg)); err == nil {
if _, err := os.Stat(evaluatedPath); err == nil {
return evaluatedPath
}
}
}
return ""
}
// FindInGoSearchPath finds a package in the $GOPATH:$GOROOT
func FindInGoSearchPath(pkg string) string {
return FindInSearchPath(FullGoSearchPath(), pkg)
}
// FullGoSearchPath gets the search paths for finding packages
func FullGoSearchPath() string {
allPaths := os.Getenv(GOPATHKey)
if allPaths == "" {
allPaths = filepath.Join(os.Getenv("HOME"), "go")
}
if allPaths != "" {
allPaths = strings.Join([]string{allPaths, runtime.GOROOT()}, ":")
} else {
allPaths = runtime.GOROOT()
}
return allPaths
}

23
vendor/github.com/go-openapi/swag/post_go18.go generated vendored Normal file
View file

@ -0,0 +1,23 @@
// Copyright 2015 go-swagger maintainers
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// +build go1.8
package swag
import "net/url"
func pathUnescape(path string) (string, error) {
return url.PathUnescape(path)
}

Some files were not shown because too many files have changed in this diff Show more