搭建RESTful API 之 实现WSGI服务的URL映射

本文涉及的产品
云解析 DNS,旗舰版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
全局流量管理 GTM,标准版 1个月
简介:

javarestfull 搭建参考 http://blog.csdn.net/hejias/article/details/47424511

问题引出:对于一个稍具规模的网站来说,实现的功能不可能通过一条URL来完成。如何定义多条URL,也是RESTful API考虑的问题。

需求:

本小节将考虑这样一个虚拟机管理的WSGI服务。用户可以通过发送HTTP请求,来实现对虚拟机的管理(包括创建、查询、更新以及删除虚拟机等操作)。这个WSGI服务不会真正的在物理机上创建虚拟机,只是在服务中保存相应的虚拟机记录而已。

(nova已经实现类似的功能。当用户向 Nova 发送创建虚拟机的请求时,Nova 首先会在数据库中添加相应的记录,同时在物理机上创建相应的虚拟机。

Nova必须保证数据库中保存的虚拟机信息和实际创建的虚拟机信息一致,我们直接将记录保存在内存中)

开始今天的行程:

一、基础知识

(1)、RESTful API提供一套URL的规则。在RESTful API中,每条URL都是与资源相对应的。 一个资源可能是集合,也可能是一个个体。集合通常用集合名来标志。

例如:本小节实例中,使用instances表示虚拟机的集合,而个体通常使用统一的ID标志,使用UUID标志虚拟机

(2)、对于集合的操作通常是添加和查询; 对于个体的操作是虚拟机的查询、删除和更新。对应的URL如下图示:  

{instance_id}是虚拟机的UUID。将资源的ID放在URL中,是RESTful API的一大特点。

(3)、在WSGI中,要实现URL映射,主要是依赖Mapper和Controller两个类。

Mapper类用于实现URL的映射。当用户发送请求时,Mapper类会根据用户请求的URL及其方法来确定处理放入方法。

Controller类,则是实现处理HTTP请求的各种方法。

 

二、代码实现

1、配置文件:configure.ini

 

[python]  view plain  copy
  1. [pipeline:main]  
  2. pipeline = auth instance  
  3. [app:instance]  
  4. paste.app_factory = routers:app_factory  
  5. [filter:auth]  
  6. paste.filter_factory = auth:filter_factory  


WSGI服务共使用了auth过滤器和instance应用程序两个部件。auth与上一节的相同,不同的是新定义了instance应用程序。instance应用程序对应的工

 

厂方法是routers包的app_factory方法。

2、URL映射的实现

WSGI服务使用了auth过滤器和instance应用程序两个部件。其中auth过滤器是用于HTTP头认证的,比较简单。核心功能都在instance应用程序中实现。

 

[python]  view plain  copy
  1. from webob.dec import *  
  2. from webob import Request,Response  
  3. import webob.exc  
  4.   
  5. from routes import Mapper,middleware  
  6. import controllers  
  7.   
  8. class Router(object):  
  9.     def __init__(self):  
  10.         self.mapper = Mapper()  
  11.         self.add_routes()  
  12.         self.router = middleware.RoutesMiddleware(self._dispatch, self.mapper)  
  13.  
  14.     @wsgify  
  15.     def __call__(self, req):  
  16.         return self.router  
  17.   
  18.     def add_routes(self):  
  19.         controller = controllers.Controller()  
  20.   
  21.         self.mapper.connect('/instances', controller = controller,action = 'create', conditions = {'method' : ['POST']})  
  22.         self.mapper.connect('/instances', controller = controller,action = 'index', conditions = {'method' : ['GET']})  
  23.         self.mapper.connect('/instances/{instance_id}', controller = controller,action = 'show', conditions = {'method' : ['GET']})  
  24.         self.mapper.connect('/instances/{instance_id}', controller = controller,action = 'update', conditions = {'method' : ['PUT']})  
  25.         self.mapper.connect('/instances/{instance_id}', controller = controller,action = 'delete', conditions = {'method':['DELETE']})  
  26.  
  27.     @staticmethod  
  28.     @wsgify  
  29.     def _dispatch(req):  
  30.         match = req.environ['wsgiorg.routing_args'][1]  #获取URL解析结果  
  31.         if not match:   #如果解析结果为空,则输出错误信息  
  32.             return webob.exc.HTTPNotFound()  
  33.   
  34.         app = match['controller']   #获取URL对应的controller实例  
  35.         return app  
  36.   
  37. def app_factory(global_config, **local_config):  
  38.     return Router()  


(1)instance应用程序对应的工厂方法为routers包的app_factory方法。app_factory方法返回一个Router对象。工厂方法必须返回一个函数的实例。

 

