diff --git a/context.go b/context.go index e1d9be43..2e851d72 100644 --- a/context.go +++ b/context.go @@ -272,7 +272,7 @@ func (c *Context) Error(err error) *Error { // Set is used to store a new key/value pair exclusively for this context. // It also lazy initializes c.Keys if it was not used previously. -func (c *Context) Set(key any, value any) { +func (c *Context) Set(key any, value any) *Context { c.mu.Lock() defer c.mu.Unlock() if c.Keys == nil { @@ -280,6 +280,7 @@ func (c *Context) Set(key any, value any) { } c.Keys[key] = value + return c } // Get returns the value for the given key, ie: (value, true). @@ -498,8 +499,9 @@ func (c *Context) Param(key string) string { // Example Route: "/user/:id" // AddParam("id", 1) // Result: "/user/1" -func (c *Context) AddParam(key, value string) { +func (c *Context) AddParam(key, value string) *Context { c.Params = append(c.Params, Param{Key: key, Value: value}) + return c } // Query returns the keyed url query value if it exists, @@ -1044,19 +1046,21 @@ func bodyAllowedForStatus(status int) bool { } // Status sets the HTTP response code. -func (c *Context) Status(code int) { +func (c *Context) Status(code int) *Context { c.Writer.WriteHeader(code) + return c } // Header is an intelligent shortcut for c.Writer.Header().Set(key, value). // It writes a header in the response. // If value == "", this method removes the header `c.Writer.Header().Del(key)` -func (c *Context) Header(key, value string) { +func (c *Context) Header(key, value string) *Context { if value == "" { c.Writer.Header().Del(key) - return + return c } c.Writer.Header().Set(key, value) + return c } // GetHeader returns value from request headers. @@ -1073,14 +1077,15 @@ func (c *Context) GetRawData() ([]byte, error) { } // SetSameSite with cookie -func (c *Context) SetSameSite(samesite http.SameSite) { +func (c *Context) SetSameSite(samesite http.SameSite) *Context { c.sameSite = samesite + return c } // SetCookie adds a Set-Cookie header to the ResponseWriter's headers. // The provided cookie must have a valid Name. Invalid cookies may be // silently dropped. -func (c *Context) SetCookie(name, value string, maxAge int, path, domain string, secure, httpOnly bool) { +func (c *Context) SetCookie(name, value string, maxAge int, path, domain string, secure, httpOnly bool) *Context { if path == "" { path = "/" } @@ -1094,12 +1099,13 @@ func (c *Context) SetCookie(name, value string, maxAge int, path, domain string, Secure: secure, HttpOnly: httpOnly, }) + return c } // SetCookieData adds a Set-Cookie header to the ResponseWriter's headers. // It accepts a pointer to http.Cookie structure for more flexibility in setting cookie attributes. // The provided cookie must have a valid Name. Invalid cookies may be silently dropped. -func (c *Context) SetCookieData(cookie *http.Cookie) { +func (c *Context) SetCookieData(cookie *http.Cookie) *Context { if cookie.Path == "" { cookie.Path = "/" } @@ -1107,6 +1113,7 @@ func (c *Context) SetCookieData(cookie *http.Cookie) { cookie.SameSite = c.sameSite } http.SetCookie(c.Writer, cookie) + return c } // Cookie returns the named cookie provided in the request or @@ -1386,8 +1393,9 @@ func (c *Context) NegotiateFormat(offered ...string) string { } // SetAccepted sets Accept header data. -func (c *Context) SetAccepted(formats ...string) { +func (c *Context) SetAccepted(formats ...string) *Context { c.Accepted = formats + return c } /************************************/ diff --git a/context_test.go b/context_test.go index 016fa86d..a70bea68 100644 --- a/context_test.go +++ b/context_test.go @@ -3677,3 +3677,46 @@ func BenchmarkGetMapFromFormData(b *testing.B) { }) } } + +func TestContextChaining(t *testing.T) { + c, _ := CreateTestContext(httptest.NewRecorder()) + // Basic cookie settings + cookie := &http.Cookie{ + Name: "name", + Value: "gin", + MaxAge: 1, + Path: "/", + Domain: "localhost", + Secure: true, + HttpOnly: true, + } + + c.Set("foo", "bar"). + AddParam("id", "1"). + SetSameSite(http.SameSiteLaxMode). + SetCookie("user", "gin", 1, "/", "localhost", true, true). + SetCookieData(cookie). + Header("Content-Type", "text/plain"). + Header("X-Custom", "value"). + SetAccepted(MIMEJSON, MIMEXML). + Status(200) + + value, err := c.Get("foo") + assert.Equal(t, "bar", value) + assert.True(t, err) + + v, ok := c.Params.Get("id") + assert.True(t, ok) + assert.Equal(t, "1", v) + + assert.Equal(t, []string{"user=gin; Path=/; Domain=localhost; Max-Age=1; HttpOnly; Secure; SameSite=Lax", "name=gin; Path=/; Domain=localhost; Max-Age=1; HttpOnly; Secure"}, c.Writer.Header().Values("Set-Cookie")) + + assert.Equal(t, "text/plain", c.Writer.Header().Get("Content-Type")) + assert.Equal(t, "value", c.Writer.Header().Get("X-Custom")) + + assert.Equal(t, MIMEJSON, c.NegotiateFormat(MIMEJSON, MIMEXML)) //nolint:testifylint + assert.Equal(t, MIMEXML, c.NegotiateFormat(MIMEXML, MIMEHTML)) + assert.Equal(t, MIMEJSON, c.NegotiateFormat(MIMEJSON)) //nolint:testifylint + + assert.Equal(t, 200, c.Writer.Status()) +}