Skip to content

Commit

Permalink
Add support for error responses with custom descriptions
Browse files Browse the repository at this point in the history
  • Loading branch information
vearutop committed Dec 7, 2023
1 parent 62a510e commit ba64098
Show file tree
Hide file tree
Showing 12 changed files with 59 additions and 37 deletions.
1 change: 1 addition & 0 deletions .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ issues:
path: ".go"
text: "\"io/ioutil\" has been deprecated since Go 1.16" # Keeping backwards compatibility with go1.13.
- linters:
- testifylint
- gomnd
- goconst
- goerr113
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@
}
},
"409":{
"description":"Conflict",
"description":"Response with custom description.",
"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdvancedCustomErr"}}}
},
"412":{
Expand Down
3 changes: 2 additions & 1 deletion _examples/advanced-generic-openapi31/error_response.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ func errorResponse() usecase.Interactor {

u.SetTitle("Declare Expected Errors")
u.SetDescription("This use case demonstrates documentation of expected errors.")
u.SetExpectedErrors(status.InvalidArgument, anotherErr{}, status.FailedPrecondition, status.AlreadyExists)
u.SetExpectedErrors(status.InvalidArgument, anotherErr{}, status.FailedPrecondition,
status.WithDescription(status.AlreadyExists, "Response with custom description."))
u.SetTags("Response")

return u
Expand Down
3 changes: 2 additions & 1 deletion _examples/advanced-generic-openapi31/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,8 @@ func NewRouter() http.Handler {
s.Get("/gzip-pass-through", directGzip())
s.Head("/gzip-pass-through", directGzip())

s.Get("/error-response", errorResponse())
s.Get("/error-response", errorResponse(), func(h *nethttp.Handler) {
})
s.Post("/text-req-body/{path}", textReqBody(), nethttp.RequestBodyContent("text/csv"))
s.Post("/text-req-body-ptr/{path}", textReqBodyPtr(), nethttp.RequestBodyContent("text/csv"))

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.31
github.com/bool64/dev v0.2.32
github.com/bool64/httpmock v0.1.13
github.com/bool64/httptestbench v0.1.4
github.com/gin-gonic/gin v1.9.1
Expand All @@ -17,11 +17,11 @@ require (
github.com/rs/cors v1.9.0
github.com/stretchr/testify v1.8.4
github.com/swaggest/assertjson v1.9.0
github.com/swaggest/jsonschema-go v0.3.62
github.com/swaggest/openapi-go v0.2.41
github.com/swaggest/jsonschema-go v0.3.64
github.com/swaggest/openapi-go v0.2.43
github.com/swaggest/rest v0.0.0-00010101000000-000000000000
github.com/swaggest/swgui v1.7.3
github.com/swaggest/usecase v1.2.1
github.com/swaggest/usecase v1.3.0
github.com/valyala/fasthttp v1.48.0
)

Expand Down
16 changes: 8 additions & 8 deletions _examples/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ 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.31 h1:OS57EqYaYe2M/2bw9uhDCIFiZZwywKFS/4qMLN6JUmQ=
github.com/bool64/dev v0.2.31/go.mod h1:iJbh1y/HkunEPhgebWRNcs8wfGq7sjvJ6W5iabL8ACg=
github.com/bool64/dev v0.2.32 h1:DRZtloaoH1Igky3zphaUHV9+SLIV2H3lsf78JsJHFg0=
github.com/bool64/dev v0.2.32/go.mod h1:iJbh1y/HkunEPhgebWRNcs8wfGq7sjvJ6W5iabL8ACg=
github.com/bool64/httpmock v0.1.13 h1:3QpRXQ5kwHLW8xnVT8+Ug7VS6RerhdEFV+RWYC61aVo=
github.com/bool64/httpmock v0.1.13/go.mod h1:YMTLaypQ3o5DAx78eA/kDRSLec0f+42sLMDmHdmeY+E=
github.com/bool64/httptestbench v0.1.4 h1:35f9RwWqcnQRXM+sA+GUhWVGSa6XEFlKpNSH9oYzOjI=
Expand Down Expand Up @@ -125,16 +125,16 @@ 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.62 h1:eIE0aRklWa2eLJg2L/zqyWpKvgUPbq2oKOtrJGJkPH0=
github.com/swaggest/jsonschema-go v0.3.62/go.mod h1:DYuKqdpms/edvywsX6p1zHXCZkdwB28wRaBdFCe3Duw=
github.com/swaggest/openapi-go v0.2.41 h1:aO8Q5ZugBmbd16YcppG18e3T+tgU8NJrXA3HLPgnANI=
github.com/swaggest/openapi-go v0.2.41/go.mod h1:Ww0uMQS11bz3jftWFi6+CA82yl6DHqTv9AE/LLVxzAs=
github.com/swaggest/jsonschema-go v0.3.64 h1:HyB41fkA4XP0BZkqWfGap5i2JtRHQGXG/21dGDPbyLM=
github.com/swaggest/jsonschema-go v0.3.64/go.mod h1:DYuKqdpms/edvywsX6p1zHXCZkdwB28wRaBdFCe3Duw=
github.com/swaggest/openapi-go v0.2.43 h1:nuNr60vmsx4pxIh1NoaIKrruh+pVba6iXjF+dXlTLAk=
github.com/swaggest/openapi-go v0.2.43/go.mod h1:/ykzNtS1ZO7X43OnEtyisMktxCiawQLyGd08rkjV68U=
github.com/swaggest/refl v1.3.0 h1:PEUWIku+ZznYfsoyheF97ypSduvMApYyGkYF3nabS0I=
github.com/swaggest/refl v1.3.0/go.mod h1:3Ujvbmh1pfSbDYjC6JGG7nMgPvpG0ehQL4iNonnLNbg=
github.com/swaggest/swgui v1.7.3 h1:e1Du/3kqvR5HxL41M4pdkJhsADHtuyWpahl8tdcPStM=
github.com/swaggest/swgui v1.7.3/go.mod h1:FP9uIPTB/QqVs2ZbOD6zc5yTw8SDTJfftak5f4ZRqOQ=
github.com/swaggest/usecase v1.2.1 h1:XYVdK9tK2KCPglTflUi7aWBrVwIyb58D5mvGWED7pNs=
github.com/swaggest/usecase v1.2.1/go.mod h1:5ccwVsLJ9eQpU4m0AGTM444pdqSPQBiocIwMmdRH9lQ=
github.com/swaggest/usecase v1.3.0 h1:Zte74uCWQYeGradJbxlhOrqi77K/GMK16VYTIjyenoA=
github.com/swaggest/usecase v1.3.0/go.mod h1:cae3lDd5VDmM36OQcOOOdAlEDg40TiQYIp99S9ejWqA=
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU=
Expand Down
8 changes: 4 additions & 4 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ module github.com/swaggest/rest
go 1.17

require (
github.com/bool64/dev v0.2.31
github.com/bool64/dev v0.2.32
github.com/bool64/httpmock v0.1.13
github.com/bool64/shared v0.1.5
github.com/cespare/xxhash/v2 v2.2.0
Expand All @@ -13,10 +13,10 @@ require (
github.com/stretchr/testify v1.8.2
github.com/swaggest/assertjson v1.9.0
github.com/swaggest/form/v5 v5.1.1
github.com/swaggest/jsonschema-go v0.3.62
github.com/swaggest/openapi-go v0.2.41
github.com/swaggest/jsonschema-go v0.3.64
github.com/swaggest/openapi-go v0.2.43
github.com/swaggest/refl v1.3.0
github.com/swaggest/usecase v1.2.1
github.com/swaggest/usecase v1.3.0
)

require (
Expand Down
16 changes: 8 additions & 8 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
github.com/bool64/dev v0.2.17/go.mod h1:iJbh1y/HkunEPhgebWRNcs8wfGq7sjvJ6W5iabL8ACg=
github.com/bool64/dev v0.2.24/go.mod h1:iJbh1y/HkunEPhgebWRNcs8wfGq7sjvJ6W5iabL8ACg=
github.com/bool64/dev v0.2.25/go.mod h1:iJbh1y/HkunEPhgebWRNcs8wfGq7sjvJ6W5iabL8ACg=
github.com/bool64/dev v0.2.27/go.mod h1:iJbh1y/HkunEPhgebWRNcs8wfGq7sjvJ6W5iabL8ACg=
github.com/bool64/dev v0.2.29/go.mod h1:iJbh1y/HkunEPhgebWRNcs8wfGq7sjvJ6W5iabL8ACg=
github.com/bool64/dev v0.2.31 h1:OS57EqYaYe2M/2bw9uhDCIFiZZwywKFS/4qMLN6JUmQ=
github.com/bool64/dev v0.2.31/go.mod h1:iJbh1y/HkunEPhgebWRNcs8wfGq7sjvJ6W5iabL8ACg=
github.com/bool64/dev v0.2.32 h1:DRZtloaoH1Igky3zphaUHV9+SLIV2H3lsf78JsJHFg0=
github.com/bool64/dev v0.2.32/go.mod h1:iJbh1y/HkunEPhgebWRNcs8wfGq7sjvJ6W5iabL8ACg=
github.com/bool64/httpmock v0.1.13 h1:3QpRXQ5kwHLW8xnVT8+Ug7VS6RerhdEFV+RWYC61aVo=
github.com/bool64/httpmock v0.1.13/go.mod h1:YMTLaypQ3o5DAx78eA/kDRSLec0f+42sLMDmHdmeY+E=
github.com/bool64/shared v0.1.5 h1:fp3eUhBsrSjNCQPcSdQqZxxh9bBwrYiZ+zOKFkM0/2E=
Expand Down Expand Up @@ -77,14 +77,14 @@ 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.62 h1:eIE0aRklWa2eLJg2L/zqyWpKvgUPbq2oKOtrJGJkPH0=
github.com/swaggest/jsonschema-go v0.3.62/go.mod h1:DYuKqdpms/edvywsX6p1zHXCZkdwB28wRaBdFCe3Duw=
github.com/swaggest/openapi-go v0.2.41 h1:aO8Q5ZugBmbd16YcppG18e3T+tgU8NJrXA3HLPgnANI=
github.com/swaggest/openapi-go v0.2.41/go.mod h1:Ww0uMQS11bz3jftWFi6+CA82yl6DHqTv9AE/LLVxzAs=
github.com/swaggest/jsonschema-go v0.3.64 h1:HyB41fkA4XP0BZkqWfGap5i2JtRHQGXG/21dGDPbyLM=
github.com/swaggest/jsonschema-go v0.3.64/go.mod h1:DYuKqdpms/edvywsX6p1zHXCZkdwB28wRaBdFCe3Duw=
github.com/swaggest/openapi-go v0.2.43 h1:nuNr60vmsx4pxIh1NoaIKrruh+pVba6iXjF+dXlTLAk=
github.com/swaggest/openapi-go v0.2.43/go.mod h1:/ykzNtS1ZO7X43OnEtyisMktxCiawQLyGd08rkjV68U=
github.com/swaggest/refl v1.3.0 h1:PEUWIku+ZznYfsoyheF97ypSduvMApYyGkYF3nabS0I=
github.com/swaggest/refl v1.3.0/go.mod h1:3Ujvbmh1pfSbDYjC6JGG7nMgPvpG0ehQL4iNonnLNbg=
github.com/swaggest/usecase v1.2.1 h1:XYVdK9tK2KCPglTflUi7aWBrVwIyb58D5mvGWED7pNs=
github.com/swaggest/usecase v1.2.1/go.mod h1:5ccwVsLJ9eQpU4m0AGTM444pdqSPQBiocIwMmdRH9lQ=
github.com/swaggest/usecase v1.3.0 h1:Zte74uCWQYeGradJbxlhOrqi77K/GMK16VYTIjyenoA=
github.com/swaggest/usecase v1.3.0/go.mod h1:cae3lDd5VDmM36OQcOOOdAlEDg40TiQYIp99S9ejWqA=
github.com/yosuke-furukawa/json5 v0.1.2-0.20201207051438-cf7bb3f354ff h1:7YqG491bE4vstXRz1lD38rbSgbXnirvROz1lZiOnPO8=
github.com/yosuke-furukawa/json5 v0.1.2-0.20201207051438-cf7bb3f354ff/go.mod h1:sw49aWDqNdRJ6DYUtIQiaA3xyj2IL9tjeNYmX2ixwcU=
github.com/yudai/gojsondiff v1.0.0 h1:27cbfqXLVEJ1o8I6v3y9lg8Ydm53EKqHXAOMxEGlCOA=
Expand Down
2 changes: 1 addition & 1 deletion gzip/container.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import (

// Writer writes gzip data into suitable stream or returns 0, nil.
type Writer interface {
GzipWrite([]byte) (int, error)
GzipWrite(d []byte) (int, error)
}

// JSONContainer contains compressed JSON.
Expand Down
25 changes: 22 additions & 3 deletions openapi/collector.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ package openapi
import (
"context"
"encoding/json"
"errors"
"fmt"
"net/http"
"strconv"
Expand Down Expand Up @@ -412,6 +413,11 @@ func (c *Collector) processUseCase(oc openapi.OperationContext, u usecase.Intera
func (c *Collector) setOCJSONResponse(oc openapi.OperationContext, output interface{}, statusCode int) {
oc.AddRespStructure(output, func(cu *openapi.ContentUnit) {
cu.HTTPStatus = statusCode

if described, ok := output.(jsonschema.Described); ok {
cu.Description = described.Description()

Check warning on line 418 in openapi/collector.go

View check run for this annotation

Codecov / codecov/patch

openapi/collector.go#L418

Added line #L418 was not covered by tests
}

Check notice on line 419 in openapi/collector.go

View workflow job for this annotation

GitHub Actions / test (1.21.x)

1 statement(s) on lines 417:419 are not covered by tests.

if output != nil {
cu.ContentType = c.DefaultErrorResponseContentType
}
Expand All @@ -431,10 +437,16 @@ func (c *Collector) processOCExpectedErrors(oc openapi.OperationContext, u useca

for _, e := range hasExpectedErrors.ExpectedErrors() {
var (
errResp interface{}
statusCode int
errResp interface{}
statusCode int
description string
)

var described jsonschema.Described
if errors.As(e, &described) {
description = described.Description()

Check warning on line 447 in openapi/collector.go

View check run for this annotation

Codecov / codecov/patch

openapi/collector.go#L447

Added line #L447 was not covered by tests
}

Check notice on line 448 in openapi/collector.go

View workflow job for this annotation

GitHub Actions / test (1.21.x)

1 statement(s) on lines 446:448 are not covered by tests.

if h.MakeErrResp != nil {
statusCode, errResp = h.MakeErrResp(context.Background(), e)
} else {
Expand All @@ -451,7 +463,14 @@ func (c *Collector) processOCExpectedErrors(oc openapi.OperationContext, u useca

errsByCode[statusCode] = append(errsByCode[statusCode], errResp)

c.setOCJSONResponse(oc, errResp, statusCode)
oc.AddRespStructure(errResp, func(cu *openapi.ContentUnit) {
cu.HTTPStatus = statusCode
cu.Description = description

if errResp != nil {
cu.ContentType = c.DefaultErrorResponseContentType
}
})
}

c.combineOCErrors(oc, statusCodes, errsByCode)
Expand Down
10 changes: 5 additions & 5 deletions request/decoder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -418,7 +418,7 @@ func TestDecoder_Decode_dateTime(t *testing.T) {
MakeRequestValidator(http.MethodGet, input, nil)

err = dec.Decode(req, input, validator)
assert.NoError(t, err, fmt.Sprintf("%v", err))
assert.NoError(t, err)
}

type inputWithLoader struct {
Expand Down Expand Up @@ -464,7 +464,7 @@ func TestDecoder_Decode_manualLoader_ptr(t *testing.T) {
MakeRequestValidator(http.MethodGet, input, nil)

err = dec.Decode(req, input, validator)
assert.NoError(t, err, fmt.Sprintf("%v", err))
assert.NoError(t, err)
assert.True(t, loadTriggered)
assert.True(t, input.Time.IsZero())
}
Expand All @@ -490,7 +490,7 @@ func TestDecoder_Decode_manualLoader_val(t *testing.T) {
MakeRequestValidator(http.MethodGet, input, nil)

err = dec.Decode(req, &input, validator)
assert.NoError(t, err, fmt.Sprintf("%v", err))
assert.NoError(t, err)
assert.True(t, loadTriggered)
assert.True(t, input.Time.IsZero())
}
Expand All @@ -507,7 +507,7 @@ func TestDecoder_Decode_setter_ptr(t *testing.T) {
MakeRequestValidator(http.MethodGet, input, nil)

err = dec.Decode(req, input, validator)
assert.NoError(t, err, fmt.Sprintf("%v", err))
assert.NoError(t, err)
assert.False(t, input.Time.IsZero())
assert.NotNil(t, input.r)
}
Expand All @@ -524,7 +524,7 @@ func TestDecoder_Decode_setter_val(t *testing.T) {
MakeRequestValidator(http.MethodGet, input, nil)

err = dec.Decode(req, &input, validator)
assert.NoError(t, err, fmt.Sprintf("%v", err))
assert.NoError(t, err)
assert.False(t, input.Time.IsZero())
assert.NotNil(t, input.r)
}
Expand Down
2 changes: 1 addition & 1 deletion request/middleware.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (
)

type requestDecoderSetter interface {
SetRequestDecoder(nethttp.RequestDecoder)
SetRequestDecoder(rd nethttp.RequestDecoder)
}

type requestMapping interface {
Expand Down

0 comments on commit ba64098

Please sign in to comment.