Encapsulation and calling of Python3 API

1. API encapsulation

API (Application Programming Interface, application programming interface) are some predefined functions, the purpose is to provide applications and developers with the ability to access a set of routines based on a piece of software or hardware, without having to access the source code, or understand the inner workings Mechanism details.

The interface of Python3 is WSGI: Web Server Gateway Interface.

The WSGI interface definition is very simple, it only requires web developers to implement a function to respond to HTTP requests. Let's take a look at the simplest web version Hello, web!:

def application(environ, start_response):
    start_response('200 OK', [('Content-Type', 'text/html')])
    return [b'<h1>Hello, web!</h1>']

The above application() function is an HTTP processing function that conforms to the WSGI standard, and it receives two parameters:

  • environ: a dict object containing all HTTP request information;

  • start_response: A function that sends an HTTP response.

In the application() function, call:

start_response('200 OK', [('Content-Type', 'text/html')])

The Header of the HTTP response is sent. Note that the Header can only be sent once, that is, start_response()the function can only be called once. start_response()The function receives two parameters, one is the HTTP response code, and the other is a set of HTTP Headers represented by a list, and each Header is represented by a tuple containing two strs.

Normally, the Content-Type header should be sent to the browser. Many other commonly used HTTP headers should also be sent.

Then, the return value of the function b'<h1>Hello, web!</h1>'will be sent to the browser as the Body of the HTTP response.

With WSGI, what we care about is how to get the HTTP request information from the environ dict object, then construct HTML, send the Header through start_response(), and finally return the Body.

The entire application() function itself does not involve any part of HTTP parsing, that is to say, the underlying code does not need to be written by ourselves, we are only responsible for considering how to respond to requests at a higher level.

But wait, how is this application() function called? If we call it ourselves, we cannot provide the two parameters environ and start_response, and the returned bytes cannot be sent to the browser.

So the application() function must be called by the WSGI server. There are many servers that conform to the WSGI specification, and we can choose one to use. But now, we just want to test as soon as possible that the application() function we wrote can really output HTML to the browser, so we must quickly find the simplest WSGI server and run our web application.

Python3 has a built-in WSGI server. This module is called wsgiref, which is a reference implementation of a WSGI server written in pure Python. The so-called "reference implementation" means that the implementation fully complies with the WSGI standard, but does not consider any operational efficiency, and is only used for development and testing.

Run the WSGI service

Let's first write hello.py to implement the WSGI processing function of the web application:

# hello.py

def application(environ, start_response):
    start_response('200 OK', [('Content-Type', 'text/html')])
    return [b'<h1>Hello, web!</h1>']

Then, write a server.py responsible for starting the WSGI server and loading the application() function:

# server.py
# 从wsgiref模块导入:
from wsgiref.simple_server import make_server
# 导入我们自己编写的application函数:
from hello import application

# 创建一个服务器,IP地址为空,端口是8080,处理函数是application:
httpd = make_server('', 8080, application)
print('Serving HTTP on port 8080...')
# 开始监听HTTP请求:
httpd.serve_forever()

operation result:

  • Start WSGI

    Geek-Mac:Downloads zhangyi$ python3 server.py 
    Serving HTTP on port 8080...
  • access API

    Geek-Mac:Downloads zhangyi$ curl "localhost:8080/"
    <h1>Hello, web!</h1>Geek-Mac:Downloads zhangyi$

This is the simplest WSGI application, and then write a simple program to test the API yourself in daily work

example

api.py

#!/usr/bin/env python3
# -*- coding: UTF-8 -*-

import json
# 导入 urllib.parse 模块的 parse_qs 方法
from urllib.parse import parse_qs
from wsgiref.simple_server import make_server


def api(app):

    def application(environ, start_response):

        start_response('200 OK', [('Content-Type', 'text/html')])
        # 获取当前get请求的所有数据,返回是string类型
        parse = parse_qs(environ['QUERY_STRING'])
        data = json.dumps(app(parse))

        # 返回值是 UTF-8
        return [data.encode('utf-8')]

    def run():

        httpd = make_server('', 8080, application)
        print("Serving HTTP on port 8080 ...")
        httpd.serve_forever()

    # 外部模块调用才执行
    if __name__ != "__main__":
        run()

app.py

#!/usr/bin/env python3
# -*- coding: UTF-8 -*-

# API 调用实例
# http://127.0.0.1:8080/?name=Geek&user=root

# 导入 api 模块的 api 方法,当然也可以将 api 模块做成一个包,方便调用
from api import api


# 使用装饰器的形式调用函数
@api
def app(parse):

    # 使用 urllib.parse 模块的 parse_qs.get 方法获取 url 中字段的值
    name = parse.get('name', [''])[0]
    user = parse.get('user', [''])[0]

    # 将获取的值写到字典中
    data = {'name': name, 'user': user}

    return data

