# Tutorials Simple application without database usage ----------------------------------------- This tutorial goes through a test application line-by-line. This application tries to register the following URLs 1. Accepts json input data, and returns an empty response if successfull 2. Returns a html page 3. Returns a json data 4. Accepts some parameters and returns an empty response ### Setup Apart from your application source code, you will have to add certain files for packaging. For this example app, we shall have the following directory structure. / PKG-INFO setup.py resources/ create_form.html items_access.html example_app/ __init__.py app.py - [`/PKG-INFO`][PKG-INFO] file is the file in which you define some variables about your app which will be used by the packager. - `/setup.py` file is the file the you traditionally write for any python module. You can learn about this file from [here](https://docs.python.org/2.7/install/index.html). It basically tells the packager about the dependent python packages and the list of modules and other resources needed to be installed - `/resources` folder has the static files. In this example we use two html pages. The setup.py must have instructions to install the static files. We will have to note the directory in which the static resource are installed in the [`PKG-INFO`][PKG-INFO] file. like ``` statics-url: statics-path: ``` - Rest of the files contains the app's source code. This example app has all the code in a single file `example_app/app.py`. ### Entry point The application entry accepts one parameter which is the [state](entry.md) of the application. def entry(state): if state != STATE_VALIDATION: # do intializations here. pass # entry point should return a list of callbacks. Since this is a # simple application, we just return a callback for routes. return {CALLBACK_ROUTES: routes_cb} The above entry point does not have anything to initialize or migrate. The list of callbacks should be returned no matter in what state the application is started. This entry-point will have to updated in the [PKG-INFO] file like entry-point: example_app.app:entry ### Route callback [Routes](routes.md) callback accepts a mapper object on which the URLs can be registered. In this example we will register the URLs with the help of a submapper as we are passing the same `handler` for all the URLs. def routes_cb(mapper): # We have the same handler for all the below urls. If not for submapper, # we will have to define 'handler' in each of the mapper.connect(). # The mapper object has to be passed to the BaseHandler.__init__ with mapper.submapper(handler=TestAppHandler(mapper)) as m: # Below url sends an index page. The static prefix will be # used inside the html page to access the static resources. # no permissions attribute means it can be accessed by anyone m.connect("/aalam/testapp/", action="send_homepage", conditions={"method": ['GET']}) # Below url accepts input data, and it can be in xml/json format. # It allows only valid users with "Items/create" permission m.connect("/aalam/testapp/items", action="create_item", deserializer="create_item_deserializer", permissions=Permissions.all(["Items/create"]).deny_anon(), conditions={"method": ['PUT']}) # Below URL will send a json output. We do not have a serializer # for this, because the framework will by default use the json # serializer for response data. # This api is denied for anonymous requests. m.connect("/aalam/testapp/item/{item_name}", action="get_item", permissions=Permissions().deny_anon(), serializer="get_item_serializer", conditions={"method": ['GET']}) # Below URL is used to update a setting, but will permit a user # to update the setting that is created by the same user. m.connect("/aalam/testapp/item/{item_name}", action="update_item", permissions=Permissions().deny_anon(), conditions={"method": ['POST']}) In the above code, `TestAppHandler` is the class which will have all the action handler methods that are passed in the each `m.connect` call. ### Route Handler [Route Handler](routes.md) should inherit `aalam_common.wsgi.BaseHandler` class. This class should define methods for all the `action`, `serializer` and `deserializer` arguments used for the URL using this handler. class TestAppHandler(wsgi.BaseHandler): def __init__(self, mapper): # The BaseHandler.__init__ must be called with this mapper object. # If you do not have anything to do in this method, better not # define it. super(TestAppHandler, self).__init__(mapper) def send_homepage(self, request): # We are not documenting this, as this API will be more useful # for the users than the developers. # We dont to send the index page on a static prefixed URL, hence # we set the static_file attribute in the request object and let # the framework handle the response. # The index file will be placed by the aalam packager only if # it is mentioned in the setup.py like # setup(data_files=[("index.html", "resource/index.html"), ...]) request.static_file = {"resource": "index.html", "path": os.path.join( cfg.CONF.package_dir, "resources", "index.html")} # we are not returning any data, as the framework will take care # of it. def create_item_deserializer(self, request): # Input is expected to be either in json or xml format, so check # content type. json_deserializer() method is defined in the # BaseHandler, so using it as is. if request.content_type == "application/json": # We have an inbuilt json serializer defined in BaseHandler class return self.json_deserializer(request) elif request.content_type == "application/xml": # Parse the input xml data from request.body and return a # dictionary object pass def create_item(self, request, name=None, type=None): """ Create Item Creates a new item of a user chosen name and type Section: Items Input: type: application/json description: Input data in json spec: { "name": "Some name", "type": "Some type", } Input: type: application/xml description: Input data in xml spec: Some name Some type ` | :download:`PKG-INFO ` | :download:`example_app/__init__.py ` | :download:`example_app/app.py ` | :download:`resources/index.html ` | :download:`resources/create_form.html ` | :download:`resources/items_access.html ` ``` [PKG-INFO]: http://docs.aalam.io/_/apps/latest/py-pkg-info.html