Daaang Amy
open main menu
Part of series: Learning the Backend

Let's Go Further Ch 1-5

/ 3 min read

For the next part in my backend dev journey, I’ll be starting Let's Go Further! This time, instead of putting all my notes for the chapters in one post, I’m going to spread some of them out into mini posts instead. That way I can easily search for them later when I need them. I’ll be putting relevant links here.

Using the Correct HTTP Request Method

MethodUsage
GETuse for retrieving information only
POSTuse for non-indempotent actions. Generally used for creating a new resource
PUTuse for indempotent actions. Generally used for updating or replacing a new resource
PATCHuse for actions thaat partially update a resource at a specific URL
DELETEuse for deleting a resource at a specific URL

Enveloping JSON Responses

There are many ways you can design your JSON Repsonses and there’s no right or wrong way but it’s important to think about the formatting upfront. A good format is to always envelope your response with a parent JSON object.

A few benefits:

  1. self-documenting
  2. reduces risk of errors on the client side
  3. mitigate a security vulnerability in older browsers

Something cool with embedding structs

We can take advantage of struct embedding to create an alias of a struct and copy over fields and values. That way don’t somehow change values from the original data and make a copy of it instead.

type Movie struct {
  ID        int64     `json:"id"`
  CreatedAt time.Time `json:"created_at"`
  Title     string    `json:"title"`
  Year      int32     `json:"year,omitempty"`
  Runtime   Runtime   `json:"runtime,omitempty"`
  Genres    []string  `json:"genres,omitempty"`
  Version   int32     `json:"version"`
}


type MovieAlias Movie

func (m Movie) MarshalJSON() ([]byte, error) {
  var runtime string
  if m.Runtime != 0 {
    runtime = fmt.Sprintf("%d mins", m.Runtime)
  }

  aux := struct {
    MovieAlias
    Runtime string `json:"runtime,omitempty"`
  } {
    MovieAlias: MovieAlias(m),
    Runtime: runtime,
  }

  return json.Marshal(aux)
}

JSON Validators

Given this struct:

type Validator struct {
	Errors map[string]string
}

func New() *Validator {
  return &Validator{Errors: make(map[string]string)}
}

❓Why would you create a new Validator pointer instead of just a new Validator?

Guess: Maybe we create a new pointer when we only expect to have one instance of it? For example, you wouldn’t need more than one validator object since it’s a helper struct to just store all validation errors and nothing more.

Answer?: ❗In Go, when a struct is passed into a function, it is is passed by copy not by reference. Which means that when we validate data and then store errors messages inside Validator.Errors, that data is lost in the parent function. You lose access to the new data. A workaround for this is to return a new object Validator but that would waste memory space.

When you pass by reference, you’ll be able to grab the changes by grabbing it from memory. Rather than needing to create a new variable to store the changed data.

So the answer is:

  1. we need access to that data in the parent function (the one calling the validation methods)
  2. reduce memory usage

Other Notes Relevant To Ch 1-5

Previous Let’s Go Posts