Smarshal (SMARt + unMARSHAL)
(i'm just putting it out there beacuse i make use of it in few of my personal projects to replace boilerplate code in complex (not necessarily well designed) api responses, contributions are welcome)
type User struct {
ID uint `json:"id"`
Email string `json:"email"`
Username string `json:"username"`
}
type Meta struct {
RequestID string `json:"requestID"`
}
user := &User{
ID: 1,
Email: "[email protected]",
Username: "example",
}
meta := &Meta{
RequestID: "be700d399b9761c5f021a8774b304175",
}
b, err := smarshal.Marshal(user, meta)
if err != nil {
...
}
Marshal will return combined struct like below:
{
"id": 1,
"email": "[email protected]",
"username": "example",
"requestID": "be700d399b9761c5f021a8774b304175"
}
Consider this possible API responses:
{
"status": "failed",
"error": "Something went really bad! :c",
"requestID": "be700d399b9761c5f021a8774b304175"
}
{
"id": 1,
"email": "[email protected]",
"username": "example",
"requestID": "be700d399b9761c5f021a8774b304175"
}
Normally you could create a struct containing all possible fields preffarably as pointers so you could check if they are nil and act accordingly. Using this package you can create single CustomError for your API that is universal accross different responses.
type CustomError struct {
Status string `json:"status"`
Error string `json:"error"`
}
type User struct {
ID uint `json:"id"`
Email string `json:"email"`
Username string `json:"username"`
HasPaid bool `json:"hasPaid"`
}
type Meta struct {
RequestID string `json:"requestID"`
}
customErr := &CustomError{}
user := &User{}
meta := &Meta{}
err := smarshal.Unmarshal(apiResponse, &user, &meta, &customErr)
if err != nil {
...
}
if customErr != nil {
...
}
if user != nil {
...
}
if meta != nil {
...
}
Notice double pointer used here to be able to check for nil
when populated struct was equal to its zero value (Unmarshal if provided single pointer will work as expected but will return zero value struct)