Skip to content

Commit c8623b2

Browse files
authored
feat(api): error mapping (#3708)
1 parent cb7b1b2 commit c8623b2

File tree

3 files changed

+51
-45
lines changed

3 files changed

+51
-45
lines changed

api/v3/apierrors/handler.go

Lines changed: 6 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -13,51 +13,17 @@ import (
1313

1414
const httpStatusCodeErrorAttribute = "openmeter.http.status_code"
1515

16-
type v3ErrorMapping struct {
17-
match func(err error) bool
18-
build func(ctx context.Context, err error) *BaseAPIError
16+
type ErrorMapping struct {
17+
Match func(err error) bool
18+
Build func(ctx context.Context, err error) *BaseAPIError
1919
}
2020

2121
// NewV3ErrorHandlerFunc returns an oapi-codegen ChiServerOptions.ErrorHandlerFunc implementation.
2222
//
2323
// It is invoked when the generated router fails request binding (query/path/header parsing).
2424
// The main purpose is to ensure we always write a response (otherwise net/http defaults to 200 with
2525
// an empty body), and to keep error-to-status mapping consistent with our model error types.
26-
func NewV3ErrorHandlerFunc(logger errorsx.Handler) func(w http.ResponseWriter, r *http.Request, err error) {
27-
// Mirrors pkg/framework/commonhttp/encoder.go GenericErrorEncoder ordering (after the status-code attribute mapping).
28-
mappings := []v3ErrorMapping{
29-
{
30-
match: models.IsGenericConflictError,
31-
build: func(ctx context.Context, err error) *BaseAPIError { return NewConflictError(ctx, err, err.Error()) },
32-
},
33-
{
34-
match: models.IsGenericForbiddenError,
35-
build: func(ctx context.Context, err error) *BaseAPIError { return NewForbiddenError(ctx, err) },
36-
},
37-
{
38-
match: models.IsGenericNotImplementedError,
39-
build: func(ctx context.Context, err error) *BaseAPIError { return NewNotImplementedError(ctx, err) },
40-
},
41-
{
42-
match: models.IsGenericValidationError,
43-
build: func(ctx context.Context, err error) *BaseAPIError { return NewBadRequestError(ctx, err, nil) },
44-
},
45-
{
46-
match: models.IsGenericNotFoundError,
47-
build: func(ctx context.Context, err error) *BaseAPIError { return NewNotFoundError(ctx, err, "") },
48-
},
49-
{
50-
match: models.IsGenericUnauthorizedError,
51-
build: func(ctx context.Context, err error) *BaseAPIError { return NewUnauthenticatedError(ctx, err) },
52-
},
53-
{
54-
match: models.IsGenericPreConditionFailedError,
55-
build: func(ctx context.Context, err error) *BaseAPIError {
56-
return NewPreconditionFailedError(ctx, err.Error())
57-
},
58-
},
59-
}
60-
26+
func NewV3ErrorHandlerFunc(logger errorsx.Handler, mappings []ErrorMapping) func(w http.ResponseWriter, r *http.Request, err error) {
6127
return func(w http.ResponseWriter, r *http.Request, err error) {
6228
if err == nil {
6329
return
@@ -90,9 +56,9 @@ func NewV3ErrorHandlerFunc(logger errorsx.Handler) func(w http.ResponseWriter, r
9056
}
9157

9258
for _, m := range mappings {
93-
if m.match(err) {
59+
if m.Match(err) {
9460
logger.HandleContext(ctx, err)
95-
m.build(ctx, err).HandleAPIError(w, r)
61+
m.Build(ctx, err).HandleAPIError(w, r)
9662
return
9763
}
9864
}

api/v3/server/server.go

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import (
3030
"github.com/openmeterio/openmeter/openmeter/subscription"
3131
"github.com/openmeterio/openmeter/pkg/errorsx"
3232
"github.com/openmeterio/openmeter/pkg/framework/transport/httptransport"
33+
"github.com/openmeterio/openmeter/pkg/models"
3334
)
3435

3536
type Config struct {
@@ -207,7 +208,50 @@ func (s *Server) RegisterRoutes(r chi.Router) error {
207208
Middlewares: []api.MiddlewareFunc{
208209
validationMiddleware,
209210
},
210-
ErrorHandlerFunc: apierrors.NewV3ErrorHandlerFunc(s.ErrorHandler),
211+
ErrorHandlerFunc: apierrors.NewV3ErrorHandlerFunc(s.ErrorHandler, []apierrors.ErrorMapping{
212+
{
213+
Match: models.IsGenericConflictError,
214+
Build: func(ctx context.Context, err error) *apierrors.BaseAPIError {
215+
return apierrors.NewConflictError(ctx, err, err.Error())
216+
},
217+
},
218+
{
219+
Match: models.IsGenericForbiddenError,
220+
Build: func(ctx context.Context, err error) *apierrors.BaseAPIError {
221+
return apierrors.NewForbiddenError(ctx, err)
222+
},
223+
},
224+
{
225+
Match: models.IsGenericNotImplementedError,
226+
Build: func(ctx context.Context, err error) *apierrors.BaseAPIError {
227+
return apierrors.NewNotImplementedError(ctx, err)
228+
},
229+
},
230+
{
231+
Match: models.IsGenericValidationError,
232+
Build: func(ctx context.Context, err error) *apierrors.BaseAPIError {
233+
return apierrors.NewBadRequestError(ctx, err, nil)
234+
},
235+
},
236+
{
237+
Match: models.IsGenericNotFoundError,
238+
Build: func(ctx context.Context, err error) *apierrors.BaseAPIError {
239+
return apierrors.NewNotFoundError(ctx, err, "")
240+
},
241+
},
242+
{
243+
Match: models.IsGenericUnauthorizedError,
244+
Build: func(ctx context.Context, err error) *apierrors.BaseAPIError {
245+
return apierrors.NewUnauthenticatedError(ctx, err)
246+
},
247+
},
248+
{
249+
Match: models.IsGenericPreConditionFailedError,
250+
Build: func(ctx context.Context, err error) *apierrors.BaseAPIError {
251+
return apierrors.NewPreconditionFailedError(ctx, err.Error())
252+
},
253+
},
254+
}),
211255
})
212256
})
213257

openmeter/server/server.go

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -102,10 +102,6 @@ func NewServer(config *Config) (*Server, error) {
102102
server.NewRequestLoggerMiddleware(slog.Default().Handler()),
103103
middleware.Recoverer,
104104
}
105-
// Append PostAuthMiddlewares (e.g., FFXConfigContextMiddleware) to V3 API middlewares
106-
for _, mw := range config.PostAuthMiddlewares {
107-
v3Middlewares = append(v3Middlewares, mw)
108-
}
109105

110106
v3API, err := v3server.NewServer(&v3server.Config{
111107
BaseURL: "/api/v3",

0 commit comments

Comments
 (0)