How To Use MapFish Server
This HowTo describes step by step how to use MapFish Server Framework to set up a MapFish project. A MapFish project defines Web Services on which MapFish Client components can rely. See Map Fish Protocol for a description of the interfaces provided by MapFish Web Services.
Warning: This HowTo assumes that the MapFish egg is installed. If not, go to the How To Install page.
Warning: The MapFish-0.1 egg (provided on http://dev.camptocamp.com/packages/eggs/) does not have support for paster commands. Therefore, make sure the installed egg comes from MapFish version > 0.1. If there's no MapFish version > 0.1 (which is the case at time of this writing), please build and install the MapFish egg from SVN trunk.
Create a MapFish project
Paste is used to create MapFish projects:
/path/to/vpython/bin/paster create --overwrite --no-interactive --template=mapfish MyMapFishProject mapfishclientmfbasepath=/path/to/MapFish/client/mfbase
Replace MyMapFishProject with your actual project name. In the rest of this HowTo, we'll refer to your project name as MyMapFishProject.
Note: the above command assumes that you have installed the MapFish egg and its dependencies in a virtual python.
Your project is now created. More concretely, a directory named MyMapFishProject populated with various files has been created. This is your project dir.
A MapFish project is really a Pylons with some geo-oriented specificities.
Set up PostGIS connections
To set up PostGIS connections edit the development.ini configuration file and adds lines of this form in the [app:main_pylons] section:
sqlalchemy.<db>.url = postgres://<dbuser>:<dbpassword>@<dbhost>/<db>
Replace <db>, <dbuser>, <dbpassword>, and <dbhost> appropriately.
If you need multiple database connections, use multiple lines of this sort.
Set up layers
You now need to create layers. In effect, a layer corresponds to a PostGIS table. To create layers edit the layers.ini and add your layers following the example given in the file.
Example of single-layer configuration:
# Layer configuration file # Example: # # [users] # singular=user # plural=users # db=dbname # table=users # epsg=4326 # units=degrees # geomcolumn=the_geom # idcolumn=Integer:id [countries] singular=country plural=countries db=geostat table=world_factbk_simplified epsg=4326 units=degrees geomcolumn=simplify idcolumn=Integer:gid
Note 1: as a convention use plural names as your layer names. Note 2: the idcolumn property can be omited as of v0.3
Generate model and controller code
Now it's time to get paster and MapFish generate code for you.
If you have created a layer named countries (as in the above example) use this command:
/path/to∕vpython/bin/paster mf-layer countries
This command creates three files: a controller file, its associated test file, and a model file. Take a look at the controller and model files to get a sense on what the code generator did for you. To do fancy things you'll have to edit these files anyway so don't be shy...
Note: two other paster commands are provided by MapFish: mf-controller and mf-model. The former takes care of creating the controller. The latter deals with the model. Internally, mf-layer composes mf-controller and mf-model.
Finish configuration
In a perfect world you'd be done. Since world isn't perfect (yet) you have to edit some files to complete your layer configuration.
Change dir to mymapfishproject and edit the files:
- config/environment.py
Add this line after the from pylons import config line:
from sqlalchemy import engine_from_config
and this one at the end of the file:
config['pylons.g'].sa_geostat_engine = engine_from_config(config, 'sqlalchemy.geostat.')
This latter line creates an sqlalchemy database engine associated with your database. Obviously, geostat must be replaced by your database connection name (what you've configured in development.ini).
Note: do no forget that indentation matter in Python! The line must be indented to be part of the load_environment() function.
- config/routing.py
Some URL routing configuration is needed. Add the following lines:
map.resource('country', 'countries')
before the lines for the default routes:
map.connect(':controller/:action/:id') map.connect('*url', controller='template', action='view')
Again, check your indentation!
See the documentation of Routes to know more about routing configuration with Routes.
- model/__init__.py
The layer must be bound to the database engine. Edit model/__init__.py and and replace the line
binds = {}
With our example, that line is replaced with:
binds = {'countries': MetaData(config['pylons.g'].sa_geostat_engine)}
- lib/base.py
One last thing to do is change the BaseController code. The BaseController class must look like this:
class BaseController(WSGIController): def __call__(self, environ, start_response): try: """Invoke the Controller""" # WSGIController.__call__ dispatches to the Controller method # the request is routed to. This routing information is # available in environ['pylons.routes_dict'] return WSGIController.__call__(self, environ, start_response) finally: model.Session.remove()
The .remove() method is very important! See this page for further details.
Starting the web server
You should be all set now. Try starting the paster web server:
/path/to/vpython/bin/paster serve --reload development.ini
and checkout http://localhost:5000/countries?maxfeatures=10
Your browser should be displaying a nice GeoJSON object!
You can now go back to your webpage and configure MapFish widgets to access your layer through the URL http://localhost:5000/countries.
If you this warning message:
/path/to/vpython/lib/python2.4/site-packages/SQLAlchemy-0.4.0-py2.4.egg/sqlalchemy/databases/postgres.py:497: RuntimeWarning: Did not recognize type 'geometry' of column 'the_geom'
warnings.warn(RuntimeWarning("Did not recognize type '%s' of column '%s'" % (attype, name)))
don't worry, it's harmless.