Router类中必须实现__call__方法。  Router类的__call__方法的定义。返回router变量,其实也是一个可调用的实例。

__call__是在服务器收到HTTP请求时被调用。当服务器调用__call__方法时,会转而调用router方法。

(2)Router类的初始化方法(两件事情)

 

  • 初始化mapper成员变量。mapper成员变量是routes包的Mapper标准类,主要功能是 创建Mapper对象,用于URL解析。 然后,调用自身的add_routes方法往Mapper对象中注册URL映射
  • 初始化router成员变量。 (路由匹配,修改环境变量,实现分发) router成员变量的功能将HTTP请求分发给相应的方法进行处理。router成员变量是一个 RoutesMiddleware对象。初始化需要提供两个参数-----dispatch方法和mapper变量。dispatch方法是Router类的静态方法,功能是实现HTTP请求的分发。      

 

RoutesMiddleware对象(可调用的实例)执行过程:首先通过Mapper对象解析信息(匹配路由,修改环境变量),讲解析结果传递给dispatch方法。

(3)addroutes方法

addroutes方法共添加了5条URL路由,各条URL映射对应的功能参见上表。在添加URL映射时,调用mapper变量的connect方法。

Mapper类的connect方法用法:

<URL>:请求的URL

<controller>:处理HTTP请求的controller对象,这个对象必须是可调用的(实现了__call__方法)

<action>:指的是处理HTTP请求的方法名。所有定义的<action>对应的方法都在controller类中

<method-list>:是HTTP请求的方法列表。在RESTful API中,定义了GET、POST、PUT、DEAD和DELETE等方法,不同的方法对应资源的某项操作

action是一个字符串,指定的是方法名,而不是方法的实例。

(4)dispatch方法

  首先获取URL的解析结果(通过mapper类对象进行匹配路由,修改环境变量)。如果结果为空,说明相应的URL没有在mapper对象中注册,输出错误信

息。如果不为空,返回URL对应的controller对象。由于controller对象是可调用的,最终WSGI服务会调用controller对象的__call__方法处理HTTP请

求。  (dispatch方法只是将URL请求进行分发给相应的controller,并没有具体到方法)

 

3、controller类的实现

 

[python]  view plain  copy
  1. import uuid  
  2. from webob import Request,Response  
  3. import simplejson  
  4. from webob.dec import wsgify  
  5.   
  6. class Controller(object):  
  7.     def __init__(self):  
  8.         self.instances = {}  
  9.         for i in range(3):  
  10.             inst_id = str(uuid.uuid4())  
  11.             self.instances[inst_id] = {'id' : inst_id, 'name' : 'inst-' + str(i)}  
  12.         print self.instances  
  13.  
  14.     @wsgify  
  15.     def create(self, req):  
  16.         print req.params  
  17.         name = req.params['name']  
  18.         if name:  
  19.             inst_id = str(uuid.uuid4())  
  20.   
  21.             inst = {'id' : inst_id, 'name' : name}  
  22.             self.instances[inst_id] = inst  
  23.             return {'instance' : inst}  
  24.  
  25.     @wsgify  
  26.     def show(self, req, instance_id):  
  27.         inst = self.instances.get(instance_id)  
  28.         return {'instance' : inst}  
  29.  
  30.     @wsgify  
  31.     def index(self, req):  
  32.         return {'instances': self.instances.values()}  
  33.  
  34.     @wsgify  
  35.     def delete(self, req, instance_id):  
  36.         if self.instances.get(instance_id):  
  37.                 self.instances.pop(instance_id)  
  38.     @wsgify  
  39.     def update(self, req, instance_id):  
  40.         inst = self.instances.get(instance_id)  
  41.         name = req.params['name']  
  42.         if inst and name:  
  43.             inst['name'] = name  
  44.             return {'instance': inst}  
  45.  
  46.     @wsgify  
  47.     def __call__(self, req):  
  48.         arg_dict = req.environ['wsgiorg.routing_args'][1] #获取URL解析结果  
  49.         action = arg_dict.pop('action')  #获取处理的方法  
  50.         del arg_dict['controller']   #删除 controller项,剩下的都是参数列表  
  51.   
  52.         method = getattr(self, action)  #搜索controller类中定义的方法  
  53.         result = method(req, **arg_dict)  #调用方法,处理HTTP请求  
  54.   
  55.         if result is None:   #无返回值  
  56.             return Response(body='',status='204 Not Found',headerlist=[('Content-Type','application/json')])  
  57.         else:  #有返回值  
  58.             if not isinstance(result, str):  
  59.                 result = simplejson.dumps(result) #将返回值转化为字符串  
  60.             return result  

