Rest Web Service with App Engine and Webapp - python

I want to build a REST web service on app engine. Currently i have this:
from google.appengine.ext import webapp
from google.appengine.ext.webapp import util
class UsersHandler(webapp.RequestHandler):
def get(self, name):
self.response.out.write('Hello '+ name+'!')
def main():
util.run_wsgi_app(application)
#Map url like /rest/users/johnsmith
application = webapp.WSGIApplication([(r'/rest/users/(.*)',UsersHandler)]
debug=True)
if __name__ == '__main__':
main()
And i would like to retreive for example all my users when the path /rest/users is accessed. I Imagine I can do this by building another handler, but I want to know if is possible to do it inside of this handler.

Sure, you can -- change your handler's get method to
def get(self, name=None):
if name is None:
"""deal with the /rest/users case"""
else:
# deal with the /rest/users/(.*) case
self.response.out.write('Hello '+ name+'!')
and your application to
application = webapp.WSGIApplication([(r'/rest/users/(.*)', UsersHandler),
(r'/rest/users', UsersHandler)]
debug=True)
In other words, map your handler to all the URL patterns you want it to handle, and make sure the handler's get method can distinguish among them easily (typically via its arguments).

Related

Hierarchy of routes without overwriting handlers

I'm writing a flask application.
It makes sense to have multiple endpoints, like that:
prefix + '/'
prefix + '/<id>'
prefix + '/<id>/parameters'
prefix + '/<id>/parameters/<param>'
However, if I try to declare them all inside a blueprint, I'm getting a AssertionError: Handler is overwriting existing for endpoint _blueprintname_._firsthandlername_
Is there any way around this? I know it's been straight-forwardly done before, in technologies like .net core. Thanks in advance.
If you plan to add many parameters in your routes, you could have a look at this module for flask.
It helps you assigning routes to resources.
You could build up a set of routes as follows:
from flask import Flask, request
from flask_restful import Resource, Api, reqparse
app = Flask(__name__)
api = Api(app)
class Some(Resource):
def get(self, id=None, params=None):
"""
In order to allow empty params for routes, the named arguments
must be initialized
"""
if id and params:
return {'message':'this is get with id and params'}
if id:
return {'message':'this is get with id'}
return {'message':'this is get'}
def post():
"""
One can use here reqparse module to validate post params
"""
return {'message':'this is post'}
# Add the resource to the service
api.add_resource(Some, '/', '/<string:id>','/<string:id>/<string:params>', ...)
# start the service
if __name__ == '__main__':
app.run(debug=True)

flask binding resource to an endpoint

as i know so far there are two ways of binding resouces to an endpoint using flask framework,
the first one is using the #app.route decorator, like this:
from flask import Flask
app = Flask(__name__)
#app.route('/')
def hello_world():
return 'Hello, World!'
if __name__ == '__main__':
app.run()
the second way is to create a class that inherite from Resources in flask-restfull, this class contains the http methods as functions, we bind it to an endpoint using add_resource method, as follow:
from flask import Flask
from flask_restful import Resource, Api
app = Flask(__name__)
api = Api(app)
class HelloWorld(Resource):
def get(self):
return 'Hello, World!'
api.add_resource(HelloWorld, '/')
if __name__ == '__main__':
app.run()
as I understand this two different syntaxes do the same thing, what I dont understand is what is the difference between the two ? or is one designed for a specific type of applications and the other to another type of applications ?
Flask-RESTful is an extension of Flask, which itself is built on many of the excellent utilities provided by Werkzeug.
from flask import Flask
app = Flask(__name__)
#app.route('/foo')
def say_foo():
return 'foo'
#app.route('/bar')
def say_bar():
return 'bar'
if __name__ == '__main__':
app.run()
One of the biggest ideas behind REST is using HTTP to interact with resources. The problem with this code is our resource is split up over multiple methods. There's no encapsulation. While the API itself incorporates basic elements of REST, the code completely fails to capture these ideas. This is bad! There's no reason our internal code shouldn't match the external appearance of our API.
Using Flask-RESTful
from flask import Flask
from flask_restful import Resource, Api
app = Flask(__name__)
api = Api(app)
class Foo(Resource):
def get(self):
return 'foo'
class Bar(Resource)
def get(self):
return 'bar'
# As you might have guessed, these two lines add a given resource to our API at the
# specified route. We no longer need to enumerate what methods a route supports,
# since Flask-RESTful resolves this information by inspecting what methods you've
# defined on your resource object.
api.add_resource(Foo, '/foo')
api.add_resource(Bar, '/bar')
if __name__ == '__main__':
app.run()
We have classes now! This is a huge deal. Our routes now map directly to objects. Even better, the methods on a given class are exactly the same as their HTTP counterparts. We no longer have to deal with naming methods on our routes like say_foo, since there's a 1 to 1 mapping between HTTP methods and methods on our classes.
read more: https://dougblack.io/words/flask-restful-101.html

URL of a wsgi_app Flask app using DispatcherMiddleware

