@@ -18,13 +18,20 @@ package api
1818
1919import (
2020 "encoding/json"
21+ "fmt"
22+ "mime"
2123 "net/http"
24+ "strings"
2225)
2326
27+ // Envelope is the body of all requests and responses that contain data.
28+ // NOTE: error responses use the ErrorEnvelope type
2429type Envelope [D any ] struct {
30+ // TODO: make all declarations of Envelope use pointers for D
2531 Data D `json:"data"`
2632}
2733
34+ // WriteJSON writes a JSON response with the given status code, data, and headers.
2835func (a * App ) WriteJSON (w http.ResponseWriter , status int , data any , headers http.Header ) error {
2936
3037 js , err := json .MarshalIndent (data , "" , "\t " )
@@ -47,3 +54,42 @@ func (a *App) WriteJSON(w http.ResponseWriter, status int, data any, headers htt
4754
4855 return nil
4956}
57+
58+ // DecodeJSON decodes the JSON request body into the given value.
59+ func (a * App ) DecodeJSON (r * http.Request , v any ) error {
60+ decoder := json .NewDecoder (r .Body )
61+ decoder .DisallowUnknownFields ()
62+ if err := decoder .Decode (v ); err != nil {
63+ return fmt .Errorf ("error decoding JSON: %w" , err )
64+ }
65+ return nil
66+ }
67+
68+ // ValidateContentType validates the Content-Type header of the request.
69+ // If this method returns false, the request has been handled and the caller should return immediately.
70+ // If this method returns true, the request has the correct Content-Type.
71+ func (a * App ) ValidateContentType (w http.ResponseWriter , r * http.Request , expectedMediaType string ) bool {
72+ contentType := r .Header .Get ("Content-Type" )
73+ if contentType == "" {
74+ a .unsupportedMediaTypeResponse (w , r , fmt .Errorf ("Content-Type header is missing" ))
75+ return false
76+ }
77+ mediaType , _ , err := mime .ParseMediaType (contentType )
78+ if err != nil {
79+ a .badRequestResponse (w , r , fmt .Errorf ("error parsing Content-Type header: %w" , err ))
80+ return false
81+ }
82+ if mediaType != expectedMediaType {
83+ a .unsupportedMediaTypeResponse (w , r , fmt .Errorf ("unsupported media type: %s, expected: %s" , mediaType , expectedMediaType ))
84+ return false
85+ }
86+
87+ return true
88+ }
89+
90+ // LocationGetWorkspace returns the GET location (HTTP path) for a workspace resource.
91+ func (a * App ) LocationGetWorkspace (namespace , name string ) string {
92+ path := strings .Replace (WorkspacesByNamePath , ":" + NamespacePathParam , namespace , 1 )
93+ path = strings .Replace (path , ":" + ResourceNamePathParam , name , 1 )
94+ return path
95+ }
0 commit comments