Chapter 7. Random Recommendations Web Service

The concept behind the project that we will build in this chapter is a simple one: we want users to be able to generate random recommendations for things to do in specific geographical locations based on a predefined set of journey types that we will expose through the API. We will give our project the codename Meander.

Often on projects in the real world, you are responsible for the full stack; somebody else builds the website, a different person still might write the iOS app, and maybe an outsourced company builds the desktop version. On more successful API projects, you might not even know who the consumers of your API are, especially if it's a public API.

In this chapter, we will simulate this reality by designing and agreeing a minimal API design with a fictional partner up front before going on to implement the API. Once we have finished our side of the project, we will download a user interface built by our teammates to see the two work together to produce the final application.

In this chapter, you will:

  • Learn to express the general goals of a project using short and simple Agile user stories
  • Discover that you can agree a meeting point in a project by agreeing on the design of an API, which allows many people to work in parallel
  • See how early versions of code can actually have data fixtures written in code and compiled into the program, allowing us to change the implementation later without touching the interface
  • Learn a strategy that allows structs (and other types) to represent a public version of themselves for cases when we want to hide or transform internal representations
  • Learn to use embedded structs to represent nested data, while keeping the interface of our types simple
  • Learn to use http.Get to make external API requests, specifically to the Google Places API, with no code bloat
  • Learn to effectively implement enumerators in Go, even though they aren't really a language feature
  • Experience a real-world example of TDD
  • See how the math/rand package makes it easy to select an item from a slice at random
  • Learn an easy way to grab data from the URL parameters of the http.Request type

Project overview

Following Agile methodologies, let's write two user stories that describe the functionality of our project. User stories shouldn't be comprehensive documents describing the entire set of features of an application; rather small cards are perfect for not only describing what the user is trying to do, but why. Also, we should do this without trying to design the whole system up front or delve too deep into implementation details.

First we need a story about seeing the different journey types from which our users may select:

As a

traveler

I want

to see the different types of journeys I can get recommendations for

So that

I can decide what kind of evening to take my partner on

Secondly, we need a story about providing random recommendations for a selected journey type:

As a

traveler

I want

to see a random recommendation for my selected journey type

So that

I know where to go, and what the evening will entail

These two stories represent the two core capabilities that our API needs to provide, and actually ends up representing two endpoints.

In order to discover places around specified locations, we are going to make use of the Google Places API, which allows us to search for listings of businesses with given types, such as bar, café, or movie_theater. We will then use Go's math/rand package to pick from those places at random, building up a complete journey for our users.

Tip

The Google Places API supports many business types; see https://developers.google.com/places/documentation/supported_types for the complete list.

Project design specifics

In order to turn our stories into an interactive application, we are going to provide two JSON endpoints; one to deliver the kinds of journeys users will be able to select in the application, and another to actually generate the random recommendations for the selected journey type.

GET /journeys

The above call should return a list such as the following:

[
  {
    name: "Romantic",
    journey: "park|bar|movie_theater|restaurant|florist"
  },
  {
    name: "Shopping",
    journey: "department_store|clothing_store|jewelry_store"
  }
]

The name field is a human-readable label for the type of recommendations the app generates, and the journey field is a pipe-separated list of supported journey types. It is the journey value that we will pass, as a URL parameter, into our other endpoint, which generates the actual recommendations:

GET /recommendations?
     lat=1&lng=2&journey=bar|cafe&radius=10&cost=$...$$$$$

This endpoint is responsible for querying the Google Places API and generating the recommendations before returning an array of place objects. We will use the parameters in the URL to control the kind of query to make as per the HTTP specification. The lat and lng parameters, representing latitude and longitude, respectively, tell our API where in the world we want recommendations from, and the radius parameter represents the distance in meters around the point in which we are interested in. The cost value is a human-readable way of representing the price range for places that the API returns. It is made up of two values: a lower and upper range separated by three dots. The number of dollar characters represents the price level, with $ being the most affordable and $$$$$ being the most expensive. Using this pattern, a value of $...$$ would represent very low cost recommendations, where $$$$...$$$$$ would represent a pretty expensive experience.

Tip

Some programmers might insist the cost range is represented by numerical values, but since our API is going to be consumed by people, why not make things a little more interesting?

An example payload for this call might look something like this:

[
  {
    icon: "http://maps.gstatic.com/mapfiles/place_api/icons/cafe-71.png",
    lat: 51.519583, lng: -0.146251,
    vicinity: "63 New Cavendish St, London",
    name: "Asia House",
    photos: [{
      url: "https://maps.googleapis.com/maps/api/place/photo?maxwidth=400&photoreference=CnRnAAAAyLRN"
     }]
  }, ...
]

The array returned contains a place object representing a random recommendation for each segment in the journey, in the appropriate order. The preceding example is a café in London. The data fields are fairly self-explanatory; the lat and lng fields represent the location of the place (they're short for latitude and longitude), the name and vicinity fields tell us what and where the business is, and the photos array gives us a list of relevant photographs from Google's servers. The vicinity and icon fields will help us deliver a richer experience to our users.

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

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