1500字范文,内容丰富有趣,写作好帮手!
1500字范文 > 使用Flask和Connexion构建和记录Python REST API

使用Flask和Connexion构建和记录Python REST API

时间:2022-09-07 20:24:02

相关推荐

使用Flask和Connexion构建和记录Python REST API

If you’re writing a web application, then you’re probably thinking about making HTTP calls to your server to get data to populate the dynamic parts of your application.

如果您正在编写Web应用程序,那么您可能正在考虑对服务器进行HTTP调用以获取数据以填充应用程序的动态部分。

The goal of this article is to show you how to use Python 3, Flask, and Connexion to build useful REST APIs that can include input and output validation, and provide Swagger documentation as a bonus. Also included is a simple but useful single page web application that demonstrates using the API with JavaScript and updating the DOM with it.

本文的目的是向您展示如何使用Python 3, Flask和Connexion构建有用的REST API,这些API可以包括输入和输出验证,并提供Swagger文档作为奖励。 还包括一个简单但有用的单页Web应用程序,该应用程序演示了如何将API与Jav​​aScript一起使用以及如何使用DOM更新DOM。

The REST API you’ll be building will serve a simple people data structure where the people are keyed to the last name, and any updates are marked with a new timestamp.

您将要构建的REST API将提供一个简单的人员数据结构,其中人员将被键入姓氏,所有更新都将标有新的时间戳。

This data could be represented in a database, saved in a file, or be accessible through some network protocol, but for us an in-memory data structure works fine. One of the purposes of an API is to decouple the data from the application that uses it, hiding the data implementation details.

这些数据可以表示在数据库中,也可以保存在文件中,或者可以通过某些网络协议访问,但是对于我们来说,内存中的数据结构可以正常工作。 API的目的之一是将数据与使用它的应用程序分离,从而隐藏数据实现细节。

Free Bonus:Click here to download a copy of the “REST API Examples” Guide and get a hands-on introduction to Python + REST API principles with actionable examples.

免费红利:单击此处下载“ REST API示例”指南的副本,并通过可行的示例获得有关Python + REST API原理的动手介绍。

什么是REST (What REST Is)

Before you get started creating an API server, I want to talk about REST a little bit. There’s lots of information about REST available through some quick Google searches, and my intent is not to duplicate that here.

在开始创建API服务器之前,我想先介绍一下REST。 通过快速的Google搜索,有很多关于REST的信息,我的目的不是在此重复。

I just want to share how I view REST and use it to build APIs. I see REST as a set of conventions taking advantage of the HTTP protocol to provide CRUD (Create, Read, Update, and Delete) behavior on things and collections of those things. The CRUD behavior maps nicely to the HTTP protocol method verbs like this:

我只想分享我如何查看REST并使用它来构建API。 我将REST看作是一组约定,它们利用HTTP协议为事物及其事物的集合提供CRUD(创建,读取,更新和删除)行为。 CRUD行为很好地映射到HTTP协议方法动词,如下所示:

You can perform these actions on a thing or resource. It’s useful to think about a resource as something a noun can be applied to: a person, an order for something, a person’s address. This idea of a resource lines up nicely with a URL (Unique Resource Locator).

您可以对事物或资源执行这些操作。 将资源视为名词可以应用于的东西是有用的:一个人,某物的命令,一个人的地址。 资源的想法与URL(唯一资源定位符)很好地结合在一起。

A URL should identify a unique resource on the web, something that will work with the same thing over and over again for the same URL. With these two ideas, we have a way to take common application actions on something uniquely identified on the web. This is a very useful way of working.

URL应该标识网络上的唯一资源,对于同一URL,可以重复使用同一资源的东西。 有了这两个想法,我们就可以对网络上唯一标识的内容采取常见的应用程序操作。 这是一种非常有用的工作方式。

This idea goes a long way towards creating clean APIs and performing the actions many applications want from the API.

这个想法对创建干净的API以及执行许多应用程序希望从API进行的操作大有帮助。

REST不是什么 (What REST Is Not)

Because REST is useful and helps map out how we might want to interact with a web based API, it’s sometimes used for things that don’t really fit well. There are lots of cases where what we want to do is perform some work or take an action directly. An example might be performing a string substitution, which granted is a silly thing to make an API for, but let’s go with it for now. Here’s a URL that might be constructed to provide this:

由于REST很有用,有助于确定我们可能希望如何与基于Web的API进行交互,因此有时将REST用于不太适合的事情。 在很多情况下,我们要做的是做一些工作或直接采取行动。 一个示例可能是执行字符串替换,这是制作API的愚蠢之举,但现在让我们开始吧。 这是可以用来提供此功能的URL:

/api/substituteString/<string>/<search_string>/<sub_string>/api/substituteString/<string>/<search_string>/<sub_string>

Here,stringis the string to make the substitution in,search_stringis the string to replace, andsub_stringis the string to replacesearch_stringwith. This can certainly be tied to some code in the server that does the intended work. But this has some problems in REST terms.

在这里,string是要替换的字符串,search_string是要替换的字符串,sub_string是要替换search_string的字符串。 当然,这可以绑定到服务器中完成预期工作的某些代码。 但这在REST方面存在一些问题。