(1)准备参数   (2)查找并执行controller中相应的方法  (3)返回结果

 

定义的 /instances/{instance_id}这样的URL。当Router的mapper对象解析这样的URL时,会把{instance_id}解析成一个参数。

例如:对于/instances/123 这条url,解析完毕后,会在以上代码的arg_dict字典中产生 {'instance_id':123}。

create方法:

功能是创建一条虚拟机记录,其对应的URL是 POST/instances。在发送请求时,必须提供name字段来指定虚拟机名。 

 

[python]  view plain  copy
  1. def create(self, req):  
  2.         print req.params  
  3.         name = req.params['name']   #获取虚拟机名  
  4.         if name:  
  5.             inst_id = str(uuid.uuid4())  #自动生成UUID  
  6.   
  7.             inst = {'id' : inst_id, 'name' : name}  #构造虚拟机信息元祖  
  8.             self.instances[inst_id] = inst   #添加虚拟机记录  
  9.             return {'instance' : inst}  

可使用req.param来获取客户端提交的数据。

 

代码测试:

执行python WSGIService.py,便可启动WSGI服务。WSGI服务启动后,可在另一个终端进行测试。对所有的URL进行测试:

(1)、GET /instances

 

WSGI服务启动时,会自动生成3条虚拟机记录。输出的结果,便是生成的3条虚拟机记录信息。

(2)、POST /instances

 

以上命令创建名为new-inst的虚拟机记录。

(3)、GET /instances/{instance_id} 

 

[python]  view plain  copy
  1. curl -H 'X-Auth-Token:open-sesame' -X GET > 127.0.0.1:8000/instances/c81e83fe-ae90-44a3-89e7-20918dfa9aef  

 

{instance_id}是要查询的虚拟机的id,需要根据自己的实际情况修改。可以通过GET /instances来查看所有虚拟机记录的id

(4)、PUT /instances/{instance_id} 

 

[python]  view plain  copy
  1. curl -H 'X-Auth-Token:open-sesame' -X PUT --data 'name=new-inst2' > 127.0.0.1:8000/instances/c81e83fe-ae90-44a3-89e7-20918dfa9aef  

 更名虚拟机

 

(5)、DELETE /instances/{instance_id}

 

[python]  view plain  copy
  1. curl -H 'X-Auth-Token:open-sesame' -X DELETE  > 127.0.0.1:8000/instances/c81e83fe-ae90-44a3-89e7-20918dfa9aef  

 删除虚拟机

 

 

RESTful API

1、使用PasteDeploy配置WSGI服务

(1)、RESTful API底层是HTTP协议。传统HTTP协议基础上,明确定义各种HTTP方法的意义。 RESTful API定义的标准方法。

 

(2)、RESTful API使用PasteDeploy定制WSGI服务。WSGI服务的功能可以通过配置文件配置。在配置文件中可以定义app、filter、pipeline和composite等部件,

   

 

(3)、app和filter都须对应一个工厂方法。工厂方法通常有如下参数:

def factory(global_config, **local_config)

global_config参数保存从客户端传入的参数,例如HTTP消息体、客户上下文信息等。

local_config参数保存了在配置文件中设置的参数。

每个工厂方法最终会返回一个处理对应的app和filter HTTP请求的方法实例。处理app请求的方法实例通常有如下参数:  def app(request): request参数保存HTTP请求的上下文信息。

处理filter请求的方法实例通常有如下参数:def filter(request, app):其中request参数保存HTTP请求的上下文,app参数指定从当前过滤器的下一个过滤器(或应用程序)开始,到最后一个应用程序位置所形成的的子pipeline的实例。

2、Mapper.connect方法的调用

一个完整的WSGI服务,通常需要解析和处理多条URL。routes标准包中,定义了Mapper类来实现URL映射的管理。可以通过调用Mapper对象的connect方法来向WSGI服务注册URL映射。Mapper对象的connect方法一个调用示例。

mapper.connect(url,controller=controller, action=action, conditions = condition)

(1)、url参数指定的是请求的URL。两种形式,/<resources>类型的URL对应的是集合的操作,/<resources>/<resource-id>类型的URL对应的是成员操作。<resources>是资源的集合名,<resource-id>是资源的UUID。

(2)、controller指定的是处理HTTP请求的controller对象

(3)、action参数指定controller对象中处理HTTP请求的方法

