How to use Google Places API with Caching ( complete Golang/React Source )
Tags: go, javascript, react, webdev
Published: 2021-01-30 08:36:42

---
title: How to use Google Places API with Caching ( complete Golang/React Source )
published: true
description: A working example of a cached service for Google Places API with a React Frontend using debounced.
tags: go,javascript,react, webdev
cover_image: https://dev-to-uploads.s3.amazonaws.com/i/isw6hjh556onqiyqdtww.png
---
This day's I started with a new side-project named [ProdutoMania](https://produtomania.com)

This project's main feature is to find products from my home country at the place I'm currently staying. 
So I need a selector of location and to use Google Place/Maps API is on the hand. 

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/dmyxfsk83b9z4d7s7cf5.png)

Now, this API is paid as soon usage is getting above a certain amount.

This can be risky if you do put the queries as autocomplete/typehead directly fetching results on the client-side. So I decided to call backend API with a search term and the handler on the server-side take control of the usage of the API.

This opens the possibility to do throttling (not part of this post) and caching. Caching makes much sense, as locations do not change every minute, hour, not even days. 
There is a max period of time allowed by Google for caching, at the time of writing this post it was 30 days.

To build the API I use:
- Go with Chi Router (could also be done without, just using net/http standard package)
- Google's official Go Client for Google Maps
- Caching Middleware [victorspringer/http-cache](https://github.com/victorspringer/http-cache)

Victor Springer's Caching Middleware is a perfect fit to cache RESTful API's. It supports memory, Redis, DynamoDB, and other storage for the cache. 

here the config part of the story:

```Go
// Cache Middleware Config
memcached, err := memory.NewAdapter(
	memory.AdapterWithAlgorithm(memory.LRU),
	memory.AdapterWithCapacity(1000000),
)
if err != nil {
	fmt.Println(err.Error())
	os.Exit(1)
}
cacheClient, err := cache.NewClient(
	cache.ClientWithAdapter(memcached),
	cache.ClientWithTTL(24 * time.Hour),
	cache.ClientWithRefreshKey("opn"),
)
```
Then I define the handler and routes applying the middleware:

```Go
// Cache Google Place API calls
hLocation := http.HandlerFunc(handler.GetLocations)

r.Route("/", func(r chi.Router) {

// location autocomplete
r.With().Get("/{term}", CacheClient.Middleware(hLocation).ServeHTTP)
})
 
```
On Frontend Side I use:
- React with Webpack, using my own [React 17/Webpack/ Boilerplate](https://github.com/altafino/react-webpack-5-tailwind-2)
- Downshift as a flexible Autocomplete/Dropdown Component
- Debounced-fn Package 

The Debouncing is important for the typeahead function to not call API on every onChange triggered by a Char. It also does not make sense to send just one char to API.

here the useLocation Hook/Service part of code:

```JavaScript
export function useLocation() {
  const [{ isLoading, error, data }, dispatch] = useReducer(
    reducer,
    initialState
  )
  const fetchLocationResults = debounce(
    async (searchString) => {
      if (searchString.length > 2) {
        const locationUrl = `http://localhost:9090/${searchString}`
        dispatch({ type: actionTypes.FETCH_REQUEST })
        try {
          const response = await axios.get(locationUrl)
          dispatch({
            type: actionTypes.FETCH_SUCCESS,
            results: response.data,
          })
        } catch (error) {
          dispatch({ type: actionTypes.FETCH_FAILURE, error })
        }
      }
    },
    { wait: 400 }
  )
  return { error, isLoading, data, fetchLocationResults }

```

You can get the full source to check the details:
[https://github.com/stefanwuthrich/cached-google-places](https://github.com/stefanwuthrich/cached-google-places)

Have fun (without high invoice from Google :-) )