I have two application factory functions - one creates the "customer" app, and the other creates the "admin" backend app. Both of the factory functions essentially do what is described here - create a flask app and register some extensions to it and then add some blueprints(with a url_prefix). I glue the two apps together via the create_combined_app() from below. It is the return value of that function which I register with my Flask-Script's Manager.
def create_combined_app(config_name):
customer_app = create_customer_app(config_name)
admin_app = create_admin_app(config_name)
from werkzeug.wsgi import DispatcherMiddleware
customer_app.wsgi_app = DispatcherMiddleware(customer_app.wsgi_app, {
'/admin': admin_app
})
return customer_app
And then this is how I run it.
def make_me_an_app():
return create_combined_app(config)
manager = Manager(make_me_an_app)
...
if __name__ == '__main__':
manager.run()
I want to do some testing which involves getting all GET routes of my app and making sure they load. I followed the example from here, but I only see the urls of the customer app, and none of the urls from the admin backend.
#main.route("/site-map")
def site_map():
from flask import current_app, jsonify
links = []
app = current_app
for rule in app.url_map.iter_rules():
if "GET" in rule.methods and has_no_empty_params(rule):
url = url_for(rule.endpoint, **(rule.defaults or {}))
links.append((url, rule.endpoint))
return jsonify(links)
The admin backend works when I try to access it from the browser - it all works nicely, except that I don't see the admin's urls when I call /site-map.
Thanks! :)
I think DispatcherMiddleware create separate apps. Which mean you created customer_app and admin_app. Those 2 live as standalone. They don't know each others, therefor current_app is just the show customer_app.
Here is the describe from Flask http://flask.pocoo.org/docs/0.12/patterns/appdispatch/

Access Flask config outside of application factory

I'm currently using the Flask Application Factory pattern with Blueprints. The issue that I'm having is how do I access the app.config object outside of the application factory?
I don't need all the configuration options from the Flask app. I just need 6 keys. So the current way I do this is when the create_app(application factory) is called, I basically create a global_config dictionary object and I just set the global_config dictionary to have the 6 keys that I need.
Then, the other modules that need those configuration options, they just import global_config dictionary.
I'm thinking, there has to be a better way to do this right?
So, on to the code
My current init.py file:
def set_global_config(app_config):
global_config['CUPS_SAFETY'] = app_config['CUPS_SAFETY']
global_config['CUPS_SERVERS'] = app_config['CUPS_SERVERS']
global_config['API_SAFE_MODE'] = app_config['API_SAFE_MODE']
global_config['XSS_SAFETY'] = app_config['XSS_SAFETY']
global_config['ALLOWED_HOSTS'] = app_config['ALLOWED_HOSTS']
global_config['SQLALCHEMY_DATABASE_URI'] = app_config['SQLALCHEMY_DATABASE_URI']
def create_app(config_file):
app = Flask(__name__, instance_relative_config=True)
try:
app.config.from_pyfile(config_file)
except IOError:
app.config.from_pyfile('default.py')
cel.conf.update(app.config)
set_global_config(app.config)
else:
cel.conf.update(app.config)
set_global_config(app.config)
CORS(app, resources=r'/*')
Compress(app)
# Initialize app with SQLAlchemy
db.init_app(app)
with app.app_context():
db.Model.metadata.reflect(db.engine)
db.create_all()
from authenication.auth import auth
from club.view import club
from tms.view import tms
from reports.view import reports
from conveyor.view import conveyor
# Register blueprints
app.register_blueprint(auth)
app.register_blueprint(club)
app.register_blueprint(tms)
app.register_blueprint(reports)
app.register_blueprint(conveyor)
return app
An example of a module that needs access to those global_config options:
from package import global_config as config
club = Blueprint('club', __name__)
#club.route('/get_printers', methods=['GET', 'POST'])
def getListOfPrinters():
dict = {}
for eachPrinter in config['CUPS_SERVERS']:
dict[eachPrinter] = {
'code': eachPrinter,
'name': eachPrinter
}
outDict = {'printers': dict, 'success': True}
return jsonify(outDict)
There has to be a better way then passing a global dictionary around the application correct?
There is no need to use global names here, that defeats the purpose of using an app factory in the first place.
Within views, such as in your example, current_app is bound to the app handling the current app/request context.
from flask import current_app
#bp.route('/')
def example():
servers = current_app.config['CUPS_SERVERS']
...
If you need access to the app while setting up a blueprint, the record decorator marks functions that are called with the state the blueprint is being registered with.
#bp.record
def setup(state):
servers = state.app.config['CUPS_SERVERS']
...

Pyramid decorator chaining

In my pyramid application I am trying to implement authorization by decorating the view function.
When I use the config.scan() function none of the views are added, however if I explicitly add them using config.add_view() everything works fine.
I have two file one which defines all the view functions (views.py)
from pyramid.view import view_config
from pyramid.response import Response
from functools import wraps
def authorized(func): #decorator difnition
#wraps(func)
def new_func(request):
if(request.cookies.get('user')): # authorization
return func(request)
else:
return Response('not authirised')
return new_func
#view_config(route_name='hello') # view function being decorated
#authorized
def privileged_action(request):
return Response('Hello %(name)s!' % request.matchdict)
And another file to create the server (serve.py) which imports views.py
from wsgiref.simple_server import make_server
from pyramid.config import Configurator
from views import privileged_action
if __name__ == '__main__':
config = Configurator()
config.add_route('hello', '/hello/{name}')
# config.add_view(privileged_action, route_name='hello') # This works
config.scan() # This doesn't work
app = config.make_wsgi_app()
server = make_server('0.0.0.0', 8080, app)
server.serve_forever()
This gives 404 not found error if I access using 'http://localhost:8080/hello/a'
Why does this not work?
Is there any way to make this work?
Your code with the decorators looks fine.
The documentation for Configurator.scan() states for its first argument:
The package argument should be a Python package or module object (or a dotted Python name which refers to such a package or module). If package is None, the package of the caller is used.
So make sure you are doingconfig.scan(views), to get your web app dynamically adding your views.

Categories

Resources