One problem that comes to mind is that this URL doesn’t point to a unique resource, so what it returns is entirely dependent on the path variable sections. Also, there is no concept of CRUD against this URL. It really only needs one HTTP method, and the method name conveys nothing about the action to take.

想到的一个问题是此URL指向的不是唯一资源,因此它返回的内容完全取决于路径变量部分。 另外,没有针对此URL的CRUD的概念。 它实际上只需要一个HTTP方法,并且该方法的名称没有传达任何有关要执行的操作的信息。

As an API, it’s not great either. The meaning of the path variables is dependent on their position in the URL. This could be addressed by changing the URL to use a query string instead, like this:

作为API,它也不是很好。 路径变量的含义取决于它们在URL中的位置。 可以通过将URL更改为使用查询字符串来解决此问题,如下所示:

But the URL portion/api/substituteStringisn’t a thing (noun) or collection of things at all: it’s an action (verb).

但是URL部分/api/substituteString根本不是事物(名词)或事物的集合:它是动作(动词)。

This doesn’t fit well in the REST conventions, and trying to force it to do so makes for a poor API. What the above really represents is an RPC, or Remote Procedure Call. Thinking about this as an RPC makes much more sense.

这不太适合REST约定,而试图强制这样做会导致API较差。 以上内容真正代表的是RPC(远程过程调用)。 将其视为RPC更有意义。

The beauty is that both REST and RPC conventions can coexist in an API without any problems! By keeping in mind the intention of each, you can use both to compliment each other in your API design. There are many situations where it would be useful to perform CRUD operations on something. There are also many situations where it would be useful to take an action with a thing (as a parameter) but not necessarily affect the thing itself.

这样做的好处是,REST和RPC约定都可以共存于API中,而不会出现任何问题! 牢记每个人的意图,您可以在API设计中使用两者来相互补充。 在许多情况下,对某些对象执行CRUD操作会很有用。 在很多情况下,对事物执行操作(作为参数)会很有用,但不一定会影响事物本身。

People REST API (The People REST API)

For our example program, you’re going to create a REST API providing access to a collection of people with CRUD access to an individual person within that collection. Here’s the API design for the people collection:

对于我们的示例程序,您将创建一个REST API,以提供对某人集合的访问,而对该集合中的个人提供CRUD访问。 这是人员集合的API设计:

入门 (Getting Started)

First, you’ll create a simple web server using the Flask Micro Framework. To get started, create a directory where you can create the code. You should also work in a virtualenv so you can install modules later on, which you’ll need to do. In addition, create a templates directory.

首先,您将使用Flask Micro Framework创建一个简单的Web服务器。 首先,创建一个目录,您可以在其中创建代码。 您还应该在virtualenv中工作,以便以后可以安装模块,这将是您需要做的。 另外,创建一个模板目录。

The Python code below gets a very basic web server up and running, and responding withHello Worldfor a request for the home page:

下面的Python代码启动并运行了一个非常基本的Web服务器,并通过Hello World响应了对主页的请求:

from from flask flask import import ((FlaskFlask ,,render_templaterender_template))# Create the application instance# Create the application instanceapp app = = FlaskFlask (( __name____name__ , , template_foldertemplate_folder == "templates""templates" ))# Create a URL route in our application for "/"# Create a URL route in our application for "/"@app.route@app.route (( '/''/' ))def def homehome ():():"""""" This function just responds to the browser ULR This function just responds to the browser ULR localhost:5000/ localhost:5000/ :return: the rendered template 'home.html' :return: the rendered template 'home.html' """ """return return render_templaterender_template (( 'home.html''home.html' ))# If we're running in stand alone mode, run the application# If we're running in stand alone mode, run the applicationif if __name__ __name__ == == '__main__''__main__' ::appapp .. runrun (( debugdebug == TrueTrue ))

You should also create ahome.htmlin the templates folder, as this is what will be served to a browser when navigating to the URL'/'. Here is the contents of thehome.htmlfile:

您还应该在模板文件夹中创建一个home.html,因为这是导航到URL'/'时将提供给浏览器'/'。 这是home.html文件的内容:

You’ll notice the HTML file is namedhome.htmlrather thanindex.html. This is intentional because having anindex.htmlfile in the templates directory causes problems once you import the Connexion module in your program.

您会注意到HTML文件名为home.html而不是index.html。 这是有意的,因为一旦在程序中导入Connexion模块,模板目录中的index.html文件就会引起问题。

You can run your application with this command line in the directory containing theserver.pyfile with the Python VirtualEnv active:

您可以在包含server.py文件的目录中通过以下命令行运行您的应用程序,并激活Python VirtualEnv:

python server.pypython server.py

When you run this application, a web server will start on port 5000, which is the default port used by Flask. If you open a browser and navigate tolocalhost:5000, you should seeHello World!displayed. Right now, this is useful to see the web server is running. You’ll extend thehome.htmlfile later to become a full single page web application using the REST API you’re developing.

