上个月,我开始了一个名为ProdutoMania的新项目。

该项目的主要功能是在我当前居住的地方查找某人的祖国的产品。
因此,我需要一个位置选择器,并且要使用Google Maps / Place API。

替代文字
只要使用量超过一定金额,便会向该API付费。

如果您确实将查询作为类型标头直接在客户端获取结果,则这可能会带来很大的风险。因此,我决定使用搜索字词来调用后端API,服务器端的处理程序将控制该API的使用。

这提供了进行节流(不属于本文的一部分)和缓存的可能性。缓存非常有意义,因为位置不会每分钟,每小时甚至几天都不会改变。
Google最多允许缓存时间,撰写本文时为30天。

要构建我使用的API,请执行以下操作:

与Chi Router搭配使用(也可以不使用net / http标准程序包而完成此操作)
Google的Google Maps官方Go Client
缓存中间件victorspringer / http-cache
Victor Springer的缓存中间件非常适合缓存RESTful API。它支持内存,Redis,DynamoDB和其他用于缓存的存储。

这里是故事的配置部分:

// 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"),
)
然后,我定义处理程序并应用中间件进行路由:

// 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)
})

在前端,我使用:

使用我自己的React 17 / Webpack / Boilerplate与Webpack 5配合使用React 17
降档作为灵活的自动完成/下拉组件
去弹-fn程序包
对于typeahead函数,不要在Char触发的每个onChange上都不调用API,去抖动非常重要。仅向API发送一个字符也是没有意义的。

这里的useLocation Hook / Service部分代码:

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 }

您可以获取完整的源代码来检查详细信息:https :
//github.com/stefanwuthrich/cached-google-places