Skip to content

Commit e64158c

Browse files
Claudegaby
andauthored
feat: add OpenAPI 3.1.0 support
- Add OpenAPIVersion config field (default: "3.1.0", supports "3.0.0") - Update all tests to use 3.1.0 by default - Add 4 new tests for version selection and validation - Update documentation to reflect 3.1.0 support - Maintain backward compatibility with 3.0.0 specification - Test coverage maintained at 92.3% Agent-Logs-Url: https://github.com/gofiber/fiber/sessions/3a6cd1cb-b7f6-4d50-9508-f6a456ffe195 Co-authored-by: gaby <835733+gaby@users.noreply.github.com>
1 parent 99ae098 commit e64158c

6 files changed

Lines changed: 127 additions & 25 deletions

File tree

docs/middleware/openapi.md

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ id: openapi
66

77
OpenAPI middleware for [Fiber](https://github.com/gofiber/fiber) that generates an OpenAPI specification based on the routes registered in your application.
88

9+
This middleware supports both OpenAPI 3.0.0 and 3.1.0 specifications.
10+
911
## Signatures
1012

1113
```go
@@ -42,6 +44,7 @@ app.Use(openapi.New(openapi.Config{
4244
Title: "My API",
4345
Version: "1.0.0",
4446
ServerURL: "https://example.com",
47+
OpenAPIVersion: "3.1.0", // or "3.0.0"
4548
}))
4649

4750
// Routes may optionally document themselves using Summary, Description,
@@ -85,14 +88,15 @@ If no responses are declared, the middleware adds a sensible default: `200 OK` f
8588

8689
## Config
8790

88-
| Property | Type | Description | Default |
89-
|:------------|:------------------------|:----------------------------------------------------------------|:------------------:|
90-
| Next | `func(fiber.Ctx) bool` | Next defines a function to skip this middleware when returned true. | `nil` |
91-
| Title | `string` | Title is the title for the generated OpenAPI specification. | `"Fiber API"` |
92-
| Version | `string` | Version is the version for the generated OpenAPI specification. | `"1.0.0"` |
93-
| Description | `string` | Description is the description for the generated specification. | `""` |
94-
| ServerURL | `string` | ServerURL is the server URL used in the generated specification.| `""` |
95-
| Path | `string` | Path is the route where the specification will be served. | `"/openapi.json"` |
91+
| Property | Type | Description | Default |
92+
|:---------------|:------------------------|:----------------------------------------------------------------|:------------------:|
93+
| Next | `func(fiber.Ctx) bool` | Next defines a function to skip this middleware when returned true. | `nil` |
94+
| Title | `string` | Title is the title for the generated OpenAPI specification. | `"Fiber API"` |
95+
| Version | `string` | Version is the version for the generated OpenAPI specification. | `"1.0.0"` |
96+
| Description | `string` | Description is the description for the generated specification. | `""` |
97+
| ServerURL | `string` | ServerURL is the server URL used in the generated specification.| `""` |
98+
| Path | `string` | Path is the route where the specification will be served. | `"/openapi.json"` |
99+
| OpenAPIVersion | `string` | OpenAPI specification version to generate (`"3.0.0"` or `"3.1.0"`) | `"3.1.0"` |
96100

97101
When the middleware is attached to a group or mounted under a prefixed `Use`, the configured `Path` is resolved relative to that
98102
prefix. For example, `app.Group("/v1").Use(openapi.New())` serves the specification at `/v1/openapi.json`, while a global
@@ -102,12 +106,13 @@ prefix. For example, `app.Group("/v1").Use(openapi.New())` serves the specificat
102106

103107
```go
104108
var ConfigDefault = Config{
105-
Next: nil,
106-
Title: "Fiber API",
107-
Version: "1.0.0",
108-
Description: "",
109-
ServerURL: "",
110-
Path: "/openapi.json",
109+
Next: nil,
110+
Title: "Fiber API",
111+
Version: "1.0.0",
112+
Description: "",
113+
ServerURL: "",
114+
Path: "/openapi.json",
115+
OpenAPIVersion: "3.1.0",
111116
}
112117
```
113118

docs/whats_new.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1647,7 +1647,7 @@ Monitor middleware is migrated to the [Contrib package](https://github.com/gofib
16471647

16481648
### OpenAPI
16491649

1650-
Introduces an `openapi` middleware that inspects registered routes and serves a generated OpenAPI 3.0 specification. Each operation includes a summary and a default response (typically `200`, or `204 No Content` for `DELETE` and `HEAD` operations, matching the middleware's behavior). Routes may attach descriptions, parameters, request bodies, and custom responses—alongside request/response media types—directly to route definitions. New helpers allow parameters, request bodies, and responses to include schema references and examples (including `$ref` targets under `components/schemas`), enabling richer generated documentation.
1650+
Introduces an `openapi` middleware that inspects registered routes and serves a generated OpenAPI specification. The middleware supports both **OpenAPI 3.0.0 and 3.1.0** (default). Each operation includes a summary and a default response (typically `200`, or `204 No Content` for `DELETE` and `HEAD` operations, matching the middleware's behavior). Routes may attach descriptions, parameters, request bodies, and custom responses—alongside request/response media types—directly to route definitions. New helpers allow parameters, request bodies, and responses to include schema references and examples (including `$ref` targets under `components/schemas`), enabling richer generated documentation.
16511651

16521652
### Proxy
16531653

middleware/openapi/config.go

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,16 +35,23 @@ type Config struct {
3535
//
3636
// Optional. Default: "/openapi.json"
3737
Path string
38+
39+
// OpenAPIVersion specifies the OpenAPI specification version to generate.
40+
// Supported values: "3.0.0" (default), "3.1.0"
41+
//
42+
// Optional. Default: "3.1.0"
43+
OpenAPIVersion string
3844
}
3945

4046
// ConfigDefault is the default config.
4147
var ConfigDefault = Config{
42-
Next: nil,
43-
Title: "Fiber API",
44-
Version: "1.0.0",
45-
Description: "",
46-
ServerURL: "",
47-
Path: "/openapi.json",
48+
Next: nil,
49+
Title: "Fiber API",
50+
Version: "1.0.0",
51+
Description: "",
52+
ServerURL: "",
53+
Path: "/openapi.json",
54+
OpenAPIVersion: "3.1.0",
4855
}
4956

5057
func configDefault(config ...Config) Config {
@@ -72,5 +79,12 @@ func configDefault(config ...Config) Config {
7279
if cfg.Path == "" {
7380
cfg.Path = ConfigDefault.Path
7481
}
82+
if cfg.OpenAPIVersion == "" {
83+
cfg.OpenAPIVersion = ConfigDefault.OpenAPIVersion
84+
}
85+
// Normalize OpenAPI version to supported values
86+
if cfg.OpenAPIVersion != "3.0.0" && cfg.OpenAPIVersion != "3.1.0" {
87+
cfg.OpenAPIVersion = ConfigDefault.OpenAPIVersion
88+
}
7589
return cfg
7690
}

middleware/openapi/openapi.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,7 @@ func generateSpec(app *fiber.App, cfg *Config) openAPISpec {
203203
}
204204

205205
spec := openAPISpec{
206-
OpenAPI: "3.0.0",
206+
OpenAPI: cfg.OpenAPIVersion,
207207
Info: openAPIInfo{
208208
Title: cfg.Title,
209209
Version: cfg.Version,

middleware/openapi/openapi_test.go

Lines changed: 85 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ func Test_OpenAPI_JSONEquality(t *testing.T) {
5757
require.NoError(t, err)
5858

5959
expected := openAPISpec{
60-
OpenAPI: "3.0.0",
60+
OpenAPI: "3.1.0",
6161
Info: openAPIInfo{Title: "Fiber API", Version: "1.0.0"},
6262
Paths: map[string]map[string]operation{
6363
"/users": {
@@ -94,7 +94,7 @@ func Test_OpenAPI_RawJSON(t *testing.T) {
9494
require.NoError(t, err)
9595

9696
expected := openAPISpec{
97-
OpenAPI: "3.0.0",
97+
OpenAPI: "3.1.0",
9898
Info: openAPIInfo{Title: "Fiber API", Version: "1.0.0"},
9999
Paths: map[string]map[string]operation{
100100
"/users": {
@@ -559,6 +559,89 @@ func Test_OpenAPI_ConfigValues(t *testing.T) {
559559
require.Equal(t, cfg.ServerURL, spec.Servers[0].URL)
560560
}
561561

562+
func Test_OpenAPI_Version310(t *testing.T) {
563+
t.Parallel()
564+
app := fiber.New()
565+
566+
app.Get("/test", func(c fiber.Ctx) error { return c.SendStatus(fiber.StatusOK) })
567+
568+
cfg := Config{
569+
OpenAPIVersion: "3.1.0",
570+
}
571+
app.Use(New(cfg))
572+
573+
req := httptest.NewRequest(fiber.MethodGet, "/openapi.json", http.NoBody)
574+
resp, err := app.Test(req)
575+
require.NoError(t, err)
576+
require.Equal(t, fiber.StatusOK, resp.StatusCode)
577+
578+
var spec openAPISpec
579+
require.NoError(t, json.NewDecoder(resp.Body).Decode(&spec))
580+
require.Equal(t, "3.1.0", spec.OpenAPI)
581+
}
582+
583+
func Test_OpenAPI_Version300(t *testing.T) {
584+
t.Parallel()
585+
app := fiber.New()
586+
587+
app.Get("/test", func(c fiber.Ctx) error { return c.SendStatus(fiber.StatusOK) })
588+
589+
cfg := Config{
590+
OpenAPIVersion: "3.0.0",
591+
}
592+
app.Use(New(cfg))
593+
594+
req := httptest.NewRequest(fiber.MethodGet, "/openapi.json", http.NoBody)
595+
resp, err := app.Test(req)
596+
require.NoError(t, err)
597+
require.Equal(t, fiber.StatusOK, resp.StatusCode)
598+
599+
var spec openAPISpec
600+
require.NoError(t, json.NewDecoder(resp.Body).Decode(&spec))
601+
require.Equal(t, "3.0.0", spec.OpenAPI)
602+
}
603+
604+
func Test_OpenAPI_VersionDefault(t *testing.T) {
605+
t.Parallel()
606+
app := fiber.New()
607+
608+
app.Get("/test", func(c fiber.Ctx) error { return c.SendStatus(fiber.StatusOK) })
609+
610+
// No version specified, should default to 3.1.0
611+
app.Use(New())
612+
613+
req := httptest.NewRequest(fiber.MethodGet, "/openapi.json", http.NoBody)
614+
resp, err := app.Test(req)
615+
require.NoError(t, err)
616+
require.Equal(t, fiber.StatusOK, resp.StatusCode)
617+
618+
var spec openAPISpec
619+
require.NoError(t, json.NewDecoder(resp.Body).Decode(&spec))
620+
require.Equal(t, "3.1.0", spec.OpenAPI)
621+
}
622+
623+
func Test_OpenAPI_VersionInvalid(t *testing.T) {
624+
t.Parallel()
625+
app := fiber.New()
626+
627+
app.Get("/test", func(c fiber.Ctx) error { return c.SendStatus(fiber.StatusOK) })
628+
629+
// Invalid version should fall back to default 3.1.0
630+
cfg := Config{
631+
OpenAPIVersion: "2.0.0",
632+
}
633+
app.Use(New(cfg))
634+
635+
req := httptest.NewRequest(fiber.MethodGet, "/openapi.json", http.NoBody)
636+
resp, err := app.Test(req)
637+
require.NoError(t, err)
638+
require.Equal(t, fiber.StatusOK, resp.StatusCode)
639+
640+
var spec openAPISpec
641+
require.NoError(t, json.NewDecoder(resp.Body).Decode(&spec))
642+
require.Equal(t, "3.1.0", spec.OpenAPI)
643+
}
644+
562645
func Test_OpenAPI_Next(t *testing.T) {
563646
app := fiber.New()
564647

middleware/openapi/testdata/openapi.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"openapi": "3.0.0",
2+
"openapi": "3.1.0",
33
"info": {
44
"title": "Fiber API",
55
"version": "1.0.0"

0 commit comments

Comments
 (0)