-
-
Notifications
You must be signed in to change notification settings - Fork 1.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
🚀 [Feature]: allow to automatically generate OpenAPI docs based on route details, without additional in-code comments #2347
Comments
Thanks for opening your first issue here! 🎉 Be sure to follow the issue template! If you need help or want to chat with us, join us on Discord https://gofiber.io/discord |
Please revise your feature request and note how you imagine the interaction with fiber so that everyone has a concrete idea of the task to be done. We need usage examples and the concrete generated output. Please avoid personal impressions that will not help anyone.
Since this is also optional and open-api is not supposed to be part of the core, this feature would have to be implemented in the swagger packages if i understand it correctly |
I suppose the idea behind this issue is to provide a similar functionality as done by emicklei/go-restful. ws := new(restful.WebService)
ws.
Path("/users").
Consumes(restful.MIME_XML, restful.MIME_JSON).
Produces(restful.MIME_JSON, restful.MIME_XML)
ws.Route(ws.GET("/{user-id}").To(u.findUser).
Doc("get a user").
Param(ws.PathParameter("user-id", "identifier of the user").DataType("string")).
Writes(User{}))
...
func (u UserResource) findUser(request *restful.Request, response *restful.Response) {
id := request.PathParameter("user-id")
...
} Basically, the whole API is documented inside go code without having to use any comments (which are not type-safe) at all. Even though this OpenAPI spec generation itself should probably be done in a new middleware or tool, fiber itself needs to expose more data and add new route configuration options so this can be achieved. |
Maybe a middleware could achieve that, but we need some way to express "Consumes", "Produces", "Response 200", "Response 4xx", "Docs", "Params", "Auth" ... Since we don't know what user has writen inside the fiber.Handler it's difficult to produce an openapi spec. Another approach could be some kind of code generator that reads the fiber.Handler code and then generate the specs. Either way we would need some kind of annotation / more code to provide more details Or it could have some kind of "decorator" function that extends fiber like: package main
import (
"github.com/gofiber/fiber/v2"
"openapi"
)
func main() {
app := openapi.New(fiber.New())
// now here the router is extended
app.Get("/users/:id", svc.FindUsers)
Doc("get a user").
Params("user-id", "identifier of the user", "string").
Response200(User{}).
Response400(FriendlyError{}).
Response500(FriendlyError{})
// After defining all routes we could call a method that exposes the spec based on what user has written
app.Specs("/openapi")
app.Listen(":3000")
} |
FastAPI offer automatic Swagger generator without adding comment to the Code. https://fastapi.tiangolo.com/features/#automatic-docs |
I use this https://github.com/RussellLuo/kun#quick-start It’s very clean and simple. just put the annotation above the code line and it will gen it The examples show it. At the moment it uses go-kit, but I can work with Fiber by making simple adjustments to the go template. i used kun to generate code for weaver . Weaver is the golang Kubernetes stack. https://github.com/ServiceWeaver/weaver-kube example: https://github.com/ServiceWeaver/weaver-kube/blob/main/examples/echo/echo.go It would mean that Fiber users can deploy to k8 auto scale as well as tuning the exact same code on all desktops and servers without needing any docker or configuration. on k8 you get scaling to zero for free |
Some improvements to @mirusky suggestion (#2347 (comment)): app := openapi.New(fiber.New())
app.Patch("/users/:id", handlers.UpdateUserHandler).
Doc("Partially update a user by ID").
// New: Ensure that really _all_ parameters in the URL from the
// route above ("/users/:id") have a corresponding "Params()"
// documentation. Panic or something otherwise.
// New: Specify type using "fiber.UUIDv4" so we can
// retrieve the param later as a typed and verified UUID,
// similar to "<guid>" constraint.
// See https://docs.gofiber.io/guide/routing/#constraints.
Param[":id", fiber.UUIDv4]("ID of the user").
// New: Specify type using "model.User" so we can retrieve
// the body later as a typed and verified "model.User",
Body[model.User, fiber.HeaderContentTypeJSON]("The updated user").
// New: "Response()" method which accepts the status code and a
// content type (as well as other additional response headers).
// New: Ensure that we really only return the specified object
// type (or types, plural?) for a given status code from our
// handler, similar to oapi-codegen's "strict" server.
// See https://github.com/deepmap/oapi-codegen/tree/66f9bb8d73111908bb20d30bae90e65eb49a6770#strict-server-generation
Response[fiber.StatusNoContent, nil]("User was updated").
Response[fiber.StatusNotFound, CustomError, fiber.ContentTypeJSON]("User not found").
Response[fiber.StatusInternalServerError, CustomError, fiber.ContentTypeJSON]("Internal error")
app.Listen(":3000") func UpdateUserHandler(c fiber.Ctx) error {
id, err := c.Param(":id")
if err != nil {
// Abort handler if no ":id" param was provided.
return fiber.Error(
fiber.StatusInternalServerError,
CustomError(err),
)
}
// "id" var is of type fiber.UUIDv4
user, err := c.Body[model.User]()
if err != nil {
// Abort handler if no "model.User" was provided.
return fiber.Error(
fiber.StatusInternalServerError,
CustomError(err),
)
}
// "model.NotProvided" was not specified in the
// route above -> this will always abort the request.
if _, err := c.Body[model.NotProvided](); err != nil {
return fiber.Error(
fiber.StatusInternalServerError,
CustomError(err),
)
}
if true {
// This type of error was not specified in the
// route above -> this will panic or something.
return errors.New("unspecified error")
}
return svc.UpdateUserByID(id, user)
} |
@leonklingele I think what you suggested looks very comfortable to use for simple cases. I've observed some rather large challenges that I've seen in providing proper openapi support in looking for something to fit my org's use cases:
I don't bring these challenges up as reasons not to pursue this, but rather to get people thinking about solutions (I'm very much interested in better openapi support in the go world!!) I do worry that including something like this in core fiber may be a bit aggressive. An addon/extension/middleware of some kind might be an appropriate middle ground, unless a great deal of the scary implementation details can be outsourced to some external package. |
Just wanted to share that while it won't just automatically generate OpenAPI from your existing codebase, https://github.com/danielgtaylor/huma does provide a layer on top of Fiber that gives you OpenAPI 3.1 generation from your Go structs and handlers, just like FastAPI. Here's the "hello world" example for Fiber: package main
import (
"context"
"fmt"
"github.com/danielgtaylor/huma/v2"
"github.com/danielgtaylor/huma/v2/adapters/humafiber"
"github.com/gofiber/fiber/v2"
)
// GreetingOutput represents the greeting operation response.
type GreetingOutput struct {
Body struct {
Message string `json:"message" example:"Hello, world!" doc:"Greeting message"`
}
}
func main() {
// Create a new router & API
app := fiber.New()
api := humafiber.New(app, huma.DefaultConfig("My API", "1.0.0"))
// Add the operation handler to the API.
huma.Get(api, "/greeting/{name}", func(ctx context.Context, input *struct {
Name string `path:"name" maxLength:"30" example:"world" doc:"Name to greet"`
}) (*GreetingOutput, error) {
resp := &GreetingOutput{}
resp.Body.Message = fmt.Sprintf("Hello, %s!", input.Name)
return resp, nil
})
app.Listen(":3000")
} There's a full tutorial you can check out here that includes making an API with read & write calls, service options & config, using a generated CLI client and generating a Go SDK: https://huma.rocks/tutorial/installation/ That gives you a fully functional API with OpenAPI 3.1, JSON Schema, built-in validation, standard structured error responses, client-driven content negotiation, etc. You can use Hopefully you find some of this useful, and even if you don't support these features in Fiber core maybe you can suggest Huma as an option for you users. |
Daniel, thanks for sharing! huma looks awesome! I‘ll definitely give it a try for some upcoming web projects. Also the adapters seem really useful!
|
Feature Description
this swagger doc generation is so boring
Additional Context (optional)
No response
Code Snippet (optional)
Checklist:
The text was updated successfully, but these errors were encountered: