serving blobstore image through app-engine endpoints api
Asked Answered
W

1

4

I am building an app-engine endpoint api that takes picture from a user (android app) and saves it to blobstore programmatically. Then I save the blob_key in my datastore. The code goes like this:

  • First I received the image through my @endpoint.method as a messages.BytesField:

    image_data = messages.BytesField(1, required=True)

Then I save to the blobstore like this:

from google.appengine.api import files

def save_image(data):
  # Create the file
  file_name = files.blobstore.create(mime_type='image/png')

  # Open the file and write to it
  with files.open(file_name, 'a') as f:
    f.write('data')

  # Finalize the file. Do this before attempting to read it.
  files.finalize(file_name)

  # Get the file's blob key
  blob_key = files.blobstore.get_blob_key(file_name)
  return blob_key # which is then saved to datastore

Now I want to serve the image back. I don't see how to fit the following code into my endpoints api:

from google.appengine.ext import blobstore
from google.appengine.ext.webapp import blobstore_handlers
class ServeHandler(blobstore_handlers.BlobstoreDownloadHandler):
  def get(self, resource):
    resource = str(urllib.unquote(resource))
    blob_info = blobstore.BlobInfo.get(resource)
    self.send_blob(blob_info)

In the end I imagine a serving procedure like this:

  • in @endpoints.method:

  • get blob_key from datastore

  • obtain image with blob_key

  • add image to StuffResponseMessage

  • send StuffResponseMessage to front-end (android app)

My approach is because I want to protect the privacy of my users. Any thoughts on how to do this well? My code snippets are generally from the google developer tutorial.


EDIT:

I don't see how I would pass the blob_key from the datastore to the following method to retrieve the image:

from google.appengine.ext import blobstore
from google.appengine.ext.webapp import blobstore_handlers
class ServeHandler(blobstore_handlers.BlobstoreDownloadHandler):
  def get(self, resource):
    resource = str(urllib.unquote(resource))
    blob_info = blobstore.BlobInfo.get(resource)
    self.send_blob(blob_info)

What's inside resource, anyway?

Wasserman answered 22/3, 2013 at 4:31 Comment(2)
You don't need from __future__ import with_statement if you're using Python 2.7.Anticatalyst
ah. Thanks, @bossylobster. I took it out.Wasserman
M
2

I believe resource is the BlobKey object of what you want to serve, as a string, retreived from url path. If you look at the source of google.appengine.ext.blobstore.BlobInfo the get method uses a function __normalize_and_convert_keys that takes an argument of BlobKey object OR string.

If the blob is an image, maybe it's best to send the serving url instead to your Android app, in StuffResponseMessage maybe in your case. From google's Serving a Blob doc:

If you are serving images, a more efficient and potentially less-expensive method is to use get_serving_url using the App Engine Images API rather than send_blob. The get_serving_url function lets you serve the image directly, without having to go through your App Engine instances.

So after you save the image, take the returned blob_key (as per your method save_image(data) above) to make a serving url, then in your Android app get the image from the returned url. That of course means exposing the image url without privacy protection.

If you want to do it with protection, use BlobReader class to read the blob with file like interface. You can't use the method/class from Serving a Blob example because you do it in a remote.Service subclass rather than a handler.

Maller answered 23/3, 2013 at 19:17 Comment(2)
To send a blob from endpoint (server) to android do I need to encode it? (Base64) or is that already handled?Wasserman
@Wasserman given the serving url, you can handle it like any other external image. See this answer Android image fetchingMaller

© 2022 - 2024 — McMap. All rights reserved.