Google App Engine went GA for Go 1.12 runtimes and there are some key changes with it. The old appengine packages are not expected to work and instead everyone is expected to migrate to the Goolge Cloud client library. For long time existing apps this may be a pain but it’s in the right direction to make the code as standard as possible for better portability both within and outside GCP. Below is an example of getting rid of a custom way of integrating as a result of moving to a standard way of developing your app.
The Stripe Go library on their GitHub documentation explicitly have a section on using it within Google App Engine. It went along the lines of “If you’re running the client in a Google AppEngine environment, you’ll need to create a per-request Stripe client since the http.DefaultClient
is not available. Here’s a sample handler:”
This is because, up until Go 1.9, the only way to do external http calls from the server were using the urlfetch package. This required passing a context to create the http client. And the context had to be an app engine context which was only available as part of a http request. But with Go 1.12, there is no app engine context, there is no urlfetch (Go 1.11 allowed both ways). Instead, you can use the standard context package and create a Background context and use http.Client for making http requests. As a result of all of this, it is now possible to create the Stripe Client API object only once and use it across many requests. Given the Client.API object is very heavy to initialize (it creates lots and lots of objects one for each type of API even though you only use a handful), creating it once and reusing it with each request is much better. Given http.Client is inherently thread-safe, everything should work just fine just as expected if the app was being developed in a standard way.
So while moving from legacy code is a pain, I am all for the changes that make the app be a standard go app with built-in web server.
Lastly, I almost decided to create the client API object at the time of initializing the instance but decided against it as the best practice is to do lazy loading of less frequently used stuff. So, instead I resorted to the sync.Once pattern that would initialize the API object on the first usage of Stripe call from the app for the running instance.