当您运行此应用程序时,Web服务器将在端口5000上启动,这是Flask使用的默认端口。 如果打开浏览器并导航到localhost:5000,则应该看到Hello World!显示。 现在,这对于查看Web服务器正在运行很有用。 稍后,您将使用正在开发的REST API将home.html文件扩展为一个完整的单页Web应用程序。

In your Python program, you’ve imported the Flask module, giving the application access to the Flask functionality. You then created a Flask application instance, theappvariable. Next, you connected the URL route'/'to thehome()function by decorating it with@app.route('/'). This function calls the Flaskrender_template()function to get thehome.htmlfile from the templates directory and return it to the browser.

在您的Python程序中,您已经导入了Flask模块,从而使应用程序可以访问Flask功能。 然后,您创建了Flask应用程序实例,即app变量。 接下来,通过使用@app.route('/')装饰 URL连接,将URL路由'/'连接到home()函数。 该函数调用Flaskrender_template()函数从模板目录中获取home.html文件,并将其返回到浏览器。

All of the example code is available from a link provided at the end of this article.

可从本文结尾处提供的链接中获得所有示例代码。

使用Connexion添加REST API端点 (Using Connexion to Add a REST API Endpoint)

Now that you’ve got a working web server, let’s add a REST API endpoint. To do this, you’ll use the Connexion module, which is installed using pip:

现在您已经有了一个可以正常工作的Web服务器,让我们添加一个REST API端点。 为此,您将使用通过pip安装的Connexion模块:

This makes the Connexion module available to your program. The Connexion module allows a Python program to use the Swagger specification. This provides a lot of functionality: validation of input and output data to and from your API, an easy way to configure the API URL endpoints and the parameters expected, and a really nice UI interface to work with the created API and explore it.

这使Connexion模块可用于您的程序。 Connexion模块允许Python程序使用Swagger规范。 这提供了许多功能:验证往返于您的API的输入和输出数据,配置API URL端点和所需参数的简便方法,以及一个非常好的UI界面,可与创建的API一起使用并进行探索。

All of this can happen when you create a configuration file your application can access. The Swagger site even provides an online configuration editor tool to help create and/or syntax check the configuration file you will create.

当您创建应用程序可以访问的配置文件时,所有这些都可能发生。 Swagger站点甚至提供了一个在线配置编辑器工具,以帮助创建和/或语法检查将要创建的配置文件。

向服务器添加连接 (Adding Connexion to the Server)

There are two parts to adding a REST API URL endpoint to your application with Connexion. You’ll add Connexion to the server and create a configuration file it will use. Modify your Python program like this to add Connexion to the server:

使用Connexion将REST API URL端点添加到您的应用程序分为两个部分。 您将Connexion添加到服务器,并创建将使用的配置文件。 像这样修改您的Python程序,以将Connexion添加到服务器:

from from flask flask import import render_templaterender_templateimport import connexionconnexion# Create the application instance# Create the application instanceapp app = = connexionconnexion .. AppApp (( __name____name__ , , specification_dirspecification_dir == './''./' ))# Read the swagger.yml file to configure the endpoints# Read the swagger.yml file to configure the endpointsappapp .. add_apiadd_api (( 'swagger.yml''swagger.yml' ))# Create a URL route in our application for "/"# Create a URL route in our application for "/"@app.route@app.route (( '/''/' ))def def homehome ():():"""""" This function just responds to the browser ULR This function just responds to the browser ULR localhost:5000/ localhost:5000/ :return: the rendered template 'home.html' :return: the rendered template 'home.html' """ """return return render_templaterender_template (( 'home.html''home.html' ))# If we're running in stand alone mode, run the application# If we're running in stand alone mode, run the applicationif if __name__ __name__ == == '__main__''__main__' ::appapp .. runrun (( hosthost == '0.0.0.0''0.0.0.0' , , portport == 50005000 , , debugdebug == TrueTrue ))

You’ve added a couple of things to incorporate Connexion into the server. Theimport connexionstatement adds the module to the program. The next step is creating the application instance using Connexion rather than Flask. Internally, the Flask app is still created, but it now has additional functionality added to it.

您已添加了几件事将Connexion整合到服务器中。import connexion语句将模块添加到程序中。 下一步是使用Connexion而非Flask创建应用程序实例。 在内部,仍会创建Flask应用程序,但现在已添加了其他功能。

Part of the app instance creation includes the parameterspecification_dir. This informs Connexion what directory to look in for its configuration file, in this case our current directory. Right after this, you’ve added the line:

应用实例创建的一部分包括参数specification_dir。 这将通知Connexion要在哪个目录中查找其配置文件,在本例中为当前目录。 之后,您添加了以下行:

app.add_api('swagger.yml')

app.add_api('swagger.yml')

This tells the app instance to read the fileswagger.ymlfrom the specification directory and configure the system to provide the Connexion functionality.

这告诉应用程序实例从规范目录读取文件swagger.yml并配置系统以提供Connexion功能。

Swagger配置文件 (The Swagger Configuration File)

The fileswagger.ymlis a YAML or JSON file containing all of the information necessary to configure your server to provide input parameter validation, output response data validation, URL endpoint definition, and the Swagger UI. Here is part of theswagger.ymldefining theGET /api/peopleendpoint your REST API will provide:

文件swagger.yml是一个YAML或JSON文件,其中包含配置服务器以提供输入参数验证,输出响应数据验证,URL端点定义和Swagger UI所需的所有信息。 这是swagger.yml一部分,定义了REST API将提供的GET /api/people端点:

This file is organized in a hierarchical manner: the indentation levels represent a level of ownership, or scope.

该文件是以分层方式组织的:缩进级别代表所有权或范围级别。

For example,pathsdefines the beginning of where all the API URL endpoints are defined. The/peoplevalue indented under that defines the start of where all the/api/peopleURL endpoints will be defined. Theget:indented under that defines the section of definitions associated with an HTTP GET request to the/api/peopleURL endpoint. This goes on for the entire configuration.

例如,paths定义了定义所有API URL端点的起点。 缩进的/people值定义了定义所有/api/peopleURL端点的起点。 下面的get:缩进定义了与/api/peopleURL端点的HTTP GET请求关联的定义部分。 整个配置过程都如此。

Here are the meanings of the fields in this section of theswagger.ymlfile:

这是swagger.yml文件此部分中各字段的含义:

This section is part of the global configuration information:

本节是全局配置信息的一部分:

consumes:tells Connexion what MIME type is expected by the API.produces:tells Connexion what content type is expected by the caller of the API.basePath: "/api"defines the root of the API, kind of like a namespace the REST API will come from.consumes:告诉Connexion API需要的MIME类型 。produces:告诉Connexion API调用者期望什么内容类型。basePath: "/api"定义API的根,类似于REST API的命名空间。

This section begins the configuration of the API URL endpoint paths:

本节开始配置API URL端点路径:

paths:defines the section of the configuration containing all of the API REST endpoints./people:defines one path of your URL endpoint.get:defines the HTTP method this URL endpoint will respond to. Together with the previous definitions, this creates theGET /api/peopleURL endpoint.paths:定义配置中包含所有API REST端点的部分。/people:定义URL端点的一个路径。get:定义此URL端点将响应的HTTP方法。 与先前的定义一起,这将创建GET /api/peopleURL端点。

This section begins the configuration of the single/api/peopleURL endpoint:

本节开始配置单个/api/peopleURL端点:

operationId: "people.read"defines the Python import path/function that will respond to an HTTPGET /api/peoplerequest. The"people.read"portion can go as deep as you need to in order to connect a function to the HTTP request. Something like"<package_name>.<package_name>.<package_name>.<function_name>"would work just as well. You’ll create this shortly.tags:defines a grouping for the UI interface. All the CRUD methods you’ll define for the people endpoint will share this tag definition.summarydefines the UI interface display text for this endpoint.description:defines what the UI interface will display for implementation notes.operationId: "people.read"定义将响应HTTPGET /api/people请求的Python导入路径/函数。 为了将功能连接到HTTP请求,"people.read"部分的内容可能会更深。 类似"<package_name>.<package_name>.<package_name>.<function_name>"也可以正常工作。 您将很快创建它。tags:定义UI界面的分组。 您将为人员端点定义的所有CRUD方法将共享此标记定义。summary定义了此端点的UI界面显示文本。description:定义UI界面将为实现说明显示的内容。

This section defines the section of the configuration of a successful response from the URL endpoint:

本节定义了来自URL端点的成功响应的配置部分:

response:defines the beginning of the expected response section.200:defines the section for a successful response, HTTP status code 200.description:defines the UI interface display text for a response of 200.schema:defines the response as a schema, or structure.type:defines the structure of the schema as an array.items:starts the definition of the items in the array.properties:defines the items in the array as objects having key/value pairs.fname:defines the first key of the object.type:defines the value associated withfnameas a string.lname:defines the second key of the object.type:defines the value associated withlnameas a string.timestamp:defines the third key of the object.type:defines the value associated withtimestampas a string.response:定义预期响应部分的开始。200:定义成功响应的部分,HTTP状态码200。description:定义UI界面显示文本,响应为200。schema:将响应定义为模式或结构。type:将模式的结构定义为数组。items:开始定义数组中的项目。properties:将数组中的项目定义为具有键/值对的对象。fname:定义对象的第一个键。type:将与fname关联的值定义为字符串。lname:定义对象的第二个键。type:将与lname关联的值定义为字符串。timestamp:定义对象的第三个键。type:将与timestamp关联的值定义为字符串。

人员端点处理程序 (Handler for People Endpoint)

In theswagger.ymlfile, you configured Connexion with theoperationIdvalue to call thepeoplemodule and thereadfunction within the module when the API gets an HTTP request forGET /api/people. This means apeople.pymodule must exist and contain aread()function. Here is thepeople.pymodule you will create:

swagger.yml文件中,您配置了具有operationId值的Connexion,以在API获取针对GET /api/people的HTTP请求时调用people模块和模块中的read功能。 这意味着people.py模块必须存在并且包含read()函数。 这是您将创建的people.py模块:

