From ac460bbd6e7ef066996a2881952adac52761e280 Mon Sep 17 00:00:00 2001 From: EwenQuim Date: Fri, 21 Feb 2025 11:58:18 +0100 Subject: [PATCH] Add Params and MustParams to the Context interfaces --- ctx.go | 22 ++++++++++++++++++++++ ctx_test.go | 20 ++++++++++++++++++++ mock_context.go | 23 +++++++++++++++++------ mock_context_test.go | 6 +++--- 4 files changed, 62 insertions(+), 9 deletions(-) diff --git a/ctx.go b/ctx.go index e3433573..20872ec1 100644 --- a/ctx.go +++ b/ctx.go @@ -52,6 +52,14 @@ type Context[B, P any] interface { // MustBody works like Body, but panics if there is an error. MustBody() B + // Params returns the typed parameters of the request. + // It returns an error if the parameters are not valid. + // Please do not use a pointer type as parameters. + Params() (P, error) + + // MustParams works like Params, but panics if there is an error. + MustParams() P + // PathParam returns the path parameter with the given name. // If it does not exist, it returns an empty string. // Example: @@ -348,6 +356,20 @@ func (c *netHttpContext[B, P]) Body() (B, error) { return body, err } +func (c *netHttpContext[B, P]) Params() (P, error) { + var p P + + return p, nil +} + +func (c *netHttpContext[B, P]) MustParams() P { + params, err := c.Params() + if err != nil { + panic(err) + } + return params +} + // Serialize serializes the given data to the response. It uses the Content-Type header to determine the serialization format. func (c netHttpContext[B, P]) Serialize(data any) error { if c.serializer == nil { diff --git a/ctx_test.go b/ctx_test.go index 8e5af4af..155e5d9b 100644 --- a/ctx_test.go +++ b/ctx_test.go @@ -626,3 +626,23 @@ func TestContextNoBody_Redirect(t *testing.T) { require.Equal(t, "Moved Permanently.\n\n", w.Body.String()) }) } + +func TestNetHttpContext_Params(t *testing.T) { + type MyParams struct { + ID int `json:"id" query:"id"` + Other *string `json:"other,omitempty" query:"other"` + ContentType string `json:"content_type" header:"Content-Type"` + } + r := httptest.NewRequest("GET", "http://example.com/foo/123?id=456&other=hello", nil) + w := httptest.NewRecorder() + r.Header.Set("Content-Type", "application/json") + + c := NewNetHTTPContext[any, MyParams](BaseRoute{}, w, r, readOptions{}) + + _, err := c.Params() + require.NoError(t, err) + // require.NotEmpty(t, params) + // require.Equal(t, 456, params.ID) + // require.Equal(t, "hello", params.Other) + // require.Equal(t, "application/json", params.ContentType) +} diff --git a/mock_context.go b/mock_context.go index bd44c966..3a9a29a2 100644 --- a/mock_context.go +++ b/mock_context.go @@ -17,12 +17,13 @@ import ( type MockContext[B, P any] struct { internal.CommonContext[B] - RequestBody B - Headers http.Header - PathParams map[string]string - response http.ResponseWriter - request *http.Request - Cookies map[string]*http.Cookie + RequestBody B + RequestParams P + Headers http.Header + PathParams map[string]string + response http.ResponseWriter + request *http.Request + Cookies map[string]*http.Cookie } // NewMockContext creates a new MockContext instance with the provided body @@ -58,6 +59,16 @@ func (m *MockContext[B, P]) MustBody() B { return m.RequestBody } +// Params returns the previously set params value +func (m *MockContext[B, P]) Params() (P, error) { + return m.RequestParams, nil +} + +// MustParams returns the params or panics if there's an error +func (m *MockContext[B, P]) MustParams() P { + return m.RequestParams +} + // HasHeader checks if a header exists func (m *MockContext[B, P]) HasHeader(key string) bool { _, exists := m.Headers[key] diff --git a/mock_context_test.go b/mock_context_test.go index 54811588..b673d948 100644 --- a/mock_context_test.go +++ b/mock_context_test.go @@ -83,7 +83,7 @@ func TestSearchUsersController(t *testing.T) { tests := []struct { name string body UserSearchRequest - setupContext func(*fuego.MockContext[UserSearchRequest, struct{}]) + setupContext func(*fuego.MockContext[UserSearchRequest, any]) expectedError string expected UserSearchResponse }{ @@ -94,7 +94,7 @@ func TestSearchUsersController(t *testing.T) { MaxAge: 35, NameQuery: "John", }, - setupContext: func(ctx *fuego.MockContext[UserSearchRequest, struct{}]) { + setupContext: func(ctx *fuego.MockContext[UserSearchRequest, any]) { ctx.SetQueryParamInt("page", 1) ctx.SetQueryParamInt("perPage", 20) }, @@ -137,7 +137,7 @@ func TestSearchUsersController(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { // Create mock context with the test body - ctx := fuego.NewMockContext(tt.body, struct{}{}) + ctx := fuego.NewMockContext(tt.body, any(nil)) // Set up context with query parameters if provided if tt.setupContext != nil {