Skip to content

Commit

Permalink
feat: add support for different content types (#835)
Browse files Browse the repository at this point in the history
Basic support for different content-types on HTTP responses. This will
need to be extended in the future, but is setup now to support `text/`
types. This will definitely need more thought in the future.

This allows us to return HTML content from an HTTP ingress

```go
return builtin.HttpResponse[string]{
	Status:  200,
	Headers: map[string][]string{"Content-Type": {"text/html; charset=utf-8"}},
	Body:    "<html><body><h1>HTML Page From FTL 🚀!</h1></body></html>",
}, nil
```

![Screenshot 2024-01-25 at 10 12
07 AM](https://github.com/TBD54566975/ftl/assets/51647/acb413f9-5be3-4c5c-868b-dda155512f44)
  • Loading branch information
wesbillman authored Jan 25, 2024
1 parent c626426 commit ecbfab8
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 4 deletions.
14 changes: 10 additions & 4 deletions backend/controller/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -170,9 +170,9 @@ func New(ctx context.Context, db *dal.DAL, config Config, runnerScaling scaling.
}

type HTTPResponse struct {
Status int
Headers map[string][]string
Body json.RawMessage
Status int `json:"status"`
Headers map[string][]string `json:"headers"`
Body json.RawMessage `json:"body"`
}

// ServeHTTP handles ingress routes.
Expand Down Expand Up @@ -248,11 +248,17 @@ func (s *Service) ServeHTTP(w http.ResponseWriter, r *http.Request) {
return
}

responseBody, err = ingress.ResponseBodyForContentType(response.Headers, response.Body)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}

for k, v := range response.Headers {
w.Header()[k] = v
}
w.WriteHeader(response.Status)
responseBody = response.Body

} else {
w.WriteHeader(http.StatusOK)
w.Header().Set("Content-Type", "application/json; charset=utf-8")
Expand Down
13 changes: 13 additions & 0 deletions backend/controller/ingress/ingress.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,19 @@ func matchSegments(pattern, urlPath string, onMatch func(segment, value string))
return true
}

func ResponseBodyForContentType(headers map[string][]string, body []byte) ([]byte, error) {
contentType, hasContentType := headers["Content-Type"]
if !hasContentType || len(contentType) == 0 || contentType[0] == "" || !strings.HasPrefix(contentType[0], "text/") {
return body, nil
}

var htmlContent string
if err := json.Unmarshal(body, &htmlContent); err != nil {
return nil, err
}
return []byte(htmlContent), nil
}

func ValidateCallBody(body []byte, verbRef *schema.VerbRef, sch *schema.Schema) error {
verb := sch.ResolveVerbRef(verbRef)
if verb == nil {
Expand Down
12 changes: 12 additions & 0 deletions examples/go/httpingress/httpingress.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,3 +102,15 @@ func Delete(ctx context.Context, req builtin.HttpRequest[DeleteRequest]) (builti
Body: DeleteResponse{},
}, nil
}

type HtmlRequest struct{}

//ftl:verb
//ftl:ingress http GET /http/html
func Html(ctx context.Context, req builtin.HttpRequest[HtmlRequest]) (builtin.HttpResponse[string], error) {
return builtin.HttpResponse[string]{
Status: 200,
Headers: map[string][]string{"Content-Type": {"text/html; charset=utf-8"}},
Body: "<html><body><h1>HTML Page From FTL 🚀!</h1></body></html>",
}, nil
}

0 comments on commit ecbfab8

Please sign in to comment.