from from datetime datetime import import datetimedatetimedef def get_timestampget_timestamp ():():return return datetimedatetime .. nownow ()() .. strftimestrftime (((( "%Y-%m-"%Y-%m- %d%d %H:%M:%S" %H:%M:%S" ))))# Data to serve with our API# Data to serve with our APIPEOPLE PEOPLE = = {{"Farrell""Farrell" : : {{"fname""fname" : : "Doug""Doug" ,,"lname""lname" : : "Farrell""Farrell" ,,"timestamp""timestamp" : : get_timestampget_timestamp ()()},},"Brockman""Brockman" : : {{"fname""fname" : : "Kent""Kent" ,,"lname""lname" : : "Brockman""Brockman" ,,"timestamp""timestamp" : : get_timestampget_timestamp ()()},},"Easter""Easter" : : {{"fname""fname" : : "Bunny""Bunny" ,,"lname""lname" : : "Easter""Easter" ,,"timestamp""timestamp" : : get_timestampget_timestamp ()()}}}}# Create a handler for our read (GET) people# Create a handler for our read (GET) peopledef def readread ():():"""""" This function responds to a request for /api/people This function responds to a request for /api/people with the complete lists of people with the complete lists of people :return: sorted list of people :return: sorted list of people """ """# Create the list of people from our data# Create the list of people from our datareturn return [[ PEOPLEPEOPLE [[ keykey ] ] for for key key in in sortedsorted (( PEOPLEPEOPLE .. keyskeys ())]())]

In this code, you’ve created a helper function calledget_timestamp()that generates a string representation of the current timestamp. This is used to create your in-memory structure and modify the data when you start modifying it with the API.

在此代码中,您创建了一个名为get_timestamp()的帮助程序函数,该函数生成当前时间戳记的字符串表示形式。 当您开始使用API​​修改数据时,可用于创建内存结构并修改数据。

You then created thePEOPLEdictionary data structure, which is a simple names database, keyed on the last name. This is a module variable, so its state persists between REST API calls. In a real application, thePEOPLEdata would exist in a database, file, or network resource, something that persists the data beyond running/stopping the web application.

然后,您创建了PEOPLE词典数据结构,该结构是一个简单的名称数据库,以姓氏为关键字。 这是一个模块变量,因此其状态在REST API调用之间保持不变。 在实际的应用程序中,PEOPLE数据将存在于数据库,文件或网络资源中,这可以持久化数据,而不是运行/停止Web应用程序。

Then you created theread()function. This is called when an HTTP request toGET /api/peopleis received by the server. The return value of this function is converted to a JSON string (recall theproduces:definition in theswagger.ymlfile). Theread()function you created builds and returns a list of people sorted by last name.

然后,您创建了read()函数。 服务器收到对GET /api/people的HTTP请求时,将调用此方法。 该函数的返回值将转换为JSON字符串(调用swagger.yml文件中的produces:定义)。 您创建的read()函数将构建并返回按姓氏排序的人员列表。

Running your server code and navigating in a browser tolocalhost:5000/api/peoplewill display the list of people on screen:

运行服务器代码并在浏览器中导航到localhost:5000/api/people将在屏幕上显示人员列表:

Congratulations, you’ve created a nice API and are on your way to building out a complete one!

恭喜,您已经创建了一个不错的API,并且正准备建立一个完整的API!

Swagger UI (The Swagger UI)

Now you have a simple web API running with a single URL endpoint. At this point, it would be reasonable to think, “configuring this with theswagger.ymlfile was cool and all, but what did it get me?”

现在,您有了一个带有单个URL端点的简单Web API。 在这一点上,可以合理地认为:​​“使用swagger.yml文件进行配置很酷,但是,这对我有什么帮助呢?”

You’d be right to think that. We haven’t taken advantage of the input or output validation. All thatswagger.ymlgave us was a definition for the code path connected to the URL endpoint. However, what you also get for the extra work is the creation of the Swagger UI for your API.

您会认为是正确的。 我们尚未利用输入或输出验证。swagger.yml给我们提供的只是对连接到URL端点的代码路径的定义。 但是,您还可以获得额外的工作,就是为您的API创建Swagger UI。

If you navigate tolocalhost:5000/api/ui, the system will bring up a page that looks something like this:

如果您导航到localhost:5000/api/ui,系统将显示一个类似于以下内容的页面:

This is the initial Swagger interface and shows the list of URL endpoints supported at ourlocalhost:5000/apiendpoint. This is built automatically by Connexion when it parses theswagger.ymlfile.

这是最初的Swagger界面,显示了我们的localhost:5000/api端点支持的URL端点列表。 这是Connexion在解析swagger.yml文件时自动构建的。

If you click on the/peopleendpoint in the interface, the interface will expand to show a great deal more information about your API and should look something like this:

如果单击界面中的/people端点,则该界面将展开以显示有关您的API的更多信息,并且应如下所示:

This displays the structure of the expected response, thecontent-typeof that response, and the description text you entered about the endpoint in theswagger.ymlfile.

这将显示预期响应的结构,该响应的content-type以及您在swagger.yml文件中输入的有关端点的描述文本。

You can even try the endpoint out by clicking theTry It Out!button at the bottom of the screen. That will further expand the interface to look something like this:

您甚至可以通过单击“Try It Out!Try It Out!端点Try It Out!屏幕底部的按钮。 这将进一步扩展界面,使其看起来像这样:

This can be extremely useful when the API is complete as it gives you and your API users a way to explore and experiment with the API without having to write any code to do so.

当API完整时,这将非常有用,因为它为您和您的API用户提供了一种无需编写任何代码即可探索和试验API的方法。

Building an API this way is very useful to me at work. Not only is the Swagger UI useful as a way to experiment with the API and read the provided documentation, but it’s also dynamic. Any time the configuration file changes, the Swagger UI changes as well.

以这种方式构建API对我的工作非常有用。 Swagger UI不仅可以用作试验API和阅读提供的文档的方式,而且是动态的。 每当配置文件更改时,Swagger UI也会更改。

In addition, the configuration offers a nice, clean way to think about and create the API URL endpoints. I know from experience that APIs can develop in a sometimes random manner over time, making finding the code that supports the endpoints, and coordinating them, difficult at best.

另外,该配置提供了一种很好的,干净的方式来考虑和创建API URL端点。 我从经验中知道,API有时会随着时间的推移以随机方式进行开发,这使得找到支持端点的代码以及协调它们充其量非常困难。

By separating the code from the API URL endpoint configuration, we decouple one from the other. This alone has been very useful to me in my work building API systems supporting single page web applications.

通过将代码与API URL端点配置分开,我们可以使一个彼此分离。 对我而言,在支持单页Web应用程序的API系统工作中,这本身就非常有用。

建立完整的API (Building Out the Complete API)

Our original goal was to build out an API providing full CRUD access to our people structure. As you recall, the definition of our API looks like this:

我们最初的目标是构建一个API,以提供对我们人员结构的完整CRUD访问。 您还记得,我们的API的定义如下所示:

To achieve this, you’ll extend both theswagger.ymlandpeople.pyfiles to fully support the API defined above. For the sake of brevity, only a link will be provided for both files:

为此,您将扩展swagger.ymlpeople.py文件以完全支持上面定义的API。 为了简洁起见,将仅为两个文件提供一个链接:

swagger.ymlpeople.pyswagger.ymlpeople.py

Swagger UI已完成 (The Swagger UI Completed)

Once you’ve updated theswagger.ymlandpeople.pyfiles to complete the people API functionality, the Swagger UI system will update accordingly and look something like this:

更新完swagger.ymlpeople.py文件以完成people API功能后,Swagger UI系统将进行相应更新,如下所示:

This UI allows you to see all of the documentation you’ve included in theswagger.ymlfile and interact with all of the URL endpoints making up the CRUD functionality of the people interface.

通过该UI,您可以查看swagger.yml文件中包含的所有文档,并与构成人员界面的CRUD功能的所有URL端点进行交互。

演示单页应用程序 (Demonstration Single-Page Application)

You’ve got a working REST API with a great Swagger UI documentation/interaction system. But what do you do with it now? The next step is to create a web application demonstrating the use of the API in a semi-practical manner.

您已经拥有一个运行良好的REST API,并且具有出色的Swagger UI文档/交互系统。 但是您现在如何处理呢? 下一步是创建一个Web应用程序,以半实用的方式演示API的使用。

You’ll create a web application that displays the people on screen as well as allows the user to create new people, update existing people, and delete people. This will all be handled by AJAX calls from JavaScript to the people API URL endpoints.

您将创建一个Web应用程序,该应用程序在屏幕上显示人员,并允许用户创建新人员,更新现有人员和删除人员。 所有这些都将通过从JavaScript到people API URL端点的AJAX调用来处理。

To begin, you need to extend thehome.htmlfile to look like this:

首先,您需要扩展home.html文件,使其看起来像这样:

<!DOCTYPE html><!DOCTYPE html><< html html langlang == "en""en" >><< headhead >><< meta meta charsetcharset == "UTF-8""UTF-8" >><< titletitle >Application Home Page> Application Home Page </</ titletitle >><< link link relrel == "stylesheet" "stylesheet" hrefhref == "/ajax/libs/normalize/8.0.0/normalize.min.css""/ajax/libs/normalize/8.0.0/normalize.min.css" >><< link link relrel == "stylesheet" "stylesheet" hrefhref == "static/css/home.css""static/css/home.css" >><< scriptscriptsrcsrc == "/jquery-3.3.1.min.js""/jquery-3.3.1.min.js"integrityintegrity == "sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=""sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8="crossorigincrossorigin == "anonymous""anonymous" >></</ scriptscript >></</ headhead >><< bodybody >><< div div classclass == "container""container" >><< h1 h1 classclass == "banner""banner" >People Demo Application> People Demo Application </</ h1h1 >><< div div classclass == "section editor""section editor" >><< label label forfor == "fname""fname" >First Name> First Name<< input input idid == "fname" "fname" typetype == "text" "text" />/></</ labellabel >><< br br />/><< label label forfor == "lname""lname" >Last Name> Last Name<< input input idid == "lname" "lname" typetype == "text" "text" />/></</ labellabel >><< br br />/><< button button idid == "create""create" >Create> Create </</ buttonbutton >><< button button idid == "update""update" >Update> Update </</ buttonbutton >><< button button idid == "delete""delete" >Delete> Delete </</ buttonbutton >><< button button idid == "reset""reset" >Reset> Reset </</ buttonbutton >></</ divdiv >><< div div classclass == "people""people" >><< tabletable >><< captioncaption >People> People </</ captioncaption >><< theadthead >><< trtr >><< thth >First Name> First Name </</ thth >><< thth >Last Name> Last Name </</ thth >><< thth >Update Time> Update Time </</ thth >></</ trtr >></</ theadthead >><< tbodytbody >></</ tbodytbody >></</ tabletable >></</ divdiv >><< div div classclass == "error""error" >></</ divdiv >></</ divdiv >></</ bodybody >><< script script srcsrc == "static/js/home.js""static/js/home.js" ></></ scriptscript >></</ htmlhtml >>

