Components of Web Applications

Published on June 2016 | Categories: Documents | Downloads: 71 | Comments: 0 | Views: 391
of 9
Download PDF   Embed   Report

Comments

Content

5/4/12

Components of Web Applications
Project Home

Components of Web Applications
Author: Date: Martin Blais <[email protected]> 2005-04-08

1 Introduction
This document lists the main components of a web application, and their usual dependencies. Ideas about components of web application are emerging in the development community towards being regarded as relatively loose-coupled or even entirely orthogonal components that one can mix and match to build a concrete web application. Some standards about how to combine some of these components are emerging, and I believe that since this is an easily modularized problem, more and more such agreements will appear in the near future. Note: this document is written in the context of writing web applications in the language Python. For many reasons outside the scope of this document, we believe that Python forms the best basis in terms of language and features to build web applications. However, the concepts are reasonably language-agnostic.

Contents 1 Introduction 2 Motivation 3 Main Components 3.1 Server (also called Gateway) 3.2 Configuration 3.3 Client 3.4 Request 3.5 Response 3.6 Cookie Jar 3.7 Automatic Change Detection 3.8 Logging 3.9 Error Handling 3.10 Application Initialization 3.11 Data Store 3.12 Session Management 3.13 Easy/Pickled Storage 3.14 Authentication 3.15 Resource Mapping 3.16 Internationalization (I18N) 3.17 Form Definition and Processing 3.18 Rendering 3.19 Page Templates 3.20 Automated Testing 3.21 Email Server 4 Useful Extensions 4.1 Automatic Conversions and Caching 4.2 User Management Handlers 4.3 Issue Tracking for Feedback 4.4 Automatic Error Reporting 4.5 Asynchronous Tasks and Scheduler 4.6 Events 5 Innovative Ideas 6 Conclusion

2 Motivation
We would like to code our web application in a way that is as much as possible independent from any web application framework. As such, we need to define a set of minimal interfaces to specific components so that we can eventually completely change the underlying infrastructure, as more and more components mature or become available. This implies that we should eventually be in a position to easily change the underlying components of our web application by providing some glue between the new components and an existing application. This problem is begging for the definition of simple interfaces to provide an environment for a web application. This is where I want to get with this document.

Also, we need to identify dependencies between the various components in order to be able to make sensible decisions regarding the choice and setup code for the underlying framework providing the environment for our application.

3 Main Components
This section lists the components and related interfaces and dependencies.

3.1 Server (also called Gateway)
The goal of the server is to receive the actual request from whatever backend is being used and provide the variables from the backend into the Python language. The server is the glue between the backend and Python. Backend examples include: Apache with mod_python installed
furius.ca/indra/doc/design.html 1/9

5/4/12

Components of Web Applications

Twisted Web, Python's own simple HTTPServer, ... The WSGI interface (PEP333) has been designed specifically to address the issue of standardizing the way that various backends communicate with the rest of the web applications. A concrete WSGI server implementation will need to provide a way to connect an application object to it. Application code may want to access some parameters of the server, such as the address or the port that it is listening on. It should be able to provide that. Interfaces IServer Dependencies (None)

3.2 Configuration
We want to be able to specify configurable parameters for our application behaviour in a single place. For example, our application may have a test mode, in which it provides a set of pages specifically for testing. Thus we need a module which provides some generic set of parameters and automatically detect when this input is changed and refresh it accordingly. Interfaces IConfiguration Dependencies (None)

3.3 Client
Information about the client should be made available to the application code, such as the client port, address and hostname. Interfaces IClient Dependencies Environment provided by the server.

3.4 Request
We need to be able to provide information about the request to the application, such as the URL path, and the HTTP headers. Interfaces IRequest Dependencies Environment provided by the server.

3.5 Response
A mechanism for returning a response to the client is required. Features include the need for setting encoding, compression, content type, headers, and the body of the response. We also need to be able to flush some part of the response to the server early. Also, this mechanism needs to allow redirection to another URL, which can be very convenient in many cases. Interfaces IResponse Dependencies Environment provided by the server for writing the response.

