Skip to content

Commit

Permalink
Default status code
Browse files Browse the repository at this point in the history
  • Loading branch information
EwenQuim committed Dec 9, 2024
1 parent f42f6eb commit b26e56f
Show file tree
Hide file tree
Showing 9 changed files with 80 additions and 17 deletions.
1 change: 1 addition & 0 deletions examples/petstore/controllers/pets.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ func (rs PetsResources) Routes(s *fuego.Server) {

fuego.Get(petsGroup, "/by-age", rs.getAllPetsByAge, option.Description("Returns an array of pets grouped by age"))
fuego.Post(petsGroup, "/", rs.postPets,
option.DefaultStatusCode(201),
option.AddError(409, "Conflict: Pet with the same name already exists", PetsError{}),
)

Expand Down
15 changes: 9 additions & 6 deletions examples/petstore/controllers/pets_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,10 @@ func TestPostPets(t *testing.T) {

s.Mux.ServeHTTP(w, r)

require.Equal(t, http.StatusOK, w.Code)
require.Equal(t, http.StatusCreated, w.Code)
petId := w.Body.String()
t.Log(petId)
require.NotEmpty(t, petId)
})
}

Expand All @@ -63,7 +66,7 @@ func TestGetPets(t *testing.T) {
r := httptest.NewRequest("POST", "/pets/", strings.NewReader(`{"name": "kitkat"}`))
s.Mux.ServeHTTP(w, r)
t.Log(w.Body.String())
require.Equal(t, http.StatusOK, w.Code)
require.Equal(t, http.StatusCreated, w.Code)

w = httptest.NewRecorder()
r = httptest.NewRequest("GET", "/pets/pet-1", nil)
Expand All @@ -83,7 +86,7 @@ func TestGetAllPestByAge(t *testing.T) {
r := httptest.NewRequest("POST", "/pets/", strings.NewReader(`{"name": "kitkat"}`))
s.Mux.ServeHTTP(w, r)
t.Log(w.Body.String())
require.Equal(t, http.StatusOK, w.Code)
require.Equal(t, http.StatusCreated, w.Code)

w = httptest.NewRecorder()
r = httptest.NewRequest("GET", "/pets/by-age", nil)
Expand All @@ -103,7 +106,7 @@ func TestGetPetsByName(t *testing.T) {
r := httptest.NewRequest("POST", "/pets/", strings.NewReader(`{"name": "kitkat"}`))
s.Mux.ServeHTTP(w, r)
t.Log(w.Body.String())
require.Equal(t, http.StatusOK, w.Code)
require.Equal(t, http.StatusCreated, w.Code)

w = httptest.NewRecorder()
r = httptest.NewRequest("GET", "/pets/by-name/kitkat", nil)
Expand All @@ -123,7 +126,7 @@ func TestPutPets(t *testing.T) {
r := httptest.NewRequest("POST", "/pets/", strings.NewReader(`{"name": "kitkat"}`))
s.Mux.ServeHTTP(w, r)
t.Log(w.Body.String())
require.Equal(t, http.StatusOK, w.Code)
require.Equal(t, http.StatusCreated, w.Code)

w = httptest.NewRecorder()
r = httptest.NewRequest("PUT", "/pets/pet-1", strings.NewReader(`{"name": "snickers"}`))
Expand All @@ -143,7 +146,7 @@ func TestDeletePets(t *testing.T) {
r := httptest.NewRequest("POST", "/pets/", strings.NewReader(`{"name": "kitkat"}`))
s.Mux.ServeHTTP(w, r)
t.Log(w.Body.String())
require.Equal(t, http.StatusOK, w.Code)
require.Equal(t, http.StatusCreated, w.Code)

w = httptest.NewRecorder()
r = httptest.NewRequest("DELETE", "/pets/pet-1", nil)
Expand Down
4 changes: 2 additions & 2 deletions examples/petstore/lib/testdata/doc/openapi.golden.json
Original file line number Diff line number Diff line change
Expand Up @@ -306,7 +306,7 @@
"required": true
},
"responses": {
"200": {
"201": {
"content": {
"application/json": {
"schema": {
Expand All @@ -319,7 +319,7 @@
}
}
},
"description": "OK"
"description": "Created"
},
"400": {
"content": {
Expand Down
1 change: 1 addition & 0 deletions mux.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ type BaseRoute struct {
Middlewares []func(http.Handler) http.Handler
AcceptedContentTypes []string // Content types accepted for the request body. If nil, all content types (*/*) are accepted.
Hidden bool // If true, the route will not be documented in the OpenAPI spec
DefaultStatusCode int // Default status code for the response

mainRouter *Server // ref to the main router, used to register the route in the OpenAPI spec
}
Expand Down
22 changes: 13 additions & 9 deletions openapi.go
Original file line number Diff line number Diff line change
Expand Up @@ -188,19 +188,23 @@ func RegisterOpenAPIOperation[T, B any](s *Server, route Route[T, B]) (*openapi3
addResponseIfNotSet(s, route.Operation, openAPIGlobalResponse.Code, openAPIGlobalResponse.Description, openAPIGlobalResponse.ErrorType)
}

// Automatically add non-declared 200 Response
response200 := route.Operation.Responses.Value("200")
if response200 == nil {
response := openapi3.NewResponse().WithDescription("OK")
route.Operation.AddResponse(200, response)
response200 = route.Operation.Responses.Value("200")
// Automatically add non-declared 200 (or other) Response
if route.DefaultStatusCode == 0 {
route.DefaultStatusCode = 200
}
defaultStatusCode := strconv.Itoa(route.DefaultStatusCode)
responseDefault := route.Operation.Responses.Value(defaultStatusCode)
if responseDefault == nil {
response := openapi3.NewResponse().WithDescription(http.StatusText(route.DefaultStatusCode))
route.Operation.AddResponse(route.DefaultStatusCode, response)
responseDefault = route.Operation.Responses.Value(defaultStatusCode)
}

// Automatically add non-declared Content for 200 Response
if response200.Value.Content == nil {
// Automatically add non-declared Content for 200 (or other) Response
if responseDefault.Value.Content == nil {
responseSchema := SchemaTagFromType(s, *new(T))
content := openapi3.NewContentWithSchemaRef(&responseSchema.SchemaRef, []string{"application/json", "application/xml"})
response200.Value.WithContent(content)
responseDefault.Value.WithContent(content)
}

// Automatically add non-declared Path parameters
Expand Down
7 changes: 7 additions & 0 deletions option.go
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,13 @@ func OptionHide() func(*BaseRoute) {
}
}

// Hide hides the route from the OpenAPI spec.
func OptionDefaultStatusCode(defaultStatusCode int) func(*BaseRoute) {
return func(r *BaseRoute) {
r.DefaultStatusCode = defaultStatusCode
}
}

// OptionSecurity configures security requirements to the route.
//
// Single Scheme (AND Logic):
Expand Down
2 changes: 2 additions & 0 deletions option/option.go
Original file line number Diff line number Diff line change
Expand Up @@ -143,3 +143,5 @@ var RequestContentType = fuego.OptionRequestContentType

// Hide hides the route from the OpenAPI spec.
var Hide = fuego.OptionHide

var DefaultStatusCode = fuego.OptionDefaultStatusCode
41 changes: 41 additions & 0 deletions option_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -695,3 +695,44 @@ func TestOptionAddDescription(t *testing.T) {
require.Equal(t, "controller: `github.com/go-fuego/fuego_test.helloWorld`\n\n---\n\ntest description\n\nanother description", route.Operation.Description)
})
}

func TestDefaultStatusCode(t *testing.T) {
t.Run("Declare a default status code for the route", func(t *testing.T) {
s := fuego.NewServer()

route := fuego.Post(s, "/test", helloWorld,
fuego.OptionDefaultStatusCode(201),
)

r := httptest.NewRequest(http.MethodPost, "/test", nil)
w := httptest.NewRecorder()

s.Mux.ServeHTTP(w, r)

require.Equal(t, 201, w.Code)
require.Equal(t, "hello world", w.Body.String())
require.Equal(t, 201, route.DefaultStatusCode)
require.NotNil(t, route.Operation.Responses.Value("201").Value)
})

t.Run("Declare a default status code for the route but bypass it in the controller", func(t *testing.T) {
s := fuego.NewServer()

route := fuego.Post(s, "/test", func(c fuego.ContextNoBody) (string, error) {
c.SetStatus(200)
return "hello world", nil
},
fuego.OptionDefaultStatusCode(201),
)

r := httptest.NewRequest(http.MethodPost, "/test", nil)
w := httptest.NewRecorder()

s.Mux.ServeHTTP(w, r)

require.Equal(t, 200, w.Code)
require.Equal(t, "hello world", w.Body.String())
require.Equal(t, 201, route.DefaultStatusCode, "default status code should not be changed")
require.NotNil(t, route.Operation.Responses.Value("201").Value, "default status is still in the spec even if code is not used")
})
}
4 changes: 4 additions & 0 deletions serve.go
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,10 @@ func HTTPHandler[ReturnType, Body any, Contextable ctx[Body]](s *Server, control
return
}

if route.DefaultStatusCode != 0 {
w.WriteHeader(route.DefaultStatusCode)
}

// TRANSFORM OUT
timeTransformOut := time.Now()
ans, err = transformOut(r.Context(), ans)
Expand Down

0 comments on commit b26e56f

Please sign in to comment.