The above HTML code extends thehome.htmlfile to pull in the externalnormalize.min.cssfile, which is a CSS reset file to normalize the formatting of elements across browsers.

上面HTML代码扩展了home.html文件,以引入外部normalize.min.css文件,该文件是CSS重置文件,用于标准化浏览器中元素的格式。

It also pulls in the externaljquery-3.3.1.min.jsfile to provide the jQuery functionality you’ll use to create the single-page application interactivity.

它还jquery-3.3.1.min.js了外部jquery-3.3.1.min.js文件,以提供用于创建单页应用程序交互性的jQuery功能。

The HTML code above creates the static framework of the application. The dynamic parts appearing in the table structure will be added by JavaScript at load time and as the user interacts with the application.

上面HTML代码创建了应用程序的静态框架。 出现在表结构中的动态部分将由JavaScript在加载时以及用户与应用程序交互时添加。

静态文件 (Static Files)

In thehome.htmlfile you’ve created, there are references to two static files:static/css/home.cssandstatic/js/home.js. To add these, you’ll need to add the following directory structure to the application:

在创建的home.html文件中,有两个静态文件的引用:static/css/home.cssstatic/js/home.js要添加这些,您需要向应用程序添加以下目录结构:

Because a directory namedstaticwill automatically be served by the Flask application, any files you place in thecssandjsfolders will be available to thehome.htmlfile. For the sake of brevity, here are links to thehome.cssandhome.jsfiles:

因为Flask应用程序将自动为名为static的目录提供服务,所以您放置在cssjs文件夹中的任何文件都将可用于home.html文件。 为了简洁起见,以下是指向home.csshome.js文件的链接:

home.csshome.jshome.csshome.js

JavaScript文件 (JavaScript File)

As was mentioned, the JavaScript file provides all the interaction with and updates to the web application. It does this by breaking up the necessary functionality into three parts by using the MVC (Model / View / Controller) design pattern.

如前所述,JavaScript文件提供了与Web应用程序的所有交互和更新。 它通过使用MVC(模型/视图/控制器)设计模式将必要的功能分为三个部分来实现。

Each object is created by a self-invoking function returning its own API for use by the other pieces. For instance, the Controller is passed the instances of the Model and View as parameters in its instantiation. It interacts with those objects through their exposed API methods.

每个对象都是由一个自调用函数创建的,该函数返回自己的API供其他组件使用。 例如,在实例化中,将参数的Model和View实例作为参数传递给Controller。 它通过这些对象公开的API方法与这些对象进行交互。

The only other connection is between the Model and Controller by means of custom events on the AJAX method calls:

唯一的其他连接是通过AJAX方法调用上的自定义事件在模型和控制器之间建立的:

The Modelprovides the connection to the people API. Its own API is what the Controller calls to interact with the server when a user interaction event requires it.The Viewprovides the mechanism to update the web application DOM. Its own API is what the Controller calls to update the DOM when a user interaction event requires it.The Controllerprovides all the event handlers for user interaction with the web application. This allows it to make calls to the Model to make requests to the people API, and to the View to update the DOM with new information received from the people API.该模型提供了与人员API的连接。 当用户交互事件需要时,Controller会调用其自己的API与服务器进行交互。视图提供了更新Web应用程序DOM的机制。 当用户交互事件需要它时,Controller会调用它自己的API来更新DOM。控制器提供所有事件处理程序,供用户与Web应用程序进行交互。 这允许它调用模型以向人员API发出请求,并向视图发出以使用从人员API接收到的新信息来更新DOM的请求。

It also handles the custom events generated by the asynchronous AJAX requests made by the Model to the people API.

它还处理由模型对人员API发出的异步AJAX请求生成的自定义事件。

Here is a diagram of the MVC structure used in thehome.jsfile:

这是home.js文件中使用的MVC结构的home.js

The idea is that the Controller has a strong link to both the Model and the View. The Model has a weak link (the custom events) to the Controller and no connection to the View at all. The weak link from the Model to the Controller reduces coupling and dependence, which is useful in this case.

这个想法是,Controller与Model和View都有很强的联系。 模型与Controller的链接(自定义事件)较弱,而与View的连接则完全没有。 从模型到控制器的薄弱环节减少了耦合和依赖性,这在这种情况下很有用。

