Writing your first Aurora based Web application, part 1

In this tutorial you will learn by example how to create a Web based Blogging application using the Aurora Web application framework.

For cut and paste purposes, the source code for all stages of this tutorial can be browsed at https://github.com/yeiniel/aurora/tree/master/documentation/intro/webapp/src/tutorial-1.

Basic Layout

Scaffolding

Currently the Aurora Web application framework doesn’t provide a tool to automate the task of creating scaffolds for a new Web application, it must be done by hand.

Before we start coding our Web application we need to setup the basic layout for it. First you need to create a folder that host all application’s specific files, lets call this folder tutorial-1. Inside that folder create a Python module named application, we will use this module to host the Web application definition. Open the module file once created in your preferred text editor and write the following:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
#! /usr/bin/env python3
from aurora import webapp
__all__ = ['Application']


class Application(webapp.Application):
    """ Web Blogging application
    """

if __name__ == '__main__':
    from wsgiref import simple_server
    from aurora.webapp import foundation

    wsgi_app = foundation.wsgi(Application())
    httpd = simple_server.make_server('', 8008, wsgi_app)

    print("Serving on port 8008...")
    httpd.serve_forever()

This Python module define a class (the Application class) that inherit from a base class provided by the Web application framework, this is the Web application definition. Additional code is provided to allow the module to be executed directly as a console application, in this case the WSGI Web server shipped with the Python standard library is used to serve a Web application based on that definition on port 8008.

If you execute this module at the console and open the http://localhost:8008/ address in your preferred Web browser you will see a default and simple Not Found message. This is correct and it means you did not setup a Web request path mapping that associate a Web request handler to the base Web application path. As you can see the Web application framework doesn’t do any magic for you and this is one of its design principles.

Defining the Blogging services

There are three services that all Blogging’s platforms provide:

  • present summary of recently published Posts.
  • present a published Post.
  • form for composing a new Post.

We are going to implement this three services into our Web application. As a first step we are going to add the corresponding three service definitions stubs (methods) to the Web application definition (class) as follows:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
    def list_posts(self, request: foundation.Request) -> foundation.Response:
        """ List summaries for posts added more recently. """
        return request.response_factory(text="""
        <html>
            <body>
                <h1>List of posts</h1>
                <div>
                    <h2><a href="/post/1">Post title</a></h2>
                    <p>
                        Post summary (or the initial segment of post
                        content).
                    </p>
                </div>
                <div>
                    <h2><a href="/post/1">Post title</a></h2>
                    <p>
                        Post summary (or the initial segment of post
                        content).
                    </p>
                </div>
                <div>
                    <h2><a href="/post/1">Post title</a></h2>
                    <p>
                        Post summary (or the initial segment of post
                        content).
                    </p>
                </div>
            </body>
        </html>
        """)

    def show_post(self, request: foundation.Request) -> foundation.Response:
        """ Show a post. """
        return request.response_factory(text="""
        <html>
            <body>
                <h1><a href="/post/1">Post title</a></h1>
                <p>
                    Post content (full).
                </p>
            </body>
        </html>
        """)

    def add_post(self, request: foundation.Request) -> foundation.Response:
        """ Add a new Blog post. """
        return request.response_factory(text="""
        <html>
            <body>
                <h1>Add new post</h1>
                <form action="/add" method="post">
                    <fieldset>
                        <legend>Add Post</legend>
                        <div class="clarfix">
                            <label for="title">Title</label>
                            <div class="input">
                                <input type="text" id="title" name="title"></input>
                            </div>
                        </div>
                        <div class="clarfix">
                            <label for="content">Content</label>
                            <div class="input">
                                <textarea id="content" name="content" class="xlarge" rows="3"></textarea>
                            </div>
                        </div>
                        <div class="actions">
                            <input class="btn primary" type="submit" name="submit" value="Add" />
                        </div>
                    </fieldset>
                </form>
            </body>
        </html>
        """)

As you can see, an additional Python module has been imported, and used to annotate the three service definition stubs (the aurora.webapp.foundation module). This has been done to make clear to any user that read the source code, that this three services implement the Web request handling protocol. By making this three services implement this protocol (interface), we make them able to handle Web requests (read the Handler documentation for more information). But if you restart your Web application at the console once you make the changes to your copy of the Python module, you will not going to be able to see this services at action because the Web application don’t know which Web requests map to the different services that implement the Web request handling protocol (remember that the Web application framework don’t do magic for you).

Mapping Web request paths to Web request handlers

Now we are going to add code that map this three services as Web request path characteristic (specifically the _handler characteristic) with the Web application mapper, this way the Web application will know which Web requests sent to the three different Web request handlers. The code looks as follows:

1
2
3
4
5
6
    def __init__(self):
        self.mapper.add_rule(mapping.Route('/'), _handler=self.list_posts)
        self.mapper.add_rule(mapping.Route('/post/(?P<id>\d+)'),
            _handler=self.show_post)
        self.mapper.add_rule(mapping.Route('/compose'),
            _handler=self.add_post)

As you can see, an additional Python module has been imported (the aurora.webapp.mapping module), and used to create the Web request path rules used to map the tree Web request handlers. Once that you update your Web application definition code, restart your Web application running at the console and refresh the http://localhost:8008/ address in your browser. You will see the list of Posts summaries produced by the stub, from there you can browse to the pages of the independent Posts.

Conclusion

Well, this is all for now. In this tutorial you learn how to create a Web application using the Aurora library and how to write services that act as Web request handlers. In the next part of this tutorial you will learn how to integrate components shipped with the Aurora library to address common needs and how to to create components to integrate third party libraries.