operation result:

  • Start WSGI

    Geek-Mac:API zhangyi$ python3 app.py 
    Serving HTTP on port 8080 ...
  • access API

    Geek-Mac:API zhangyi$ curl "http://127.0.0.1:8080/?name=Geek&user=root"
    {"name": "Geek", "user": "root"}Geek-Mac:API zhangyi$

The biggest advantage of using a decorator is that it reduces the complexity of the program. We only need to care about the functions we write.  app Finally, using one above the function  @api can make the program run directly, which greatly speeds up the development efficiency.

2. API call

The API call can use the module that comes with Python3  urllib. Here is a more useful third-party module  requests.

#!/usr/bin/env python3
# -*- coding: UTF-8 -*-

# 安装requests ==> sudo pip3 install requests

import requests


# 调用 API 的 GET 请求
URL = "http://127.0.0.1:8080/?name=Geek&user=root"
data = requests.get(url = URL)

# 获取返回状态
print (data.status_code)
# 获取返回URL
print (data.url)
# 获取返回数据
print (data.text)
# 获取返回 json 解析数据
print (data.json())

operation result:

Geek-Mac:Downloads zhangyi$ python3 API.py 
200
http://127.0.0.1:8080/?name=Geek&user=root
{"name": "Geek", "user": "root"}
{'name': 'Geek', 'user': 'root'}

This is just  requeststhe simplest GET usage, as well as POST usage, dictionary parameter passing and other more detailed usages, please visit the official website: http://cn.python-requests.org/zh_CN/latest/

3. API writing specification REST

It can be summed up in one sentence: REST is the architectural design guiding principle that all web applications should abide by.

Representational State Transfer, the translation is "representational state transfer", Wikipedia has a detailed description: https://zh.wikipedia.org/wiki/Representational State Transfer. 

Resource-oriented is the most obvious feature of REST, a set of different operations for the same resource. A resource is an abstract concept that can be named on the server. Resources are organized around nouns, and the first thing to focus on is nouns. REST requires that various operations on resources must be performed through a unified interface. Only a limited set of operations can be performed on each resource. (7 HTTP methods: GET/POST/PUT/DELETE/PATCH/HEAD/OPTIONS)

What are RESTful APIs?

An API that conforms to the REST architecture design.

Summarize

An API that conforms to the REST design standard, that is, a RESTful API. The standards and guidelines followed by the REST architecture design are the performance of the HTTP protocol. In other words, the HTTP protocol is a design pattern belonging to the REST architecture. For example, stateless, request-response.

4. RESTful API Design Guidelines

Reprinted from Ruan Yifeng's blog: http://www.ruanyifeng.com/blog/2014/05/restful_api

The web application is divided into two parts, the front end and the back end. The current development trend is that front-end devices emerge in endlessly (mobile phones, tablets, desktop computers, other special-purpose devices...).

Therefore, there must be a unified mechanism to facilitate communication between different front-end devices and the back-end. This has led to the popularity of API architecture, and even the design idea of ​​"API First". RESTful API is a relatively mature set of API design theory for Internet applications. I wrote an article "Understanding RESTful Architecture" before to explore how to understand this concept.

Today, I will introduce the design details of RESTful API and discuss how to design a reasonable and easy-to-use API.

1. Agreement

The communication protocol between the API and the user always uses the HTTPs protocol.

2. Domain name

The API should be deployed under a dedicated domain name as much as possible.

https://api.example.com

If it is determined that the API is very simple and there will be no further expansion, it can be considered to be placed under the main domain name.

https://example.org/api/

3. Versioning

The version number of the API should be put into the URL.

https://api.example.com/v1/

Another way is to put the version number in the HTTP header information, but it is not as convenient and intuitive as putting it in the URL. Github adopts this practice.

4. Path (Endpoint)

The path, also known as "endpoint", indicates the specific URL of the API.

In the RESTful architecture, each URL represents a resource (resource), so there can be no verbs in the URL, only nouns, and the nouns used often correspond to the table names of the database. Generally speaking, the tables in the database are "collections" of the same kind of records, so nouns in the API should also use plurals.

For example, if there is an API that provides zoo information, including information about various animals and employees, its path should be designed as follows.

https://api.example.com/v1/zoos
https://api.example.com/v1/animals
https://api.example.com/v1/employees

5. HTTP Verbs

Specific operation types for resources are represented by HTTP verbs.

Commonly used HTTP verbs are as follows (the corresponding SQL commands are in brackets).

GET(SELECT):从服务器取出资源(一项或多项)。
POST(CREATE):在服务器新建一个资源。
PUT(UPDATE):在服务器更新资源(客户端提供改变后的完整资源)。
PATCH(UPDATE):在服务器更新资源(客户端提供改变的属性)。
DELETE(DELETE):从服务器删除资源。

