Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 3 additions & 22 deletions .github/workflows/golangci-lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,28 +21,9 @@ jobs:
steps:
- uses: actions/setup-go@v5
with:
go-version: stable
go-version: oldstable
- uses: actions/checkout@v4
- name: golangci-lint
uses: golangci/golangci-lint-action@v8.0.0
uses: golangci/golangci-lint-action@v9.2.0
with:
# Required: the version of golangci-lint is required and must be specified without patch version: we always use the latest patch version.
version: v2.4.0

# Optional: working directory, useful for monorepos
# working-directory: somedir

# Optional: golangci-lint command line arguments.
# args: --issues-exit-code=0

# Optional: show only new issues if it's a pull request. The default value is `false`.
# only-new-issues: true

# Optional: if set to true then the action will use pre-installed Go.
# skip-go-installation: true

# Optional: if set to true then the action don't cache or restore ~/go/pkg.
# skip-pkg-cache: true

# Optional: if set to true then the action don't cache or restore ~/.cache/go-build.
# skip-build-cache: true
version: v2.11.3
1 change: 1 addition & 0 deletions .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ run:
linters:
default: all
disable:
- modernize
- embeddedstructfieldcheck
- nilnil
- noinlineerr
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#GOLANGCI_LINT_VERSION := "v2.5.0" # Optional configuration to pinpoint golangci-lint version.
#GOLANGCI_LINT_VERSION := "v2.11.3" # Optional configuration to pinpoint golangci-lint version.

