When coding a web system, you have to think about an important problem, how to map urls to logic.

Openstack use routes to solve this problem.

What is routes

Routes is a python package used to map urls to program logic. Normally this is the web framework`s responsibility, so besides openstack, routes is also used in several other python web frameworks.

Quick start

>>> from routes import Mapper
>>> map = Mapper()
>>> map.connect('route_name_update_net', '/nets/{net_id}', controller='nets_controller', conditions=dict(method=['PUT']), self_defined_key='self_defined_value')
# Above code created a route named "route_name_update_net"
# It match any two component urls started with /nets
# Controller which will process the request is nets_controller
# Conditions parameter restrict the route only accept PUT request >>> map.match('/nets/123')
{'controller': u'nets_controller', 'net_id': u'123', "self_defined_key":"self_defined_value"}
# As you can see, the url which match the route will return a dict. The dict contains the controller information and necessary var
# The self_defined_key and self_defined_value also included. >>> print map
Route name Methods Path
route_name_update_net PUT /nets/{net_id}
>>>

Basic usage

Requirements

Some times you want to restrict the path var, you can use the requirements parameter in below ways

map.connect(R"/download/{platform:windows|mac}/{filename}")

This line restrict the platform var could only be windows or mac. You can also write it in below way

map.connect("/download/{platform}/{filename}", requirements={"platform": R"windows|mac"})

The R char here is very important. Without it you may need to double your slash in your url.

Once you restrict your route, you can try it like below:

# The platform must be windows or mac so below url match
>>> map.match('/download/windows/myfile')
{'platform': u'windows', 'filename': u'myfile'}
# The linux is not valid here so does not match
>>> map.match('/download/linux/myfile')

PATH_INFO

In WSIG env, the url information is stored in the environ dict with key PATH_INFO.

Routes treat the path_info specially. When the “path_info” variable is used at the end of the URL, Routes moves everything preceding it into the “SCRIPT_NAME” environment variable. This is useful when delegating to another WSGI application that does its own routing: the subapplication will route on the remainder of the URL rather than the entire URL

For example

>>> from routes import Mapper
>>> map=Mapper()
>>> map.connect('/classes/{path_info:.*}')
>>> map.match('/classes/students/tom')
{'path_info': 'students/tom'}
>>>

The subsequent system will see PATH_INFO: /students/tom and SCRIPT_NAME:classes. So the sub system can use its own route system.

Format extensions

Consider to design a url /neutron/networks/{network_id} which will used to access the network resource. The network can be returned in JSON format or XML format. So we can do it in routes like this:

>>> from routes import Mapper
>>> map=Mapper()
>>>
>>> map.connect('/neutron/networks/{network_id}{.format:json|xml}')
>>> map.match('/neutron/networks/123.json')
{'network_id': u'123', 'format': u'json'}
>>> map.match('/neutron/networks/123.xml')
{'network_id': u'123', 'format': u'xml'}
>>> map.match('/neutron/networks/123.html')
{'network_id': u'123.html', 'format': None}

Use the format parameter to specify the resource format

RESTful

Use routes can generate restful routes very conveniently

>>> from routes import Mapper
>>> map=Mapper()
>>> map.resource('net','nets')
>>> print map
Route name Methods Path
POST /nets.:(format)
POST /nets
formatted_nets GET /nets.:(format)
nets GET /nets
formatted_new_net GET /nets/new.:(format)
new_net GET /nets/new
PUT /nets/:(id).:(format)
PUT /nets/:(id)
DELETE /nets/:(id).:(format)
DELETE /nets/:(id)
formatted_edit_net GET /nets/:(id)/edit.:(format)
edit_net GET /nets/:(id)/edit
formatted_net GET /nets/:(id).:(format)
net GET /nets/:(id)

The first parameter is resource name also called member in RESTful

The second is the plural of resource name which is also called collection in RESTful

the resource function have several parameters and we will learn them one by one

controller

This parameter specify the controller to handle the request. For example:

>>> map=Mapper()
>>> map.resource('net','nets', controller='net_controller')
>>> map.match('/nets/123')
{'action': u'update', 'controller': u'net_controller', 'id': u'123'}

collection

This parameter add more additional urls for the collection operations. For example:

Before use the parameter the map is like below

>>> map=Mapper()
>>> map.resource('net','nets', controller='net_controller')
>>> print map
Route name Methods Path
POST /nets.:(format)
POST /nets
formatted_nets GET /nets.:(format)
nets GET /nets
formatted_new_net GET /nets/new.:(format)
new_net GET /nets/new
PUT /nets/:(id).:(format)
PUT /nets/:(id)
DELETE /nets/:(id).:(format)
DELETE /nets/:(id)
formatted_edit_net GET /nets/:(id)/edit.:(format)
edit_net GET /nets/:(id)/edit
formatted_net GET /nets/:(id).:(format)
net GET /nets/:(id)

After we add the collection parameter

>>> map.resource('net','nets', controller='net_controller', collection={'subnets':'POST'})
>>> print map
Route name Methods Path
formatted_subnets_nets POST /nets/subnets.:(format)
subnets_nets POST /nets/subnets
POST /nets.:(format)
POST /nets
formatted_nets GET /nets.:(format)
nets GET /nets
formatted_new_net GET /nets/new.:(format)
new_net GET /nets/new
PUT /nets/:(id).:(format)
PUT /nets/:(id)
DELETE /nets/:(id).:(format)
DELETE /nets/:(id)
formatted_edit_net GET /nets/:(id)/edit.:(format)
edit_net GET /nets/:(id)/edit
formatted_net GET /nets/:(id).:(format)
net GET /nets/:(id)

The collection operation can mathc /nets/subnets on POST method.

member

>>> map=Mapper()
>>> map.resource('net','nets', controller='net_controller', member={'subnets':'POST'})
>>> print map
Route name Methods Path
POST /nets.:(format)
POST /nets
formatted_nets GET /nets.:(format)
nets GET /nets
formatted_new_net GET /nets/new.:(format)
new_net GET /nets/new
PUT /nets/:(id).:(format)
PUT /nets/:(id)
formatted_subnets_net POST /nets/:(id)/subnets.:(format)
subnets_net POST /nets/:(id)/subnets
DELETE /nets/:(id).:(format)
DELETE /nets/:(id)
formatted_edit_net GET /nets/:(id)/edit.:(format)
edit_net GET /nets/:(id)/edit
formatted_net GET /nets/:(id).:(format)
net GET /nets/:(id)

After use member parameter, the member operation can match /nets/{id}/subnets

path_prefix and name_prefix

This two parameter are used together. For example:

>>> map=Mapper()
>>> map.resource("message", "messages", controller="categories", path_prefix="/category/{category_id}", name_prefix="category_")
>>> print map
Route name Methods Path
POST /category/{category_id}/messages.:(format)
POST /category/{category_id}/messages
formatted_category_messages GET /category/{category_id}/messages.:(format)
category_messages GET /category/{category_id}/messages
formatted_category_new_message GET /category/{category_id}/messages/new.:(format)
category_new_message GET /category/{category_id}/messages/new
PUT /category/{category_id}/messages/:(id).:(format)
PUT /category/{category_id}/messages/:(id)
DELETE /category/{category_id}/messages/:(id).:(format)
DELETE /category/{category_id}/messages/:(id)
formatted_category_edit_message GET /category/{category_id}/messages/:(id)/edit.:(format)
category_edit_message GET /category/{category_id}/messages/:(id)/edit
formatted_category_message GET /category/{category_id}/messages/:(id).:(format)
category_message GET /category/{category_id}/messages/:(id)

The path_prefix add a url prefix to the urls that can be matched. The name_prefix is the prefix of route name.

They actually are parent resource of message.

Parent resource

>>> from routes import Mapper
>>> map=Mapper()
>>> map.resource('location', 'locations', parent_resource=dict(member_name='region', collection_name='regions'))
>>> print map
Route name Methods Path
POST /regions/:region_id/locations.:(format)
POST /regions/:region_id/locations
formatted_region_locations GET /regions/:region_id/locations.:(format)
region_locations GET /regions/:region_id/locations
formatted_region_new_location GET /regions/:region_id/locations/new.:(format)
region_new_location GET /regions/:region_id/locations/new
PUT /regions/:region_id/locations/:(id).:(format)
PUT /regions/:region_id/locations/:(id)
DELETE /regions/:region_id/locations/:(id).:(format)
DELETE /regions/:region_id/locations/:(id)
formatted_region_edit_location GET /regions/:region_id/locations/:(id)/edit.:(format)
region_edit_location GET /regions/:region_id/locations/:(id)/edit
formatted_region_location GET /regions/:region_id/locations/:(id).:(format)
region_location GET /regions/:region_id/locations/:(id)

This is the same as path_prefix and name_prefix. The path_prefix here is /regions/{region_id} and name_prefix is region_

openstack use routes to map url to controller, so it is necessary to know about routes. Routes are came from Ruby on rails. It is rewritten in python. So docs about routes are not very clear might because the author think we should learn Ruby on rails routes first.

Submapper

submapper is a lazy way to write code. See examples below:

You want to generate a series route, they have common attributes like

controller: common_controller
action: index
path_prefix: api/v2
conditions: {'method':'GET'}

You can write the code in this way

>>> from routes import Mapper
>>> map = Mapper()
>>> with map.submapper(controller='common_controller', action='index', path_prefix='api/v2/', contidions={'method':'GET'}) as submapper:
... submapper.connect('api/v2/'+'nets', 'nets')
... submapper.connect('api/v2/'+'subnets', 'subnets')
...
>>> print map
Route name Methods Path
api/v2/nets api/v2/nets
api/v2/subnets api/v2/subnets

In this way you can put the common attributes in submapper.

how to read openstack code : routes的更多相关文章

  1. how to read openstack code: loading process

    之前我们了解了neutron的结构,plugin 和 extension等信息.这一章我们看一下neutron如何加载这些plugin和extension.也就是neutron的启动过程.本文涉及的代 ...

  2. how to read openstack code : stevedore

    学习了WSGI/Paste deploy后,还需要对一些在openstack中一些package有一些了解,才能更好的理解openstack的代码 What is stevedore 我们在写代码的时 ...

  3. how to read openstack code : wsgi

    要读懂本篇,你至少得写过一个python的web程序,并且把它部署到web服务器上过. 什么是wsgi 假设你写了一个python的web程序,并部署到了nginx上,那么一个http request ...

  4. how to read openstack code

    本文的目的不是介绍openstack.我们这里假设你已经知道了openstack是什么,能够做什么.所以目的是介绍如何阅读openstack的代码.通过读代码来进一步学习openstack. 转载要求 ...

  5. how to read openstack code: request extension

    We have learned resource extension and action extension. This post we will write a request extension ...

  6. how to read openstack code: action extension

    之前我们看过了core plugin, service plugin 还有resource extension. resource extension的作用是定义新的资源.而我们说过还有两种exten ...

  7. how to read openstack code: service plugin

    We have learned core plugin, service plugin and extension in last post. Now let`s review: Core Plugi ...

  8. how to read openstack code: Core plugin and resource extension

    本章我们将写一个自己的core plugin 和一个resource extension来加深理解.(阅读本文的前提是你已经理解了restful以及stevedore等内容) 什么是 core plu ...

  9. how to read openstack code: Neutron architecture

    今天这一章节非常重要.我们知道neutron是一个非常复杂的系统,由很多组件构成.研究这样一个复杂的系统,正确的顺序应该是现在宏观上对其整体结构有所了解,然后再由针对性的对其组件进行深入了解.本章要做 ...

