views:

62

answers:

2

Hi,

I'm a Google App Engine newbie and would be grateful for any help. I have an iPhone app which sources data from an sqlite db stored localling on the device.

I'd like to set up a Google App Engine web service which my iPhone client will talk to and check if there is a newer version of the sqlite database it needs to download.

So iPhone client hits the web service with some kind of version number/timestamp and if there is a newer file, the App Engine will notify the client and the client will then request the new database to download which the App Engine will serve.

Is it possible to set up a web service in Google App Engine to do this? Could anyone point me to any sample code / tutorials please?

Many Thanks

A: 

This is entirely possible with App Engine, given that you're making HTTP requests.

The best code and tutorials, in my opinion, is the official Google App Engine docs. Everything you'll need is there.

Ink-Jet
Thanks, there's a lot of content there which I'll read. Is there anything more specific/targeted to my question in the Google Docs or anywhere else? I've googled and googled but cannot find anything obvious.
Tofrizer
Without knowing more about your specific problem, I probably couldn't help. Essentially though, you'll only have to write a HTTP request to check if a new database is available, and then another to download it.
Ink-Jet
Ok having done some reading looks like quickest way would be to have a python main script which, once called, 1) returns a HTTP response with a date timestamp of the sqlite file. Then the iPhone client would 2) download the sqlite/binary file if it is stale. For 1), is there a file system in GAE or do I have to upload to the datastore and then use an API to check the date timestamp? I guess same question applies to 2) -- if no file system and I have to use datastore, presumably there is an API to request the binary file download?
Tofrizer
+5  A: 

What I would do is keep the SQLite DB as a gzipped blob in the datastore. Use the SHA1 hash as an etag. The client does a GET request with the etag header, and the server either responds with a 304 Not Modified or a 200 and the blob contents in the response body.

There is an API specifically for blobs, called the Blobstore API, but to use it you need to have billing enabled. Without billing enabled you can still easily serve blobs, but you'll be limited to 10MB per request, response, and entity size. If your zipped database is larger than that, you could conceivably break up the download into multiple requests, since you control both the client and server code. A custom blob handler that just uses the datastore might look like this:

class MyModel(db.Model):
  body = db.BlobProperty()

class MyBlobHandler(webapp.RequestHandler):
  def get(self):
    entity_key = self.request.get("entity_key")
    entity = MyModel.get(entity_key)
    self.response.headers['Content-type'] = 'what/ever'
    self.response.out.write(entity.body)
  def put(self):
    entity = MyModel(body=db.Blob(self.request.body))
    entity.put()
    self.response.out.write(entity.key())
Drew Sears
Drew - thanks, this is v helpful, let me check this out in more detail. My zipped db is about 1 MB so I can try non-billing (but am happy to go with billing enabled if it means getting this to work). Also, interesting that I can save myself a trip to the server with a 304 or 200 response. I'll give this a go and come back with an update.
Tofrizer
Drew - I'm pretty new to this server stuff but thanks to your answer I've managed to implement a GAE where I can 1) upload my zip blob to the datastore, 2) download the zip provided i know the entity key (e.g. <url>?entity_key=XXX). What I need for my final solution is for client to hit the server and know to be served an updated blob/zip to download (relative to the blob/zip already in the client). Every time I pass in the entity key, I get served the same original blob. I'm obviously doing something wrong, how can I take advantage of the 304 / 200 return?Thanks
Tofrizer
The 304 / 200 logic was not included in my original example. Basically what you'll need to do is attach a unique identifier of your choosing to each version of the database, like a hash or a timestamp or a version number. Send the identifier to the client in the response headers. When the client requests the file again, they should pass the identifier back in the request headers. When you receive the request, check first to see if their last known version is also the most current version, and if so, return a HTTP 304 instead of serving the blob again.
Drew Sears
Yep makes sense - thanks Drew!
Tofrizer