Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds Cookie and Header methods to context #84

Merged
merged 1 commit into from
Mar 20, 2024
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
25 changes: 25 additions & 0 deletions ctx.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,11 @@ type ctx[B any] interface {
// By default, [templateToExecute] is added to the list of templates to override.
Render(templateToExecute string, data any, templateGlobsToOverride ...string) (HTML, error)

Cookie(name string) (*http.Cookie, error) // Get request cookie
SetCookie(cookie http.Cookie) // Sets response cookie
Header(key string) string // Get request header
SetHeader(key, value string) // Sets response header

Context() context.Context

Request() *http.Request // Request returns the underlying http request.
Expand Down Expand Up @@ -162,6 +167,26 @@ func (c ContextNoBody) Context() context.Context {
return c.Req.Context()
}

// Get request header
func (c ContextNoBody) Header(key string) string {
return c.Request().Header.Get(key)
}

// Sets response header
func (c ContextNoBody) SetHeader(key, value string) {
c.Response().Header().Set(key, value)
}

// Get request cookie
func (c ContextNoBody) Cookie(name string) (*http.Cookie, error) {
return c.Request().Cookie(name)
}

// Sets response cookie
func (c ContextNoBody) SetCookie(cookie http.Cookie) {
http.SetCookie(c.Response(), &cookie)
}

// Render renders the given templates with the given data.
// It returns just an empty string, because the response is written directly to the http.ResponseWriter.
//
Expand Down
45 changes: 42 additions & 3 deletions documentation/docs/guides/controllers.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ import FlowChart from '@site/src/components/FlowChart';

Controllers are the main way to interact with the application. They are responsible for handling the requests and responses.



<FlowChart selected="Controller" />

## Controller types
Expand Down Expand Up @@ -48,7 +46,7 @@ type MyResponse struct {
Message string `json:"message"`
}

func MyController(ctx *fuego.ContextWithBody[MyInput]) (MyResponse, error) {
func MyController(c *fuego.ContextWithBody[MyInput]) (MyResponse, error) {
body, err := c.Body()
if err != nil {
return MyResponse{}, err
Expand All @@ -60,3 +58,44 @@ func MyController(ctx *fuego.ContextWithBody[MyInput]) (MyResponse, error) {
}
```

## Headers

You can always go further in the request and response by using the underlying net/http request and response, by using `c.Request` and `c.Response`.

### Get request header

```go
func MyController(c *fuego.ContextNoBody) (MyResponse, error) {
value := c.Header("X-My-Header")
return MyResponse{}, nil
}
```

### Set response header

```go
func MyController(c *fuego.ContextNoBody) (MyResponse, error) {
c.SetHeader("X-My-Header", "value")
return MyResponse{}, nil
}
```

## Cookies

### Get request cookie

```go
func MyController(c *fuego.ContextNoBody) (MyResponse, error) {
value := c.Cookie("my-cookie")
return MyResponse{}, nil
}
```

### Set response cookie

```go
func MyController(c *fuego.ContextNoBody) (MyResponse, error) {
c.SetCookie("my-cookie", "value")
return MyResponse{}, nil
}
```
21 changes: 17 additions & 4 deletions documentation/docs/guides/openapi.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,10 @@ func main() {
s := fuego.NewServer(fuego.WithOpenAPIConfig(fuego.OpenAPIConfig{
DisableSwagger : false, // If true, the server will not serve the swagger ui nor the openapi json spec
DisableLocalSave : false, // If true, the server will not save the openapi json spec locally
SwaggerUrl : "/xxx", // URL to serve the swagger ui
JsonUrl : "/xxx/swagger.json", // URL to serve the openapi json spec
JsonFilePath : "./foo/bar.json", // Local path to save the openapi json spec
SwaggerUrl : "/swagger", // URL to serve the swagger ui
JsonUrl : "/swagger/openapi.json", // URL to serve the openapi json spec
JsonFilePath : "doc/openapi.json", // Local path to save the openapi json spec
UIHandler : DefaultOpenAPIHandler, // Custom UI handler
}))

fuego.Get(s, "/", func(c fuego.ContextNoBody) (string, error) {
Expand Down Expand Up @@ -114,6 +115,18 @@ func openApiHandler(specURL string) http.Handler {
httpSwagger.URL(specURL), // The url pointing to API definition
)
}

func main() {
s := fuego.NewServer(
fuego.WithOpenAPIConfig(fuego.OpenAPIConfig{
UIHandler: openApiHandler("/swagger.json"),
}),
)

fuego.Get(s, "/", helloWorld)

s.Run()
}
```

The default spec url reference Element Stoplight swagger ui.
Expand Down Expand Up @@ -157,4 +170,4 @@ func main() {

s.Run()
}
```
```
2 changes: 1 addition & 1 deletion middleware/cache/cache_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ type testStruct struct {

const waitTime = 10 * time.Millisecond

func baseController(ctx *fuego.ContextNoBody) (testStruct, error) {
func baseController(c *fuego.ContextNoBody) (testStruct, error) {
time.Sleep(waitTime)
return testStruct{Name: "test", Age: 10}, nil
}
Expand Down
42 changes: 42 additions & 0 deletions mux_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package fuego

import (
"encoding/json"
"fmt"
"net/http"
"net/http/httptest"
"strings"
Expand Down Expand Up @@ -494,3 +495,44 @@ func TestGroup(t *testing.T) {
require.Equal(t, "/slash/", g.basePath)
})
}

func ExampleContextNoBody_SetCookie() {
s := NewServer()
Get(s, "/test", func(c *ContextNoBody) (string, error) {
c.SetCookie(http.Cookie{
Name: "name",
Value: "value",
})
return "test", nil
})

w := httptest.NewRecorder()
r := httptest.NewRequest(http.MethodGet, "/test", nil)

s.Mux.ServeHTTP(w, r)

fmt.Println(w.Result().Cookies()[0].Name)
fmt.Println(w.Result().Cookies()[0].Value)

// Output:
// name
// value
}

func ExampleContextNoBody_SetHeader() {
s := NewServer()
Get(s, "/test", func(c *ContextNoBody) (string, error) {
c.SetHeader("X-Test", "test")
return "test", nil
})

w := httptest.NewRecorder()
r := httptest.NewRequest(http.MethodGet, "/test", nil)

s.Mux.ServeHTTP(w, r)

fmt.Println(w.Header().Get("X-Test"))

// Output:
// test
}
Loading