There are also two HTTP verbs that are not commonly used.

HEAD:获取资源的元数据。
OPTIONS:获取信息,关于资源的哪些属性是客户端可以改变的。
下面是一些例子。
GET /zoos:列出所有动物园
POST /zoos:新建一个动物园
GET /zoos/ID:获取某个指定动物园的信息
PUT /zoos/ID:更新某个指定动物园的信息(提供该动物园的全部信息)
PATCH /zoos/ID:更新某个指定动物园的信息(提供该动物园的部分信息)
DELETE /zoos/ID:删除某个动物园
GET /zoos/ID/animals:列出某个指定动物园的所有动物
DELETE /zoos/ID/animals/ID:删除某个指定动物园的指定动物

Six, filter information (Filtering)

If the number of records is large, it is impossible for the server to return them all to the user. The API should provide parameters and filter the returned results.

Below are some common parameters.

?limit=10:指定返回记录的数量
?offset=10:指定返回记录的开始位置。
?page=2&per_page=100:指定第几页,以及每页的记录数。
?sortby=name&order=asc:指定返回结果按照哪个属性排序,以及排序顺序。
?animal_type_id=1:指定筛选条件
参数的设计允许存在冗余,即允许API路径和URL参数偶尔有重复。比如,GET /zoo/ID/animals 与 GET /animals?zoo_id=ID 的含义是相同的。

7. Status Codes

The common status codes and prompt information returned by the server to the user are as follows (the HTTP verb corresponding to the status code is in square brackets).

200 OK - [GET]:服务器成功返回用户请求的数据,该操作是幂等的(Idempotent)。
201 CREATED - [POST/PUT/PATCH]:用户新建或修改数据成功。
202 Accepted - [*]:表示一个请求已经进入后台排队(异步任务)
204 NO CONTENT - [DELETE]:用户删除数据成功。
400 INVALID REQUEST - [POST/PUT/PATCH]:用户发出的请求有错误,服务器没有进行新建或修改数据的操作,该操作是幂等的。
401 Unauthorized - [*]:表示用户没有权限(令牌、用户名、密码错误)。
403 Forbidden - [*] 表示用户得到授权(与401错误相对),但是访问是被禁止的。
404 NOT FOUND - [*]:用户发出的请求针对的是不存在的记录,服务器没有进行操作,该操作是幂等的。
406 Not Acceptable - [GET]:用户请求的格式不可得(比如用户请求JSON格式,但是只有XML格式)。
410 Gone -[GET]:用户请求的资源被永久删除,且不会再得到的。
422 Unprocesable entity - [POST/PUT/PATCH] 当创建一个对象时,发生一个验证错误。
500 INTERNAL SERVER ERROR - [*]:服务器发生错误,用户将无法判断发出的请求是否成功。

See here for a complete list of status codes: https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html

8. Error handling

If the status code is 4xx, an error message should be returned to the user. Generally speaking, error is used as the key name in the returned information, and the error message is used as the key value.

{
    error: "Invalid API key"
}

Nine, return the result

For different operations, the results returned by the server to the user should meet the following specifications.

GET /collection:返回资源对象的列表(数组)
GET /collection/resource:返回单个资源对象
POST /collection:返回新生成的资源对象
PUT /collection/resource:返回完整的资源对象
PATCH /collection/resource:返回完整的资源对象
DELETE /collection/resource:返回一个空文档

10. Hypermedia API

The RESTful API is best to achieve Hypermedia, that is, to provide links in the returned results to other API methods, so that users can know what to do next without checking the documentation.

For example, when a user makes a request to the root directory of api.example.com, he will get such a document.

{"link": {
  "rel":   "collection https://www.example.com/zoos",
  "href":  "https://api.example.com/zoos",
  "title": "List of zoos",
  "type":  "application/vnd.yourformat+json"
}}

The above code indicates that there is a link attribute in the document, and the user will know what API to call next after reading this attribute. rel indicates the relationship between this API and the current URL (collection relationship, and the URL of the collection is given), href indicates the path of the API, title indicates the title of the API, and type indicates the return type.

The design of the Hypermedia API is called HATEOAS. Github's API is designed like this. Visiting api.github.com will get a list of URLs for all available APIs.

{
  "current_user_url": "https://api.github.com/user",
  "authorizations_url": "https://api.github.com/authorizations",
  // ...
}

As can be seen from the above, if you want to get the information of the current user, you should visit api.github.com/user, and then you will get the following results.

{
  "message": "Requires authentication",
  "documentation_url": "https://developer.github.com/v3"
}

The above code indicates that the server gives the prompt information and the URL of the document.

11. Others

(1) API authentication should use the OAuth 2.0 framework.

(2) The data format returned by the server should try to use JSON instead of XML.

Guess you like

Origin blog.csdn.net/onebound_linda/article/details/131914900