3.6 Cookie Jar
furius.ca/indra/doc/design.html 2/9

5/4/12

Components of Web Applications

We need to provide a way for the application code to access or set cookies in the client browser. Generally, this will only be used for the session management code, but there could be application-specific uses as well, this is why we want to export "some" access to the cookie mechanism. Interfaces ICookieJar Dependencies Environment provided by the server, and for writing the response.

3.7 Automatic Change Detection
One feature that is extremely useful to have during development, is for a component to check for source code changes, and that automatically reloads the Python modules if some of the source code has changed. I consider this essential to fast development. This can be a little bit tricky to implement and greatly depends on how the application components are written. One must be wary of global state, and of dependencies between components. I have succeeded in implementing this by unloading all the framework modules (except a mod_python handler) when a single source file has changed. Checking for timestamps on every requests does slow down the application a great deal, but this is only enabled in a special development/test mode. This greatly speeds up development: much of the process becomes a short cycle of "change source code, save file, reload page; continue". Interfaces (None) Dependencies Configuration (to enable/disable development mode)

3.8 Logging
Since all the user-visible output goes to a client browser, there needs to be way that the application can trace its behaviour. In the available environment, there should be a simple mechanism for logging. Interfaces ILogger Dependencies (None)

3.9 Error Handling
The environment needs to provide a standard way to indicate errors, as well as a way to specify how the application should deal with these errors (e.g. renders a special error page). In addition, it would be great for this to be tied somehow with a bug/issue tracking system, so that application error can be automatically logged to the developers. Interfaces IErrorHandling Dependencies Bug/issue tracking system interface. Response mechanism.