演示申请 (Demo Application)

When created, the web application will look like this in the browser:

创建后,Web应用程序在浏览器中将如下所示:

TheCreatebutton allows the user to create a new person in the people structure on the server. When you enter a First and Last Name and hitCreate, the Controller calls the Model to make a request to thePOST /api/peopleURL endpoint. This will verify that the last name doesn’t already exist. If it doesn’t, it will create a new person in the people structure.

Create按钮允许用户在服务器上的人员结构中创建新人员。 当您输入名字和姓氏并点击Create,控制器将调用模型向POST /api/peopleURL端点发出请求。 这将验证姓氏不存在。 如果没有,它将在人员结构中创建一个新人员。

This generates a custom event in the Model that causes the Controller to call the Model again to request aGET /api/people, which will return the complete list of people sorted. The Controller then passes that onto the View to redraw the table of people.

这会在Model中生成一个自定义事件,该事件会导致Controller再次调用Model以请求GET /api/people,这将返回已排序人员的完整列表。 然后,控制器将其传递到视图以重绘人员表。

Double clicking on any row in the table will populate the First and Last Name fields in the editor section of the application. At this point, the user can either update or delete the person.

双击表中的任何行,将在应用程序的编辑器部分填充“姓氏”和“姓氏”字段。 此时,用户可以更新或删除此人。

To update successfully, the user must change something about the First Name. The Last Name must remain the same as it’s the lookup key for the person to update. When Update is clicked, the Controller calls the Model to make a request to thePUT /api/people/{lname}URL endpoint. This will verify that the Last Name does currently exist. If so, it will update that person in the people structure.

要成功更新,用户必须更改有关“名字”的内容。 姓氏必须与要更新的人的查找关键字相同。 单击更新后,控制器将调用模型以向PUT /api/people/{lname}URL端点发出请求。 这将验证姓氏当前是否存在。 如果是这样,它将在人员结构中更新该人员。

This generates a custom event in the Model that causes the Controller to call the Model again to request aGET /api/people, which will return the complete list of people sorted. The Controller then passes that onto the View to redraw the table of people.

这会在Model中生成一个自定义事件,该事件会导致Controller再次调用Model以请求GET /api/people,这将返回已排序人员的完整列表。 然后,控制器将其传递到视图以重绘人员表。

To delete successfully, the user need only clickDelete. WhenDeleteis clicked, the Controller calls the Model to make a request to theDELETE /api/people/{lname}URL endpoint. This will verify that the last name does currently exist. If so, it will delete that person from the people structure.

要成功删除,用户只需单击Delete。 单击Delete,控制器将调用模型以向DELETE /api/people/{lname}URL端点发出请求。 这将验证姓氏当前是否存在。 如果是这样,它将从人员结构中删除该人员。

This generates a custom event in the Model that causes the Controller to call the Model again to request aGET /api/people, which will return the complete list of people sorted. The Controller then passes that onto the View to redraw the table of people.

这会在Model中生成一个自定义事件,该事件会导致Controller再次调用Model以请求GET /api/people,这将返回已排序人员的完整列表。 然后,控制器将其传递到视图以重绘人员表。

Try making intentional errors in the editor, like misspelling a Last Name, and see the errors generated by the API represented on the web application.

尝试在编辑器中故意犯错误,例如拼写姓氏错误,然后查看由Web应用程序上表示的API生成的错误。

范例程式码 (Example Code)

All of the example code for this article is available here. There are four versions of the code, each in aversion_#directory, where#ranges from 1 to 4. The four versions correspond to the article sections in this manner:

本文提供了所有示例代码。 该代码有四个版本,每个版本都在version_#目录中,其中#范围是1到4。这四个版本以这种方式对应于文章部分:

version_1: This version contains the initial web server that serves up thehome.htmlfile.version_2: This version contains the web server with Connexion added and the first people API URL endpoint.version_3: This version contains the completed people API with all supported URL endpoints.version_4: This version contains the completed API and a single page web application to demonstrate it.version_1:此版本包含提供home.html文件的初始Web服务器。version_2:此版本包含添加了Connexion的Web服务器和第一个人API URL端点。version_3:此版本包含具有所有受支持的URL端点的完整的人API。version_4:此版本包含完整的API和用于演示它的单页Web应用程序。

Free Bonus:Click here to download a copy of the “REST in a Nutshell” Guide with a hands-on introduction to REST API principles and examples.

免费红利:单击此处下载“ REST in a Nutshell”指南的副本,其中包括REST API原理和示例的动手介绍。

结论 (Conclusion)

In this tutorial, you saw how relatively easy it is to create a comprehensive REST API with Python. With the Connexion module and some additional configuration work, a useful documentation and interactive system can be put in place, making your API a much more enjoyable experience for your users to interface with and understand.

在本教程中,您了解了使用Python创建全面的REST API相对容易的事情。 借助Connexion模块和一些附加的配置工作,可以放置有用的文档和交互式系统,使您的API与用户进行交互和理解提供了更加愉快的体验。

翻译自: //06/building-and-documenting-python-rest-apis-with-flask-and-connexion/

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。