随机推荐

  1. js添加千位分隔符

    function thousandBitSeparator(num){ var re=/\d{1,3}(?=(\d{3})+$)/g; var n1=num.toString().replace(/^ ...

  2. python 实现代理服务器

    # encoding:utf-8 import socket import thread import re def getAddr(d): a = re.search("Host: (.* ...

  3. CAD参数绘制多行文字(网页版)

    在CAD设计时,需要绘制多行文字,用户可以设置设置绘制文字的高度等属性. 主要用到函数说明: _DMxDrawX::DrawMText 绘制一个多行文字.详细说明如下: 参数 说明 DOUBLE dP ...

  4. vs2008如何新建自己工程的环境变量(局部)和 Windows系统(全局). .

    在vs2008的Project->Property设置里经常会看到类似$(IntDir).$(OutDir).$(ProjectName) 的预定义宏.以vc2008为例,有时候我们在引用别的库 ...

  5. viewDidLoad等相关函数调用

    viewDidLoad 此方法只有当view从nib文件初始化的时候才被调用.viewDidLoad用于初始化,加载时用到的. loadView 此方法在控制器的view为nil的时候被调用.虽然经常 ...

  6. CentOS7.4 搭建和使用telnet

    1.先检查是否安装了telnet rpm -qa | grep telnet  //检查你的CentOS是否安装了telnet和telnet-server rpm -qa xinetd //检查你的C ...

  7. idea导入本地idea的web项目(服务器用的是tomcat)

    开始吧!!! 点击import project. 我以SpringMVCPro3为例,选中,点击OK 点击next 继续next 随便吧,我点击yes 选中工程,点击next lib1不要钩,然后点击 ...

  8. 2 SQL 查询基础

    2 查询基础 2-1 SELECT语句基础 通过SELECT语句查询并选取必要数据的过程称为匹配查询或查询(query). 子句是SQL语句的组成要素,是以SELECT或者FROM等作为起始的短语. ...

  9. linux ping-测试主机之间网络的连通性

    博主推荐:更多网络测试相关命令关注 网络测试  收藏linux命令大全 ping命令用来测试主机之间网络的连通性.执行ping指令会使用ICMP传输协议,发出要求回应的信息,若远端主机的网络功能没有问 ...

  10. xtrbackup备份mysql

    mysqldump备份方式是采用逻辑备份,但是它最大的缺陷就是备份和恢复速度慢对于一个小于50G的数据库而言,这个速度还是能接受的,但如果数据库非常大,那再使用mysqldump备份就不太适合了. x ...