3.10 Application Initialization
It may be useful for the environment to provide a way to perform some task when the server has been restarted, so that before the first child/thread gets to treat a request, we can perform some initialization action, either in that child/thread, or outside. (I haven't needed this yet, so I think it is not essential.) Interfaces IAppInit Dependencies
furius.ca/indra/doc/design.html 3/9

5/4/12

Components of Web Applications

Server mechanism to detect server generation. Perhaps some database access, for synchronizing between children.

3.11 Data Store
A way to store information that is shared and synchronized between the various children/threads is absolutely necessary for the higher levels of the application framework. It would also be used by other components, such as user authentication. For cases which need to scale up to many servers, we need to provide separate pathways for reading from the database, and writing to the database, so that we can configure duplicated read-only database servers with a replicated write-only database server. It makes it easier to integrate the various components if the concrete implementation allows sharing the database connection or cursors with other components, so that we can minimize the amount of resources that the entire framework uses for each child. Also, interfaces such as DBAPI provide a way for supporting many database backends. Note that in practice, we believe that using one of the many quasi object-relational mappings (such as SQLObject) or specific interfaces (such as ZODB) will be a more practical and Pythonic approach than writing all data to a single database interface. Interfaces IDatabase. Some Python ORM interface (e.g. SQLObject or ZODB). Dependencies A database driver.

3.12 Session Management
Managing sessions using cookies is standard. This is used to implement authentication and other mechanisms. We should provide an easy interface for session management. (Note that this does not include authentication, which is only built on top of session management.) Note: I judge it useless today to bother with supporting browsers which do not support cookies and I assume that our applications will never support that. Interfaces ISession, ISessionMgr Dependencies Shared (database) storage.

3.13 Easy/Pickled Storage
Pickled storage that is tied to a specific session or that is persistent forever is really useful. This allows you to store anything that can be pickled to the database, which makes for a quick-and-dirty storage place. This is really useful for application data that needs not be persistent forever or that is not critical the application, or for testing. Note that for your persistent application data you should use the various ORM interfaces or build some interface on top of the low-level database interface. Interfaces IPickleStoreFactory, IPickleStore Dependencies Shared (database) storage.

3.14 Authentication
Built on top of the session management, the authentication module should provide a way to manage users, groups of users, and roles. Application code can then require a role at any point of its execution, thus providing a mechanism to restrict resource access very selectively (and therefore allow RESTful resource mapping). Interfaces
furius.ca/indra/doc/design.html 4/9

5/4/12

Components of Web Applications

IAuthentication Dependencies Shared database storage (for users, groups and roles). Session management.

3.15 Resource Mapping
A request consists of the URI path and its query arguments, and some HTTP headers and the method type (almost). In order to map these parameters to a resource and to allow components of the path to be used as parameters (e.g. / s r / u e n m > p o i e we need to provide a system that allows flexible customization of this mapping through code. u e s < s r a e / r f l ), Also, allowing code in the mapping provides a good place to request access permissions (roles). Basically, a way to map the incoming URI path to some function or method or file. I personally like to use the chain-ofresponsibility pattern for this, similarly to the way Twisted does it. Also, the resource mapping should provide a way to easily and efficiently serve some files or some hierarchy of files. This can be achieved by providing various concrete implementations of the IResource interface. Interfaces IResource (with concrete implementations) Dependencies Request information.

3.16 Internationalization (I18N)
The need to support rendering pages in different languages requires a bit of preparation and some support libraries. GNU gettext() provides a convenient framework for doing this, and there are some tools to support the activities of translators. I18n is best supported by forcing some global variables _ and N in the Pythonn globals. These short-named functions are _ then used to mark strings in the source code as strings to be included in a dictionary of translation. They also act as lookup functions to obtain the translated text. Interface IInternationalization Dependencies Session data (optional).

3.17 Form Definition and Processing
Typed data arguments in forms can be easily expressed as input widgets, possibly with constraints on the values. It provides a convenient way to define the inputs of methods, as well as a way to parse the input arguments. In addition to parsing the input arguments, the form definition can be reused for rendering the forms, or for rendering form data in read-only tables (this aspect should be decoupled from the form definition and parsing). Also, when a parsing error occurs, or some error occurs, the form definitions and renderers should allow for a dictionary of error messages and values to be used to populate the repeat form with hints for the user about what to correct. Interfaces IFormField, IForm, IFormFactory Dependencies (None)

3.18 Rendering
Outputting HTML is best carried out by building a tree of nodes and then flattening the hierarchy into an HTML rendition. This has many advantages: the tree can be built in any order, and loops can be used to modify existing nodes. This is notoriously useful for building complex tables; the output is beautifully indented and can be made XHTML compliant more easily; some tricks can be used to embed stylesheet information in the tree elements, or to insert required javascript includes for
furius.ca/indra/doc/design.html 5/9

5/4/12

Components of Web Applications

elements that require it; it allows the building of a template class (a Python class) that represents specific page layouts, with appropriate methods to add user-defined elements. For example, a page layout (class MainPages) that has a sidebar could have a method called a d s d t p t x ) that would add the necessary wrapping code for inserting a tip, maybe with a img reference d_iei(et and appropriate CSS classes and ids. This amounts to adding a higher level of abstraction over the stylesheet mechanism to provide more abstract, complex and dynamic page templates. This library provides an easy syntax for representing these trees of nodes in the source code. It should also provide some way to iterate the elements and attributes in order to rewrite URLs in various ways (this may be necessary for RESTfulness). Also, the rendering of forms or of form data into read-only tables can be achieved by providing "form renderers", which use the form definitions to produce a HTML subtree to be inserted in the final HTML tree. We can also provide some code to assist in the creating of tasks that are often carried out, like setting current tabs depending on which resource is chosen, i.e. mapping pages to current tabs. Interfaces A library providing HTML classes for building the HTML tree. IFormRenderer. Dependencies (None)

3.19 Page Templates
Working with artists or "web developers" requires the ability to split the work easily. Page templates are often used for that purpose. There are a plethora of free libraries implementing different paradigms for page templates, including some which blend source code and HTML, as well as some which rely on replacement of elements with specific ids. These templates are loaded in memory, and their source file can be checked for updates and the page reloaded (in development mode). Anyway, we could provide access to some system of template or other. Interfaces (None, depends highly on templating system, no generic interface) Dependencies (None)

3.20 Automated Testing
Testing approaches vary. It can be performed at a low-level, where we simply write code that calls methods in our application code, but we believe that it is best to simulate real browser activity. This tends to highlight problems that would not be detected by the low-level approach. There are a few libraries that do this: mechanize, ClientForm, ClientCookie webunit We would like to provide a common interface for our automated tests. Interfaces IBrowser, IClientForm, IClientCookie, IFakemail Dependencies (None)

3.21 Email Server
Sending and notifications when receiving email should be provided by a module. Also, this module should provide a testing mode for sending email, which does not actually send the email, but rather stashes it somewhere in a per-user pigeonhole, and for which a resource handler can be used to fetch the contents of the email for that user. This is really useful for tests, where the test program can be truly disconnected from the codebase, and simulate reading email by using this interface. This fake-email interface should only be available in testing mode.
furius.ca/indra/doc/design.html 6/9

5/4/12

Components of Web Applications

Interfaces ISendMail, IReceiveMail Dependencies (None)

4 Useful Extensions
This section describes other useful modular codes.

4.1 Automatic Conversions and Caching
Conveniences such as automatic conversion and caching of some file formats, such as restructuredtext, can be useful to provide and alternative input formats for web developers. Interfaces (Depends on format.) Dependencies (None)

4.2 User Management Handlers
A basic user management is pretty much the same for many applications. We should well-tested provide stock handlers to take care of this.

4.3 Issue Tracking for Feedback
Feedback forms can be tied to an issue tracking mechanism. This way we can keep a history of communications with customers/users and this provides a nice interface for support people to organize their work. Interfaces IIssueTracker Dependencies (None)

4.4 Automatic Error Reporting
Similarly, when we encounter an internal error, and accordingly redirect the user to an error page, we have much information about the error and we could report it somehow. There should be a way to query an issue tracking system for a specific call stack, and if an error for that call stack has not been reported yet, to automatically enter much details in the bug report, including the stack trace, request and POST arguments, as well as maybe even take a snapshot of some database portion. Interfaces IIssueTracker (same as above) Dependencies (None)

4.5 Asynchronous Tasks and Scheduler
We could provide a way for the application code to run tasks asynchronously. Perhaps check on every request a list of tasks to be executed and run them as soon as we can within the running application children. Or perhaps triggered by an external scheduler. The purpose of this is to leverage whatever resources and synchronization mechanisms are already available in the server's workers. Interfaces ? Dependencies (None)
furius.ca/indra/doc/design.html 7/9

5/4/12

Components of Web Applications

4.6 Events
A notification interface for the application to call back on the children when specific events occur could be useful. e.g. application-start, session-start, session-end, etc. Interfaces ? Dependencies (None)

5 Innovative Ideas
This document presents some ideas that are not often discussed in web application frameworks. They are not that original, but strangely enough, most frameworks do not provide the following: a version of gettext that doesn't take into account newlines for strings; decoupling the form definition and rendering; templates using class code; automatically logging tracebacks of errors into a bug database; automatic reloading of modified source code; a fake-email for testing;

6 Conclusion
A set of specific interfaces are introduced that provide a standardized minimal environment to write web applications.

furius.ca/indra/doc/design.html

8/9

5/4/12

Components of Web Applications

Dependencies between the components and their implementation.

furius.ca/indra/doc/design.html

9/9

Sponsor Documents

Or use your account on DocShare.tips

Hide

Forgot your password?

Or register your new account on DocShare.tips

Hide

Lost your password? Please enter your email address. You will receive a link to create a new password.

Back to log-in

Close