I am trying to write a API that has a "boat" resource and I want to build off of that url with an ID and another resource.
localhost:8080/boat/absk12712480/arrival
I originally had:
app = webapp2.WSGIApplication([
...
('/boat/(.*)/arrival', ArrivalHandler),
...
], debug=True)
But that kept grabbing the "/arrival" as part of the ID. So I tried:
('/boat/(.*?(?=\/)/arrival', ArrivalHandler)
('/boat/(.*?(?=\/arrival)/arrival', ArrivalHandler)
Is what I am trying to do possible and if so how?
In ('/boat/(.*)/arrival', ArrivalHandler) the regex is too greedy, and doesn't match the webapp2 URI format. If the ID is always just lower-case ascii and digits, you could use:
('/boat/<:[a-z0-9]+>/arrival', ArrivalHandler)
ought to work, or
('/boat/<id:[a-z0-9]+>/arrival', ArrivalHandler)
if you want a named parameter.
Related
Is it possible with Flask Restplus to create a model for a multipart/form-data request so that I can use it to validate the input with #api.expect?
I have this complex data structure for which I've created a api.namespace().model that has to be received together with a file. However when I tried to document the endpoint I noticed that this doesn't seem to be supported by Flask Restplus.
I've tried to find something along the lines of
parser = ns.parser()
parser.add_argument("jsonModel", type=Model, location="form")
parser.add_argument("file", type=FileStorage, location="files")
and
formModel = ns.model("myForm", {"jsonModel": fields.Nested(myModel), "file": fields.File})
But neither methods seem to support this kind of behavior.
I am currently work on a web app using webapp2, that deals with restaurant in several cities. Some of the url would look like
1. www.example.com/newyork
2. www.example.com/newyork/fastfood
3. www.example.com/newyork/fastfood/tacobell
To handle the first url, I used the following
CITY_RE = r'(/(?:[a-zA-Z0-9]+/?)*)'
app = webapp2.WSGIApplication([(CITY_RE, CityHandler)], debug = True)
How would I handle the url with multiple parameters such as 2 and 3.
I have a similar approach to match urls like /<country>/<region>/<city>/<category>e.g. /usa/california/losangeles/restaurants where I use this regex:
app = webapp2.WSGIApplication([('/([^/]+)/?([^/]*)/?([^/]*)', RegionSearch)], config=settings.w2config, debug=True)
The declare the relevant parameters in the handler class.
class RegionSearch(SearchBaseHandler):
"""Handles regional search requests."""
def get(
self,
region=None,
city=None,
category=None,
subcategory='For sale',
PAGESIZE=50, # items on page
limit=60, # number of days
year=2012,
month=1,
day=1,
next_page=None,
):
I think that you could even do it this way
webapp2.Route('/passwdresetcomplete/<city>/<category>/<name>', handler=RegionSearch, name='regionsearch')
I recently started using bottle and GAE blobstore and while I can upload the files to the blobstore I cannot seem to find a way to download them from the store.
I followed the examples from the documentation but was only successful on the uploading part. I cannot integrate the example in my app since I'm using a different framework from webapp/2.
How would I go about creating an upload handler and download handler so that I can get the key of the uploaded blob and store it in my data model and use it later in the download handler?
I tried using the BlobInfo.all() to create a query the blobstore but I'm not able to get the key name field value of the entity.
This is my first interaction with the blobstore so I wouldn't mind advice on a better approach to the problem.
For serving a blob I would recommend you to look at the source code of the BlobstoreDownloadHandler. It should be easy to port it to bottle, since there's nothing very specific about the framework.
Here is an example on how to use BlobInfo.all():
for info in blobstore.BlobInfo.all():
self.response.out.write('Name:%s Key: %s Size:%s Creation:%s ContentType:%s<br>' % (info.filename, info.key(), info.size, info.creation, info.content_type))
for downloads you only really need to generate a response that includes the header "X-AppEngine-BlobKey:[your blob_key]" along with everything else you need like a Content-Disposition header if desired. or if it's an image you should probably just use the high performance image serving api, generate a url and redirect to it.... done
for uploads, besides writing a handler for appengine to call once the upload is safely in blobstore (that's in the docs)
You need a way to find the blob info in the incoming request. I have no idea what the request looks like in bottle. The Blobstoreuploadhandler has a get_uploads method and there's really no reason it needs to be an instance method as far as I can tell. So here's an example generic implementation of it that expects a webob request. For bottle you would need to write something similar that is compatible with bottles request object.
def get_uploads(request, field_name=None):
"""Get uploads for this request.
Args:
field_name: Only select uploads that were sent as a specific field.
populate_post: Add the non blob fields to request.POST
Returns:
A list of BlobInfo records corresponding to each upload.
Empty list if there are no blob-info records for field_name.
stolen from the SDK since they only provide a way to get to this
crap through their crappy webapp framework
"""
if not getattr(request, "__uploads", None):
request.__uploads = {}
for key, value in request.params.items():
if isinstance(value, cgi.FieldStorage):
if 'blob-key' in value.type_options:
request.__uploads.setdefault(key, []).append(
blobstore.parse_blob_info(value))
if field_name:
try:
return list(request.__uploads[field_name])
except KeyError:
return []
else:
results = []
for uploads in request.__uploads.itervalues():
results += uploads
return results
For anyone looking for this answer in future, to do this you need bottle (d'oh!) and defnull's multipart module.
Since creating upload URLs is generally simple enough and as per GAE docs, I'll just cover the upload handler.
from bottle import request
from multipart import parse_options_header
from google.appengine.ext.blobstore import BlobInfo
def get_blob_info(field_name):
try:
field = request.files[field_name]
except KeyError:
# Maybe form isn't multipart or file wasn't uploaded, or some such error
return None
blob_data = parse_options_header(field.content_type)[1]
try:
return BlobInfo.get(blob_data['blob-key'])
except KeyError:
# Malformed request? Wrong field name?
return None
Sorry if there are any errors in the code, it's off the top of my head.
I'm using webapp with Google App Engine.
I recently added a call to request.get('variable_name'). This worked fine, but completely changed the contents of request.body.
Upon closer examination, it looks like if I do not make a call to request.get(), then request.body yields text without any url formatting. But after a call the request.get(), request.body now contains text that includes URL formatting (a lot of '%' signs, etc...).
Am I using webapp wrong? should I not be mixing and matching these two methods for information retrieval?
Here is some sample code:
class profiles_resource(webapp.RequestHandler):
def post(self):
# Value of request.body in debugger: 'str: {"query":"SELECT..."
token = self.request.get('token')
# Value of request.body in debugger: '%7B%22query%22%3A%22SELECT..."
request.get looks for request parameters in both the query string and the body of the request, assuming the body is formencoded. If you intend to read the body directly, do not use self.request.get or self.request.POST.
I'd like to use GAE to allow a few users to upload files and later retrieve them. Files will be relatively small (a few hundred KB), so just storing stuff as a blob should work. I haven't been able to find any examples of something like this. There are a few image uploading examples out there but I'd like to be able to store word documents, pdfs, tiffs, etc. Any ideas/pointers/links? Thanks!
The same logic used for image uploads apply for other archive types. To make the file downloadable, you add a Content-Disposition header so the user is prompted to download it. A webapp simple example:
class DownloadHandler(webapp.RequestHandler):
def get(self, file_id):
# Files is a model.
f = Files.get_by_id(file_id)
if not f:
return self.error(404)
# Set headers to prompt for download.
headers = self.response.headers
headers['Content-Type'] = f.content_type or 'application/octet-stream'
headers['Content-Disposition'] = 'attachment; filename="%s"' % f.filename
# Add the file contents to the response.
self.response.out.write(f.contents)
(untested code, but you get the idea :)
It sounds like you want to use the Blobstore API.
You don't mention if you are using Python or Java so here are links to both.
I use blobstore API that admits any file upload/download up to 50 MB.