Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion common.go
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,14 @@ func handleCustomError(c *fiber.Ctx, customErr interface{}) error {
}

// Return the error as JSON
return c.Status(statusCode).JSON(customErr)
if err := c.Status(statusCode).JSON(customErr); err != nil {
if fallbackErr := c.Status(500).JSON(fiber.Map{"error": "Failed to serialize error response"}); fallbackErr != nil {
// Both serializations failed, return original error to Fiber
return err
}
return nil
}
return nil
}

// Utility to check if a value is zero
Expand Down
13 changes: 12 additions & 1 deletion fiberoapi.go
Original file line number Diff line number Diff line change
Expand Up @@ -861,7 +861,18 @@ func Method[TInput any, TOutput any, TError any](
return handleCustomError(c, customErr)
}

return c.JSON(output)
if err := c.JSON(output); err != nil {
if fallbackErr := c.Status(500).JSON(ErrorResponse{
Code: 500,
Details: "Failed to serialize response",
Type: "serialization_error",
}); fallbackErr != nil {
// Both serializations failed, return original error to Fiber
return err
}
return nil
}
return nil
}

app.f.Add(m, fullPath, fiberHandler)
Expand Down
107 changes: 107 additions & 0 deletions serialization_error_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
package fiberoapi

import (
"encoding/json"
"io"
"net/http/httptest"
"testing"

"github.com/gofiber/fiber/v2"
)

// UnserializableOutput contains a channel which cannot be serialized to JSON
type UnserializableOutput struct {
Name string `json:"name"`
Channel chan string `json:"channel"` // Channels cannot be JSON serialized
}

type SerializationTestInput struct{}

type SerializationTestError struct {
StatusCode int `json:"statusCode"`
Message string `json:"message"`
}

func TestResponseSerializationError(t *testing.T) {
app := fiber.New()
oapi := New(app)

// Handler that returns an unserializable output (contains a channel)
Get(oapi, "/unserializable", func(c *fiber.Ctx, input SerializationTestInput) (UnserializableOutput, *SerializationTestError) {
return UnserializableOutput{
Name: "test",
Channel: make(chan string), // This will fail JSON marshaling
}, nil
}, OpenAPIOptions{
Summary: "Test endpoint with unserializable response",
})

req := httptest.NewRequest("GET", "/unserializable", nil)
resp, err := app.Test(req)
if err != nil {
t.Fatalf("Failed to make request: %v", err)
}

// Should return 500 status code
if resp.StatusCode != 500 {
t.Errorf("Expected status 500, got %d", resp.StatusCode)
}

// Should return a proper error response
body, _ := io.ReadAll(resp.Body)
var errorResp ErrorResponse
if err := json.Unmarshal(body, &errorResp); err != nil {
t.Fatalf("Failed to unmarshal error response: %v. Body: %s", err, string(body))
}

if errorResp.Code != 500 {
t.Errorf("Expected error code 500, got %d", errorResp.Code)
}

if errorResp.Type != "serialization_error" {
t.Errorf("Expected error type 'serialization_error', got '%s'", errorResp.Type)
}
}

// UnserializableError contains a channel which cannot be serialized
type UnserializableError struct {
StatusCode int `json:"statusCode"`
Channel chan string `json:"channel"`
}

func TestErrorSerializationError(t *testing.T) {
app := fiber.New()
oapi := New(app)

// Handler that returns an unserializable error
Get(oapi, "/unserializable-error", func(c *fiber.Ctx, input SerializationTestInput) (map[string]string, *UnserializableError) {
return nil, &UnserializableError{
StatusCode: 400,
Channel: make(chan string), // This will fail JSON marshaling
}
}, OpenAPIOptions{
Summary: "Test endpoint with unserializable error",
})

req := httptest.NewRequest("GET", "/unserializable-error", nil)
resp, err := app.Test(req)
if err != nil {
t.Fatalf("Failed to make request: %v", err)
}

// Should return 500 status code (fallback error)
if resp.StatusCode != 500 {
t.Errorf("Expected status 500, got %d", resp.StatusCode)
}

// Should return a proper error response
body, _ := io.ReadAll(resp.Body)
var errorResp map[string]string
if err := json.Unmarshal(body, &errorResp); err != nil {
t.Fatalf("Failed to unmarshal error response: %v. Body: %s", err, string(body))
}

if errorResp["error"] != "Failed to serialize error response" {
t.Errorf("Expected error message 'Failed to serialize error response', got '%s'", errorResp["error"])
}
}
Loading