(4)、condition参数指定服务器接收和处理HTTP请求的条件。通常在condition中指定HTTP请求的方法。例如:conditions = dict(method=[‘POST’]),指定只接受HTTP POST请求,conditions =dict(method=[‘POST’,‘PUT’])指定只接收HTTP POST和PUT请求。


转http://blog.csdn.net/li_101357/article/details/52801596


本文转自茄子_2008博客园博客,原文链接:http://www.cnblogs.com/xd502djj/p/7570794.html,如需转载请自行联系原作者。



目录
相关文章
|
27天前
|
JSON JavaScript 前端开发
深入浅出Node.js:从零开始构建RESTful API
在数字化时代的浪潮中,后端开发作为连接用户与数据的桥梁,扮演着至关重要的角色。本文将引导您步入Node.js的奇妙世界,通过实践操作,掌握如何使用这一强大的JavaScript运行时环境构建高效、可扩展的RESTful API。我们将一同探索Express框架的使用,学习如何设计API端点,处理数据请求,并实现身份验证机制,最终部署我们的成果到云服务器上。无论您是初学者还是有一定基础的开发者,这篇文章都将为您打开一扇通往后端开发深层知识的大门。
41 12
|
1月前
|
XML JSON 缓存
深入理解RESTful API设计原则与实践
在现代软件开发中,构建高效、可扩展的应用程序接口(API)是至关重要的。本文旨在探讨RESTful API的核心设计理念,包括其基于HTTP协议的特性,以及如何在实际应用中遵循这些原则来优化API设计。我们将通过具体示例和最佳实践,展示如何创建易于理解、维护且性能优良的RESTful服务,从而提升前后端分离架构下的开发效率和用户体验。
|
1月前
|
JSON 缓存 测试技术
构建高效RESTful API的后端实践指南####
本文将深入探讨如何设计并实现一个高效、可扩展且易于维护的RESTful API。不同于传统的摘要概述,本节将直接以行动指南的形式,列出构建RESTful API时必须遵循的核心原则与最佳实践,旨在为开发者提供一套直接可行的实施框架,快速提升API设计与开发能力。 ####
|
1月前
|
JSON API 开发者
深入理解RESTful API设计原则
在数字化时代,API已成为连接不同软件应用的桥梁。本文旨在探讨RESTful API设计的基本原则和最佳实践,帮助开发者构建高效、可扩展的网络服务接口。通过解析REST架构风格的核心概念,我们将了解如何设计易于理解和使用的API,同时保证其性能和安全性。
|
1月前
|
JSON 缓存 JavaScript
深入浅出:使用Node.js构建RESTful API
在这个数字时代,API已成为软件开发的基石之一。本文旨在引导初学者通过Node.js和Express框架快速搭建一个功能完备的RESTful API。我们将从零开始,逐步深入,不仅涉及代码编写,还包括设计原则、最佳实践及调试技巧。无论你是初探后端开发,还是希望扩展你的技术栈,这篇文章都将是你的理想指南。
|
1月前
|
监控 安全 API
深入浅出:构建高效RESTful API的最佳实践
在数字化时代,API已成为连接不同软件和服务的桥梁。本文将带你深入了解如何设计和维护一个高效、可扩展且安全的RESTful API。我们将从基础概念出发,逐步深入到高级技巧,让你能够掌握创建优质API的关键要素。无论你是初学者还是有经验的开发者,这篇文章都将为你提供实用的指导和启示。让我们一起探索API设计的奥秘,打造出色的后端服务吧!
|
1月前
|
JavaScript NoSQL API
深入浅出Node.js:从零开始构建RESTful API
在数字化时代的浪潮中,后端开发如同一座灯塔,指引着数据的海洋。本文将带你航行在Node.js的海域,探索如何从一张白纸到完成一个功能完备的RESTful API。我们将一起学习如何搭建开发环境、设计API结构、处理数据请求与响应,以及实现数据库交互。准备好了吗?启航吧!
|
1月前
|
JSON API 数据格式
探索后端开发:从零构建简易RESTful API
在数字时代的浪潮中,后端开发如同搭建一座桥梁,连接着用户界面与数据世界。本文将引导读者步入后端开发的殿堂,通过构建一个简易的RESTful API,揭示其背后的逻辑与魅力。我们将从基础概念出发,逐步深入到实际操作,不仅分享代码示例,更探讨如何思考和解决问题,让每一位读者都能在后端开发的道路上迈出坚实的一步。
|
1月前
|
存储 API 数据库
使用Python和Flask构建简单的RESTful API
使用Python和Flask构建简单的RESTful API
|
1月前
|
JSON 关系型数据库 测试技术
使用Python和Flask构建RESTful API服务
使用Python和Flask构建RESTful API服务