Francesco Pongetti
Aug 7, 2017 · 3 min read

You can use Google Cloud Storage in your Google App Engine applications to upload, store and serve images.

Let’s see how to implement this in a simple AngularJs application.

You will need the following tools:

  • ng-file-upload, a very interesting AngularJS directive to upload files
  • Google Cloud Storage (with Blobstore API) to host and serve the images from the Google Cloud
  • some python code to glue everything together

The steps are pretty easy as is the code.


Activate the Google Cloud Storage and install the client library

Activate Google Cloud Storage for your project by selecting the option in the Google Developers Console.
You can have a look at this introduction for a list of steps.
At the end of the process you will have a bucket for your project. The bucket is a sort of virtual folder in GCS and is the place where the uploaded images will be stored and read.
You also need to install the Python client library in your project, the library contains the module that you will import in your backend code to work with GCS.


Create the upload page

The upload page is using the ng-file-upload directive so install the directive for your project, following the instructions here.

In my code, I created a HTML page to upload the images and then I used the page in an iframe embedded in a Bootstrap modal. You can checkout the code of my upload page in my Github here. The page includes a simple select button to select the image to upload and some extra-code to show the upload progress and result.

The AngularJS controller (UploadCtrl) for the page is in controller.js. The controller implements a callback function for the select button using the Upload object exported by ng-file-upload.
What is important here is to specify the URL that will process the uploaded files — in my case ‘api/image/upload’ — this should contain the backend code that responds to the POST requests containing the image data, and saves them in the Google Cloud Storage.


Create the backend code for storing the images

Now we create the python code for the backend that receives the image uploaded and stores them in the Google Cloud Storage.

Change your app.yaml to create an endpoint for the upload page created in step 2. In my code this is ‘api/image/upload’ and as we saw, this is the URL used by the Upload function in the controller.

Then, define a request handler for POST request to that address (I use webapp2 as web application, but the same concepts apply also to Django or Flask):

import api.cloudstorage as gcs
import webapp2
def _create_file(file_type, filename, data):
write_retry_params = gcs.RetryParams(backoff_factor=1.1)
gcs_file = gcs.open(filename, 'w',
content_type=file_type,
options={
'x-goog-meta-foo': 'foo',
'x-goog-meta-bar': 'bar'},
retry_params=write_retry_params)
gcs_file.write(data)
gcs_file.close()
class ImageUploadHandler(webapp2.RequestHandler):
"""Handles image upload requests."""
def post(self): # pylint: disable=C0111
file_data = self.request.POST['file']
_create_file(file_data.type, config.BUCKET + '/' + file_data.filename, file_data.value)
self.response.write('File uploaded successfully.')
ROUTES = [webapp2.Route(r'/api/image/upload', handler=ImageUploadHandler)]
APP = webapp2.WSGIApplication(routes=ROUTES, debug=True)

Serving the images

The uploaded images are stored in Google Cloud Storage, the backend should provide a way to serve this images to the browser. This can be easily done using the Images and Blobstore APIs.

Blobstore API can access entities stored in GCS using create_gs_key() method that generate a blob key out of a GCS filename (remember to always include the bucket name in the filename!).

Images API can then directly open a blobstore object and create a static serving URL for the images. When the Blobstore API is used together with the Images API, you get a powerful way to serve images, because you can serve images directly from Cloud Storage, bypassing the App Engine app, which saves on instance hour costs!

Here the code that you can integrate in the same backend code of the previous step, as a new handler:

import api.cloudstorage as gcs
import webapp2
from google.appengine.api import images
from google.appengine.ext import blobstore
class ImageReadHandler(webapp2.RequestHandler):
"""Handles image read requests."""
def get(self, image_name): # pylint: disable=C0111
if not image_name:
self.error(404)
return
blob_key = blobstore.create_gs_key('/gs' + config.BUCKET + '/' + image_name)
img_url = images.get_serving_url(blob_key=blob_key)
self.redirect(img_url)
ROUTES = [webapp2.Route(r'/api/image/upload', handler=ImageUploadHandler),
webapp2.Route(r'/api/image/read/<image_name:.+>', handler=ImageReadHandler)
]
APP = webapp2.WSGIApplication(routes=ROUTES, debug=True)

The code accepts URLs in the format api/read/images.png and redirects to the correct static serving URL in the Google Cloud Storage.


Conclusion

That’s all, as usually you can check the complete code in my Github. Of course, the code should be improved to handle input errors and many other things (e.g. spaces in image filename), but I will leave it for the moment.

Feel free to share this post and use the comment form below if you need help.

Life ho(p)ping

Interesting code and life hacks (sometimes rants too)

Francesco Pongetti

Written by

TPM@Google, Software Engineer, MBA and some other things too

Life ho(p)ping

Interesting code and life hacks (sometimes rants too)

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade