项目描述

1、为客制化的Web API接口建立可重用的对象

2、可以与Requests,asyncio和Twisted

快速开始

Uplink把你的HTTP API接口转化成一个Python的类

from uplink import Consumer, get, headers, Path, Query

class GitHub(Consumer):

   @get("users/{user}/repos")
   def get_repos(self, user: Path, sort_by: Query("sort")):
      """获取到用户的公共存储库资源"""

建立一个可以与webservice交互的实例:

github = GitHub(base_url="https://api.github.com/")

base_url是整个uplink架构的基础,指向需要对接的API的域名,比如我是在写django项目,可以直接将这个参数集成到settings文件内,包括可以建立字典参数可选化等等。

现在,执行一个HTTP请求已经简单的变成调用一个方法。

repos = github.get_repos("octocat", sort_by="created")

前面一个参数"octocat",对应的就是类里对应方法的get(也可能是post或者其他装饰上)的user参数,后面的就不必多说,sort_by的传参。这里形成的新url其实就是

https://api.github.com/users/octocat/repos/?sort=created

返回的是一个友好的requests.Response对象

print(repos.json())
# Output: [{'id': 64778136, 'name': 'linguist', ...

这里的.json()实际上就是一个反序列化的过程。

如果想发送一个非阻塞的请求,uplink支持使用aiohttp和twisted。

使用装饰器和功能参数注解来描述HTTP request:

  1、URL参数的替代和查询参数的支持

  2、将响应体转换成Python的对象(等等,使用marshmallow或者一个客制化的转换)

  3、JSON、URL编码和多重庆球体和文件上传

  4、注入功能像中间件来使用客制化的返回和错误处理

安装

pip3 install uplink

静态请求处理

方法装饰器描述与所有Consumer方法的所有调用相关的请求属性。

例如下面的GitHub API consumer:

class GitHub(uplink.Consumer):
    @uplink.timeout(60)
    @uplink.get("/repositories")
    def get_repos(self):

调用了timeout函数,get_repos方法将会构建HTTP请求然后等带60秒,如果服务器还没有在这个时间之前没有返回就会放弃。由于方法注释仅仅是装饰器,您可以堆叠一个在另一个之上:

class GitHub(uplink.Consumer):
    @uplink.headers({"Accept": "application/vnd.github.v3.full+json"})
    @uplink.timeout(60)
    @uplink.get("/repositories")
    def get_repos(self):

动态请求处理

对于一个常规的项目而言,方法参数驱动着一个方法的动态行为;一个方法的输出通常依赖于它的输入。在uplink里面,函数参数使HTTP请求参数化,你可以标识请求的动态部分通过适当的申明这些参数。为了说明,在下面代码中的get_user()方法,我们已经申明了参数username作为URL占位符的替代, 使用Path来注释

class GitHub(uplink.Consumer):
    @uplink.get("users/{username}")
    def get_user(self, username: uplink.Path("username")): pass

通过consumer实例来调用这个方法

github.get_user(username="prkumar")

创建的HTTP请求的url是以users/prkumar结尾的。

请求方法

uplink提供装饰器将任何方法转化到请求的定义中。这些装饰器提供请求方法和相关的url包含get、post、put、patch、和delete

相关的url资源被规定在装饰器内部

@get("users/list")

你也可以定义查询参数在url里面

@get("users/list?sort=desc")

另外请求方法必须绑定到Consumer的子类

class MyApi(Consumer):
    @get("users/list")
    def list_users(self)

操纵URL

一个请求的url使用url模板参数可以被动态的更新。一个简单的URL参数是一个包含数字和字母的的字符串被{}两个花括号包围。

若要讲参数与方法的参数匹配,则将参数的名称与字母数字字符串匹配,如下:

@get("group/{id}/users")
def group_list(self, id): pass

或者使用Path注释

@get("group/{id}/users")
def group_list(self, group_id: Path("id")): pass

也可以添加Query参数

@get("group/{id}/users")
def group_list(self, group_id: Path("id"), sort: Query): pass

对于复杂的查询参数组合,可以使用映射

@get("group/{id}/users")
def group_list(self, group_id: Path("id"), options: QueryMap): pass

请求体

可以指定一个参数的值作为HTTP请求体,并用Body标注:

@post("users/new")
def create_user(self, user: Body): pass

这个注释与关键字参数(由**前缀表示)可以很好地工作:

@post("users/new")
def create_user(self, **user_info: Body): pass

表单编码,Multipart和JSON

方法也可以被申明来发送表单编码, multipart和json数据

表单编码数据在装饰form_url_encoded方法的时候被发送,每一对键值对都使用Field进行注解:

@form_url_encoded
@post("user/edit")
def update_user(self, first_name: Field, last_name: Field): pass

Multipart 在被multipart函数装饰的时候使用,内容的申明使用Part注解

@multipart
@put("user/photo")
def update_user(self, photo: Part, description: Part): pass

JSON数据同理在被json函数装饰的时候发送。Body注解声明json的有效载荷

@uplink.json
@uplink.patch("/user")
def update_user(self, **user_info: uplink.Body):

操纵头部

可以使用headers装饰器发送静态的请求头信息

@headers({
    "Accept": "application/vnd.github.v3.full+json",
    "User-Agent": "Uplink-Sample-App"
})
@get("users/{username}")
def get_user(self, username): pass

headers也可以被用来当做类的装饰器,当每一个请求都需要被添加这个装饰的时候

@headers({
    "Accept": "application/vnd.github.v3.full+json",
    "User-Agent": "Uplink-Sample-App"
})
class GitHub(Consumer):
    ....

请求头可以被动态更新当使用Header方法参数注解

@get("user")
def get_user(self, authorization: Header):

反序列化响应体

uplink让转换Httpp响应体到数据模型对象变得简单并且是可选择的,无论是使用uplink内置库的函数支持比如:marshmallow(可以查看uplink.converters.MarshmallowConverter)或者使用uplink.loads来写客制化的转换逻辑满足自己独特的要求。

最基础的,你需要使用装饰器uplink.returns模块标注想要返回的类型.而当你着手与JSON响应的API的时候uplink.json可以很好的完成。

@returns.json(User)
@get("users/{username}")
def get_user(self, username): pass

Python3的用户另外还可以使用返回类型的暗示

@returns.json
@get("users/{username}")
def get_user(self, username) -> User: pass

最后的步骤是注册一个将HTTP响应转换成预期返回类型的策略。因此,uplink.loads()可以注册一个函数,该函数可以处理特定类及其子类的反序列化。

from models import ModelBase  # 所有模型类型的基类,包含上面的User

# 告诉uplink如何将JSON响应反序列化成我们的模型类
@loads.install  #使这个对所有consumer实例有效
@loads.from_json(ModelBase)
def load_model_from_json(model_cls, json_obj):
    return model_cls.from_json(json_obj)

这一步不是必须的如果你定义你的数据模型对象使用uplink的内置库支持比如marshmallow

订制响应跟错误处理

想要订制响应跟错误处理,需要装饰response_handler或者error_handler装饰器。

例如,方法returns_success()定义如下,它是一个响应处理输出,无论请求是否成功。

@uplink.response_handler
def returns_success(response):
    return response.status == 200

现在returns_success()可以被用来像装饰器一样使用,来注入客制化的请求处理到任何请求方法中。

@returns_success
@put("/todos")
def create_todo(self, title):

为了使其作用于所有的请求方法的Consumer子类中,也可以简单的使用注册处理的方法使其作为一个类装饰器

@returns_success
class TodoApp(uplink.Consumer):
    ...

相似的,error_handler被注册来装饰方法。当需要使用这个请求方法的时候调用它。应用此请求方法,当底层HTTP客户端无法执行请求时调用这些处理程序:

@error_handler
def raise_api_error(exc_type, exc_val, exc_tb):
    # wrap client error with custom API error
    ...

值得注意的是,装饰器可以置于另一个之上链接他们的行为

@raise_api_error
@returns_success
class TodoApp(uplink.Consumer):
    ...

关于__init__()

函数注释(如Query和Header)可以与consumer子类的构造函数参数一起使用。当创建新的consumer实例时,这些参数的值应用于通过该实例所做的所有请求。

例如下面的consumer接受API访问token作为结构化参数的access_token:

class GitHub(uplink.Consumer):

    def __init__(self, access_token: uplink.Query):
        ...

    @uplink.post("/user")
    def update_user(self, **info: Body):
        """Update the authenticated user"""

现在,所有这个consumer类生成的实例请求将会在初始化的时候被access token认证

github = TodoApp("my-github-access-token")

github.update_user(bio="Beam me up, Scotty!")

_inject()请求属性

作为一个可选择的__init__的参数,你可以获得相似的行文和更多的控制通过使用Consumer._inject()方法. 通过这个方法,你可以计算请求的属性在普通的python方法中。

class TodoApp(uplink.Consumer):

    def __init__(self, username, password)
        # Create an access token
        api_key = create_api_key(username, password)

        # Inject it.
        self._inject(uplink.Query("api_key").with_value(api_key))

跟之前的注解风格相似,被_inject()添加的请求属性可以作用于全部的consumer实例的请求。

最后看一个整体实例:

此实例来自于一个django项目,url配置于django的settings文件中

看一下调用

Python 转路由之uplink的更多相关文章

  1. python django 路由系统

    URL配置                        基本格式: from django.conf.urls import url urlpatterns = [ url(正则表达式, views ...

  2. python - django (路由)

    # """ # Django路由分配系统简介: Django project目录中的urls.py文件中, 以Python [ ( ) ]的数据类型记录了可以访问到该站点 ...

  3. Python Djan 路由对应的名称

    路由关系命名 对URL路由关系进行命名,以后可以根据此名称生成自己想要的URL 1. url(r'fdsafdsaeeeee',views.index, name='hello') #给这个url后面 ...

  4. python Django 路由之正则表达式

    一.路由系统,URL 1. url(r'^index',views.index) #默认的                  url(r'^home',views.Home.as_view()) # ...

  5. python实现路由追踪,并生成追踪图片

    #!/usr/bin/env python # -*- coding: utf-8 -*- import os,sys,time,subprocess import warnings,logging ...

  6. python简单路由系统

    # 输入模块名/函数 url = input('请输入网址:') module,func = url.split('/') m = __import__('lib.'+module,fromlist= ...

  7. Python Django 路由分发

    mysite1 为一个django工程 cmdb为一个项目 dashboard为一个项目 在mysite1工程下的urls.py中定义如下: from django.conf.urls import ...

  8. 让python bottle框架支持jquery ajax的RESTful风格的PUT和DELETE等请求(新方法)

    通过上篇博文的方法处理后,进入代码调试后发现ajax获取不了服务器端返回的数据,度娘后发现原来AJAX的OPTIONS请求方式是状态类型查询,即向服务器提交信息后不返回任何信息,只将执行状态(200状 ...

  9. 用python控制路由器

    前言 最近用爬虫爬豆瓣上的资料,无奈总是被封,agent伪装和cookie修改这些都用过了,可惜都起不了什么作用,到了一定次数,还是会返回403.想用代理ip,无奈免费的太不稳定,买收费的又有点没必要 ...

随机推荐

  1. Leetcode: Longest Substring with At Most K Distinct Characters && Summary: Window做法两种思路总结

    Given a string, find the length of the longest substring T that contains at most k distinct characte ...

  2. Ant编译提示“Unsupported major.minor version 52.0”

    今天在使用Ant编译build.xml文件时报错"java.lang.UnsupportedClassVersionError:com/sun/tools/javac/Main : Unsu ...

  3. POJ 1679 The Unique MST --Kruskal应用

    这题可以用次小生成树解,这里用Kruskal算法来做.每条边除维护u,v,w外,还维护: used:表示这条边是否加过 eq:表示有没有与这条边相等的边 del:删除标记,以便删边之用 如果对于一个最 ...

  4. windows消息钩子

    1.消息钩子的概念: Windows应用程序是基于消息驱动的,不论什么线程仅仅要注冊窗体类都会有一个消息队列用于接收用户输入的消息和系统消息.为了拦截消息,Windows提出了钩子的概念.钩子(Hoo ...

  5. Codeforces Round #334 (Div. 1) C. Lieges of Legendre

    Lieges of Legendre 题意:有n堆牛,每堆有ai头牛.两个人玩一个游戏,游戏规则为: <1>从任意一个非空的堆中移走一头牛: <2>将偶数堆2*x变成k堆,每堆 ...

  6. LIB文件和DLL文件的作用

    (1)lib是编译时需要的,dll是运行时需要的.如果要完成源代码的编译,有lib就够了.如果也使动态连接的程序运行起来,有dll就够了.在开发和调试阶段,当然最好都有.(2)一般的动态库程序有lib ...

  7. 利用C#实现分布式数据库查询

    随着传统的数据库.计算机网络和数字通信技术的飞速发展,以数据分布存储和分布处理为主要特征的分布式数据库系统的研究和开发越来越受到人们的关注.但由于其开发较为复杂,在一定程度上制约了它的发展.基于此,本 ...

  8. NetFPGA-1G-CML点亮 LED

    前言 用vivado建立工程的时候选择的型号为:XC7K325tffg676-1 在以下代码文件中,仿真与设计都没有问题.在xdc文件中的时钟约束与锁相环配置中还存在问题,没有寻找到解决办法 使用手册 ...

  9. 转载:MySQL EXPLAIN 命令详解学习

    转载自:https://blog.csdn.net/mchdba/article/details/9190771 MySQL EXPLAIN 命令详解 MySQL的EXPLAIN命令用于SQL语句的查 ...

  10. wincc项目移植和复制解决办法

    wincc项目复制 wincc项目不支持直接复制,部分的后台数据库在活跃状态,直接复制wincc项目,会提示跳过活跃状态的数据库,当跳过活跃数据库时,复制的项目也是无效的.在wincc项目管理器中打不 ...