Adding 'Advanced JSON Customization' section in the README.md. Creating a runtime type (internal/data/runtime.go) to show how we can customize a JSON field.
All checks were successful
Deploy Greenlight API / deploy (push) Successful in 56s
All checks were successful
Deploy Greenlight API / deploy (push) Successful in 56s
This commit is contained in:
18
README.md
18
README.md
@@ -82,6 +82,24 @@ Enveloping response data like this isn't strictly necessary, and whether you cho
|
||||
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.
|
||||
|
||||
### Advanced JSON Customization
|
||||
|
||||
_When Go is encoding a particular type to JSON, it looks to see if the type has a **MarshalJSON()** method implemented on it. If it has, then Go will call this method to determine how to encode it._
|
||||
|
||||
Strictly speaking, when Go is encoding a particular type to JSON it looks to see if the type satisfies the json.Marshaler interface, which looks like this :
|
||||
|
||||
`type Marshaler interface {
|
||||
MarshalJSON() ([]byte, error)
|
||||
}`
|
||||
|
||||
If the type does satisfy the interface, then Go will call its **MarshalJSON()** method and use the []byte slice that it returns as the encoded JSON value.
|
||||
|
||||
If the type doesn't have a **MarshalJSON()** method, then Go will fall back to trying to encode it to JSON based on its own internal set of rules.
|
||||
|
||||
So, if we want to customize how something is encoded, all we need to do is implement a **MarshalJSON()** method on it which returns a _custom JSON representation of itself_ in a **[]byte** slice.
|
||||
|
||||
An example is available here : **internal/data/runtime.go**
|
||||
|
||||
### 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.
|
||||
|
||||
33
internal/data/runtime.go
Normal file
33
internal/data/runtime.go
Normal file
@@ -0,0 +1,33 @@
|
||||
package data
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// Runtime
|
||||
/*
|
||||
Declare a custom Runtime type, which has the underlying type int32
|
||||
(the same as our Movie struct field)
|
||||
*/
|
||||
type Runtime int32
|
||||
|
||||
// MarshalJSON
|
||||
/*
|
||||
Implement a MarshalJSON() method on the Runtime type so that it satisfies
|
||||
the json.Marshaler interface. This should return the JSON-encoded value
|
||||
for the movie runtime (in our case, it will return string in the format
|
||||
"<runtime> mins").
|
||||
*/
|
||||
func (r Runtime) MarshalJSON() ([]byte, error) {
|
||||
// Generate a string containing the movie runtime in the required format.
|
||||
jsonValue := fmt.Sprintf("%d mins", r)
|
||||
|
||||
// Use the strconv.Quote() function on the string to wrap it in double
|
||||
// quotes. It needs to be surrounded by double quotes in order to be
|
||||
// a valid *JSON string*.
|
||||
quotedJSONValue := strconv.Quote(jsonValue)
|
||||
|
||||
// Convert the quoted string value to a byte slice and return it.
|
||||
return []byte(quotedJSONValue), nil
|
||||
}
|
||||
Reference in New Issue
Block a user