Creating an envelope struct type inside our helpers file to update our writeJSON data type method's parameter. Updating healthcheckHandler and showMovieHandler with this new type to update our responses.
This commit is contained in:
11
README.md
11
README.md
@@ -73,9 +73,18 @@ A few other important things to mention :
|
||||
- Channels, functions and **complex** number types cannot be encoded. If you try to do so, you'll get a **json.UnsupportedTypeError** error at runtime.
|
||||
- Any pointer values will encode as *the value pointed to*.
|
||||
|
||||
### Enveloping responses
|
||||
|
||||
The data of the endpoint /v1/movies/123 is nested under the key "movie", rather than being the top-level JSON object itself.
|
||||
Enveloping response data like this isn't strictly necessary, and whether you choose to do so is partly a matter of style and taste. But there are a few tangible benefits :
|
||||
|
||||
1. Including a key name (like "movie") at the top-level of the JSON helps make the response more self-documenting. For any humans who see the response out of context, it is a bit easier to understand what the data relates to.
|
||||
2. It reduces the risk of errors on the client side, because it's harder to accidentally process one response thinking that it is something different. To get at the data, a client must explicitly reference it via the "movie" key.
|
||||
3. If we always envelope the data returned by our API, then we mitigate a security vulnerability in older browsers which can arise if you return a JSON array as a response.
|
||||
|
||||
### Performance
|
||||
|
||||
json.MarshalIndent() takes 65% longer to run and uses around 30% more memory than json.Marshal(), as well as making two more heap allocations. Those figures will change depending on what you're encoding, but they're fairly indicative of the performance impact.
|
||||
|
||||
For most applications this performance difference simply isn't something that you need to worry about. In real terms, we're talking about a few thousandths of a millisecond - and the improved readability of responses is probably worth this trade-off.
|
||||
But if your API is operating in a very resource-constrained environment, or needs to manage extremely high levels of traffic, then this is worth being aware of and you may prefer to stick with using json.Marshal() instead.
|
||||
But if your API is operating in a very resource-constrained environment, or needs to manage extremely high levels of traffic, then this is worth being aware of, and you may prefer to stick with using json.Marshal() instead.
|
||||
@@ -13,13 +13,13 @@ initialize it in main()
|
||||
*/
|
||||
func (app *application) healthcheckHandler(w http.ResponseWriter, r *http.Request) {
|
||||
// Create a map which holds the information that we want to send in the response.
|
||||
data := map[string]string{
|
||||
env := envelope{
|
||||
"status": "available",
|
||||
"environment": app.config.env,
|
||||
"version": version,
|
||||
}
|
||||
|
||||
err := app.writeJSON(w, http.StatusOK, data, nil)
|
||||
err := app.writeJSON(w, http.StatusOK, env, nil)
|
||||
if err != nil {
|
||||
app.logger.Error(err.Error())
|
||||
http.Error(w, "The server encountered a problem and could not process your request", http.StatusInternalServerError)
|
||||
|
||||
@@ -43,12 +43,14 @@ func (app *application) readIDParam(r *http.Request) (int64, error) {
|
||||
return id, nil
|
||||
}
|
||||
|
||||
type envelope map[string]any
|
||||
|
||||
/*
|
||||
Define a writeJSON() helper for sending responses. This takes the destination
|
||||
http.ResponseWriter, the HTTP status code to send, the data to encode to JSON, and a
|
||||
header map containing any additional HTTP headers we want to include in the response.
|
||||
*/
|
||||
func (app *application) writeJSON(w http.ResponseWriter, status int, data any, headers http.Header) error {
|
||||
func (app *application) writeJSON(w http.ResponseWriter, status int, data envelope, headers http.Header) error {
|
||||
/*
|
||||
Use the json.MarshalIndent() function so that whitespace is added to
|
||||
the encoded JSON. Here we use no line prefix ("") and tab indents ("\t") for each element.
|
||||
|
||||
@@ -36,7 +36,7 @@ func (app *application) showMovieHandler(w http.ResponseWriter, r *http.Request)
|
||||
}
|
||||
|
||||
// Encode the struct to JSON and send it as the HTTP response.
|
||||
err = app.writeJSON(w, http.StatusOK, movie, nil)
|
||||
err = app.writeJSON(w, http.StatusOK, envelope{"movie": movie}, nil)
|
||||
if err != nil {
|
||||
app.logger.Error(err.Error())
|
||||
http.Error(w, "The server encountered a problem and could not process your request", http.StatusInternalServerError)
|
||||
|
||||
Reference in New Issue
Block a user