# The head of Makefile determines location of dev-go to include standard targets.
GO ?= go
Expand Down
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -402,6 +402,11 @@ func main() {

## Additional Integrations

Router adapters below are for a different, migration-friendly use case: adding OpenAPI docs to an
*existing* router with plain `http.Handler`/`http.HandlerFunc` routes, without rewriting them as
typed usecase interactors.

* [`github.com/go-chi/chi`](https://github.com/go-chi/chi), see [example](./chirouter/example_openapi_collector_test.go).
* [`github.com/gorilla/mux`](https://github.com/gorilla/mux), see [example](./gorillamux/example_openapi_collector_test.go).

## Performance Optimization
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -629,7 +629,7 @@
"name":"in_query","in":"query","description":"Object value in query.",
"schema":{
"additionalProperties":{"format":"double","type":"number"},"description":"Object value in query.",
"type":["object","null"]
"type":"object"
},
"style":"deepObject","explode":true
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ func Test_directGzip(t *testing.T) {

r.ServeHTTP(rw, req)
assert.Equal(t, http.StatusOK, rw.Code)
assert.Equal(t, "330epditz19z", rw.Header().Get("Etag"))
assert.Equal(t, "1mzg0y3xex17j", rw.Header().Get("Etag"))
assert.Equal(t, "gzip", rw.Header().Get("Content-Encoding"))
assert.Equal(t, "abc", rw.Header().Get("X-Header"))
assert.Less(t, len(rw.Body.Bytes()), 500)
Expand All @@ -49,7 +49,7 @@ func Test_directGzip_HEAD(t *testing.T) {
assert.NoError(t, resp.Body.Close())

assert.Equal(t, http.StatusOK, resp.StatusCode)
assert.Equal(t, "330epditz19z", resp.Header.Get("Etag"))
assert.Equal(t, "1mzg0y3xex17j", resp.Header.Get("Etag"))
assert.Equal(t, "gzip", resp.Header.Get("Content-Encoding"))
assert.Equal(t, "abc", resp.Header.Get("X-Header"))
assert.Empty(t, body)
Expand Down Expand Up @@ -80,7 +80,7 @@ func Test_directGzip_perf(t *testing.T) {
assert.Less(t, res.Extra["B:rcvd/op"], 700.0)
assert.Less(t, res.Extra["B:sent/op"], 104.0)
assert.Less(t, res.AllocsPerOp(), int64(65))
assert.Less(t, res.AllocedBytesPerOp(), int64(8800))
assert.Less(t, res.AllocedBytesPerOp(), int64(8900))
} else {
assert.Less(t, res.Extra["B:rcvd/op"], 700.0)
assert.Less(t, res.Extra["B:sent/op"], 104.0)
Expand Down
8 changes: 4 additions & 4 deletions _examples/advanced/gzip_pass_through_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ func Test_directGzip(t *testing.T) {

r.ServeHTTP(rw, req)
assert.Equal(t, http.StatusOK, rw.Code)
assert.Equal(t, "330epditz19z", rw.Header().Get("Etag"))
assert.Equal(t, "1mzg0y3xex17j", rw.Header().Get("Etag"))
assert.Equal(t, "gzip", rw.Header().Get("Content-Encoding"))
assert.Equal(t, "abc", rw.Header().Get("X-Header"))
assert.Less(t, len(rw.Body.Bytes()), 500)
Expand All @@ -47,7 +47,7 @@ func Test_directGzip_HEAD(t *testing.T) {
assert.NoError(t, resp.Body.Close())

assert.Equal(t, http.StatusOK, resp.StatusCode)
assert.Equal(t, "330epditz19z", resp.Header.Get("Etag"))
assert.Equal(t, "1mzg0y3xex17j", resp.Header.Get("Etag"))
assert.Equal(t, "gzip", resp.Header.Get("Content-Encoding"))
assert.Equal(t, "abc", resp.Header.Get("X-Header"))
assert.Empty(t, body)
Expand Down Expand Up @@ -75,9 +75,9 @@ func Test_directGzip_perf(t *testing.T) {
res := testing.Benchmark(Benchmark_directGzip)

if httptestbench.RaceDetectorEnabled {
assert.Less(t, res.Extra["B:rcvd/op"], 640.0)
assert.Less(t, res.Extra["B:rcvd/op"], 670.0)
assert.Less(t, res.Extra["B:sent/op"], 104.0)
assert.Less(t, res.AllocsPerOp(), int64(60))
assert.Less(t, res.AllocsPerOp(), int64(62))
assert.Less(t, res.AllocedBytesPerOp(), int64(9000))
} else {
assert.Less(t, res.Extra["B:rcvd/op"], 640.0)
Expand Down
8 changes: 4 additions & 4 deletions _examples/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ replace github.com/swaggest/rest => ../

require (
github.com/bool64/ctxd v1.2.1
github.com/bool64/dev v0.2.43
github.com/bool64/dev v0.2.45
github.com/bool64/httpmock v0.1.15
github.com/bool64/httptestbench v0.1.4
github.com/gin-gonic/gin v1.10.0
Expand All @@ -17,8 +17,8 @@ require (
github.com/rs/cors v1.11.1
github.com/stretchr/testify v1.9.0
github.com/swaggest/assertjson v1.9.0
github.com/swaggest/jsonschema-go v0.3.78
github.com/swaggest/openapi-go v0.2.60
github.com/swaggest/jsonschema-go v0.3.79
github.com/swaggest/openapi-go v0.2.61
github.com/swaggest/rest v0.0.0-00010101000000-000000000000
github.com/swaggest/swgui v1.8.2
github.com/swaggest/usecase v1.3.1
Expand All @@ -27,7 +27,7 @@ require (

require (
github.com/andybalholm/brotli v1.1.0 // indirect
github.com/bool64/shared v0.1.5 // indirect
github.com/bool64/shared v0.1.7 // indirect
github.com/bytedance/sonic v1.12.3 // indirect
github.com/bytedance/sonic/loader v0.2.0 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
Expand Down
16 changes: 8 additions & 8 deletions _examples/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@ github.com/bool64/ctxd v1.2.1 h1:hARFteq0zdn4bwfmxLhak3fXFuvtJVKDH2X29VV/2ls=
github.com/bool64/ctxd v1.2.1/go.mod h1:ZG6QkeGVLTiUl2mxPpyHmFhDzFZCyocr9hluBV3LYuc=
github.com/bool64/dev v0.2.5/go.mod h1:cTHiTDNc8EewrQPy3p1obNilpMpdmlUesDkFTF2zRWU=
github.com/bool64/dev v0.2.25/go.mod h1:iJbh1y/HkunEPhgebWRNcs8wfGq7sjvJ6W5iabL8ACg=
github.com/bool64/dev v0.2.43 h1:yQ7qiZVef6WtCl2vDYU0Y+qSq+0aBrQzY8KXkklk9cQ=
github.com/bool64/dev v0.2.43/go.mod h1:iJbh1y/HkunEPhgebWRNcs8wfGq7sjvJ6W5iabL8ACg=
github.com/bool64/dev v0.2.45 h1:3nLKhAS/6Oklk3Mt2lHYSN/Cb4tdAD77KLwzeP+6eYE=
github.com/bool64/dev v0.2.45/go.mod h1:iJbh1y/HkunEPhgebWRNcs8wfGq7sjvJ6W5iabL8ACg=
github.com/bool64/httpmock v0.1.15 h1:PWvuqpew/FEigT7cvv03/t9G+UeE3wD2QP8PVyBBUwc=
github.com/bool64/httpmock v0.1.15/go.mod h1:Ht82vaR7YJu8YHcJoK5mDi5OG6NJfv/MmYfdfod1huQ=
github.com/bool64/httptestbench v0.1.4 h1:35f9RwWqcnQRXM+sA+GUhWVGSa6XEFlKpNSH9oYzOjI=
github.com/bool64/httptestbench v0.1.4/go.mod h1:b9ItXGtscs9AcR5oUDnWCTLosQ/DCjiG4euDbHN8T40=
github.com/bool64/shared v0.1.5 h1:fp3eUhBsrSjNCQPcSdQqZxxh9bBwrYiZ+zOKFkM0/2E=
github.com/bool64/shared v0.1.5/go.mod h1:081yz68YC9jeFB3+Bbmno2RFWvGKv1lPKkMP6MHJlPs=
github.com/bool64/shared v0.1.7 h1:F3ZvBBmPDfMkTOTkSGd7cSoOAKI+SH5vDP9Bo4d0k1U=
github.com/bool64/shared v0.1.7/go.mod h1:M5io4aRK3lj9Rwy/OxS4mvm/LJPlSsL2cfu9z96LAOM=
github.com/bytedance/sonic v1.12.3 h1:W2MGa7RCU1QTeYRTPE3+88mVC0yXmsRQRChiyVocVjU=
github.com/bytedance/sonic v1.12.3/go.mod h1:B8Gt/XvtZ3Fqj+iSKMypzymZxw/FVwgIGKzMzT9r/rk=
github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
Expand Down Expand Up @@ -129,10 +129,10 @@ github.com/swaggest/assertjson v1.9.0 h1:dKu0BfJkIxv/xe//mkCrK5yZbs79jL7OVf9Ija7
github.com/swaggest/assertjson v1.9.0/go.mod h1:b+ZKX2VRiUjxfUIal0HDN85W0nHPAYUbYH5WkkSsFsU=
github.com/swaggest/form/v5 v5.1.1 h1:ct6/rOQBGrqWUQ0FUv3vW5sHvTUb31AwTUWj947N6cY=
github.com/swaggest/form/v5 v5.1.1/go.mod h1:X1hraaoONee20PMnGNLQpO32f9zbQ0Czfm7iZThuEKg=
github.com/swaggest/jsonschema-go v0.3.78 h1:5+YFQrLxOR8z6CHvgtZc42WRy/Q9zRQQ4HoAxlinlHw=
github.com/swaggest/jsonschema-go v0.3.78/go.mod h1:4nniXBuE+FIGkOGuidjOINMH7OEqZK3HCSbfDuLRI0g=
github.com/swaggest/openapi-go v0.2.60 h1:kglHH/WIfqAglfuWL4tu0LPakqNYySzklUWx06SjSKo=
github.com/swaggest/openapi-go v0.2.60/go.mod h1:jmFOuYdsWGtHU0BOuILlHZQJxLqHiAE6en+baE+QQUk=
github.com/swaggest/jsonschema-go v0.3.79 h1:0TOShCbAJ9Xjt1e2W83l+QtMQSG2pbun2EkiYTyafCs=
github.com/swaggest/jsonschema-go v0.3.79/go.mod h1:GqVmJ+XNLeUHhFIhHNKc+C68euxfrl3a3aoZH4vTRl0=
github.com/swaggest/openapi-go v0.2.61 h1:psc+LE7pWhEjmJpmkti9tUmBPkkobdUNflBf5Ps6JSc=
github.com/swaggest/openapi-go v0.2.61/go.mod h1:786CwSwleh1IorB0nfwYGESWf83JgQh6fBc1PeJe4Iw=
github.com/swaggest/refl v1.4.0 h1:CftOSdTqRqs100xpFOT/Rifss5xBV/CT0S/FN60Xe9k=
github.com/swaggest/refl v1.4.0/go.mod h1:4uUVFVfPJ0NSX9FPwMPspeHos9wPFlCMGoPRllUbpvA=
github.com/swaggest/swgui v1.8.2 h1:JGpRCLGLZ7EqTwHsBEOo//kx8CM7Rv3RchgvfNpB+6E=
Expand Down
53 changes: 53 additions & 0 deletions chirouter/collector.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package chirouter

import (
"net/http"

oapi "github.com/swaggest/openapi-go"
"github.com/swaggest/rest/nethttp"
"github.com/swaggest/rest/openapi"
)

// OpenAPICollector is a wrapper for openapi.Collector tailored to walk chi router.
type OpenAPICollector struct {
// Collector is an actual OpenAPI collector.
Collector *openapi.Collector

// OperationExtractor allows flexible extraction of OpenAPI information.
OperationExtractor func(h http.Handler) func(oc oapi.OperationContext) error
}

// NewOpenAPICollector creates route walker for chi, that collects OpenAPI operations.
func NewOpenAPICollector(r oapi.Reflector) *OpenAPICollector {
return &OpenAPICollector{
Collector: openapi.NewCollector(r),
}
}

// OpenAPIPreparer defines http.Handler with OpenAPI information.
type OpenAPIPreparer interface {
SetupOpenAPIOperation(oc oapi.OperationContext) error
}

// Describe attaches OpenAPI documentation to a http.HandlerFunc. Unlike Collector.AnnotateOperation,
// which is keyed by a separately maintained method+pattern string that can drift from the actual
// route, Describe keeps the route registration itself as the single source of truth.
//
// The result implements http.Handler, so register it with a method that accepts one, e.g.
// router.Method(http.MethodGet, pattern, c.Describe(h, setup)).
func (dc *OpenAPICollector) Describe(h http.HandlerFunc, setup func(oc oapi.OperationContext) error) http.Handler {
return nethttp.Describe(h, setup)
}

// Walker walks chi route tree and collects OpenAPI information.
//
// Use it as chi.WalkFunc with chi.Walk.
func (dc *OpenAPICollector) Walker(method, route string, handler http.Handler, _ ...func(http.Handler) http.Handler) error {
if handler == nil {
return nil
}

Check notice on line 48 in chirouter/collector.go

View workflow job for this annotation

GitHub Actions / test (stable)

1 statement(s) are not covered by tests.

preparer := nethttp.Preparer(handler, dc.OperationExtractor)

return nethttp.CollectRouteOperation(dc.Collector, method, route, preparer)
}
Loading
Loading