Closed H0llyW00dzZ closed 1 month ago
[!NOTE] Additionally, it should be noted that these methods are compatible with the latest version of Go (I'm using) and provide a more straightforward integration with databases.
Example:
Prefix: "/gopher", Routes: []APIRoute{ {Path: "/reload", Method: fiber.MethodPost, Handler: func(c *fiber.Ctx) error { return users.ReloadConfigHandler(c, db) }}, },
then it will be https://go.dev/v1/gopher/reload (example)
// isVersionedAPIRoute checks if the given path matches a versioned API route.
func isVersionedAPIRoute(path string) bool {
// Define the versioned API route prefixes
versionedAPIPrefixes := []string{"/v1", "/v2"}
// Check if the path starts with any of the versioned API prefixes
for _, prefix := range versionedAPIPrefixes {
if len(path) >= len(prefix) && path[:len(prefix)] == prefix {
return true
}
}
return false
}
// apiInternalServerErrorHandler is a custom error handler for internal server errors in versioned APIs.
func apiInternalServerErrorHandler(c *fiber.Ctx, err error) error {
// Log the error
Logger.LogErrorf("Internal Server Error occurred in versioned API: %v", err)
// Return a JSON response with the 500 Internal Server Error status code
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
"error": fiber.ErrInternalServerError.Message,
})
}
// apiErrorHandler is a custom error handler for versioned APIs.
// It returns JSON responses for 404 (Not Found) and 403 (Forbidden) status codes.
func apiErrorHandler(c *fiber.Ctx) error {
// Check if the response status code is already set
if c.Response().StatusCode() != fiber.StatusOK {
// Get the current status code
statusCode := c.Response().StatusCode()
// Check if the status code is 404 or 403
if statusCode == fiber.StatusNotFound {
// Return a JSON response for 404 (Not Found) error
return c.Status(statusCode).JSON(fiber.Map{
"error": fiber.ErrNotFound.Message,
})
} else if statusCode == fiber.StatusForbidden {
// Return a JSON response for 403 (Forbidden) error
return c.Status(statusCode).JSON(fiber.Map{
"error": fiber.ErrForbidden.Message,
})
}
}
// If the status code is not 404 or 403, continue with the original request
return c.Next()
}
// Set custom error handler for the application
app.Use(func(c *fiber.Ctx) error {
// Call the next route handler and catch any errors
err := c.Next()
// If there was an error, use the custom error handler
if err != nil {
// Check if the error is a 404 or 403 error for versioned APIs
if e, ok := err.(*fiber.Error); ok {
if e.Code == fiber.StatusNotFound || e.Code == fiber.StatusForbidden {
// Check if the request path matches a versioned API route
if isVersionedAPIRoute(c.Path()) {
// Return a JSON response for 404 or 403 errors in versioned APIs
return c.Status(e.Code).JSON(fiber.Map{
"error": e.Message,
})
}
}
}
// Check if the error is a 404 or 403 error for frontend routes
if e, ok := err.(*fiber.Error); ok {
if e.Code == fiber.StatusNotFound {
// Check if the request path matches a frontend route
if isFrontendRoute(c.Path()) {
// Render the 404 error page for frontend routes
return webPageHandler.PageNotFoundHandler(c)
}
} else if e.Code == fiber.StatusForbidden {
// Check if the request path matches a frontend route
if isFrontendRoute(c.Path()) {
// Render the 403 error page for frontend routes
return webPageHandler.PageForbidden403Handler(c)
}
}
}
// If the error is not a 404 or 403 error for versioned APIs or frontend routes, check if it's an internal server error
if e, ok := err.(*fiber.Error); ok && e.Code == fiber.StatusInternalServerError {
// Return a JSON response for internal server errors in versioned APIs
return apiInternalServerErrorHandler(c, err)
}
// If the error is not a versioned API error, frontend error, or internal server error, fallback to the general error page
return webPageHandler.Page500InternalServerHandler(c, err)
}
// ... rest of the code ...
})
When a versioned API route is not found, it will use the original message provided by the Fiber framework, as it is reusable. Example:
[!NOTE] Also note that
Page500InternalServerHandler
andapiInternalServerErrorHandler
are for handling manipulate panics.
Like we mentioned in the other issues/PRs, versioning is something that can be handled by each user as they see fit.
Tell us about your feature request
As there is no implementation for better versioning of REST APIs/Web Front End for the Fiber framework, if anyone agrees, I can submit a pull request. This will also make it easier for maintainability, reusability, and scalability, following the idiomatic Go style.
Example:
Disclaimer