Understanding the request

The http.Request object gives us access to every piece of information we might need about the underlying HTTP request, and therefore it is worth glancing through the net/http documentation to really get a feel for its power. Examples include, but are not limited to:

  • URL, path and query string
  • HTTP method
  • Cookies
  • Files
  • Form values
  • Referrer and user agent of requester
  • Basic authentication details
  • Request body
  • Header information

There are a few things it doesn't address, which we need to either solve ourselves or look to an external package to help us with. URL path parsing is one such example—while we can access a path (such as /people/1/books/2) as a string via the http.Request type's URL.Path field, there is no easy way to pull out the data encoded in the path such as the people ID of 1, or the books ID of 2.

Note

A few projects do a good job of addressing this problem, such as Goweb or Gorillz's mux package. They let you map path patterns that contain placeholders for values that they then pull out of the original string and make available to your code. For example, you can map a pattern of /users/{userID}/comments/{commentID}, which will map paths such as /users/1/comments/2. In your handler code, you can then get the values by the names placed inside the curly braces, rather than having to parse the path yourself.

Since our needs are simple, we are going to knock together a simple path-parsing utility; we can always use a different package later if we have to, but that would mean adding a dependency to our project.

Create a new file called path.go, and insert the following code:

package main
import (
  "strings"
)
const PathSeparator = "/"
type Path struct {
  Path string
  ID   string
}
func NewPath(p string) *Path {
  var id string
  p = strings.Trim(p, PathSeparator)
  s := strings.Split(p, PathSeparator)
  if len(s) > 1 {
    id = s[len(s)-1]
    p = strings.Join(s[:len(s)-1], PathSeparator)
  }
  return &Path{Path: p, ID: id}
}
func (p *Path) HasID() bool {
  return len(p.ID) > 0
}

This simple parser provides a NewPath function that parses the specified path string and returns a new instance of the Path type. Leading and trailing slashes are trimmed (using strings.Trim) and the remaining path is split (using strings.Split) by the PathSeparator constant that is just a forward slash. If there is more than one segment (len(s) > 1), the last one is considered to be the ID. We re-slice the slice of strings to select the last item for the ID using s[len(s)-1], and the rest of the items for the remainder of the path using s[:len(s)-1]. On the same lines, we also re-join the path segments with the PathSeparator constant to form a single string containing the path without the ID.

This supports any collection/id pair, which is all we need for our API. The following table shows the state of the Path type for the given original path string:

Original path string

Path

ID

HasID

/

/

nil

false

/people/

people

nil

false

/people/1/

people

1

true

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.144.30.178