est的作者认为计算机发展到现在,最大的成就不是企业应用,而是web,是漫漫无边的互联网web世界。Web能有这么大的成就,它值得我们研究。所以Rest的作者仔细研究了Web,按照Web的世界一些关键特性,提出了我们在实现企业应用的时候应该遵循的一种风格,就是Restful。
Rest风格的API可以给我们很多好处,比如:简洁,统一,性能,可扩展性等等。可惜的是,在实现Rest的时候,总有一些Rest的关键特性没有实现,比如,无状态性,这在我做过的两个项目和我知道的另外一个项目都存在。事实上要实现无状态性在java里不是那么容易,因为那意味着要把servlet的session抛弃了。除此之外,Rest的一些其他特性在各个项目中实现的也是各有不同。
接下来,我会列出一些我认为的,要实现Rest风格API的关键步骤:
1. 所有东西都是资源(Resource)
所有要给API操作的对象都只能是资源。不管实际上存在的,还是抽象上的。所有资源都会有一个不变的标识(ID),对资源的任何API操作都不应该改变资源的标识。资源和其他资源会有关系,资源与资源的关系通过资源的标识来引用。对资源的操作都应该是完整的,比如获取资源拿到的应该是一个完整的资源对象(根据企业引用特点有些例外,后面会提到)。
事实上,上面的这些完完全全是按照互联网的特性提出来的。互联网中,一个URL就是一个资源;资源的内容就是HTML页面;不管怎么改HTML内容,URL都不会改变;资源之间通过HTML里的连接联系起来;每次获取的时候,获取到的都是完整的HTML内容。
假设有一个博客系统,那么其中的资源可以包括:博主,每个博主都是一个资源;博客,每篇博客都是一个资源,博客和博主之间有联系,通过ID联系起来;每篇博客都会有回复,回复也算是资源,但是它是隶属于博客的,可以认为回复是博客的子资源(你也可以认为博客是博主的子资源,怎么抽象取决于具体的应用,这里不讨论)。
这步通常不难实现,因为这和ORM中的对象概念是类似的,实现上,如果用了Hibernate之类的框架,改动也应该很小。
2. 规范对资源的操作,最好只包括CRUD
CRUD指创建(Create),读取(Read), 更新(Update),删除(Delete)
通常对资源的操作只包含CRUD是不可能的,CRUD里甚至连查找的操作的都没有。但这不妨碍我们对Rest的理解,Rest提出的要求是,对资源的操作都应该是统一的,不管是操作哪种类型的资源,API都应该是一致的。这样当调用API的客户端知道某种资源的时候,它不需要去学习对这个资源该怎么操作,因为对所有资源的操作都是一致的,它们都应该支持CRUD操作,以及一些其他操作,比如list(用来查找,或者列出所有资源), merge(部分更新资源,这应该是唯一的不操作资源所有内容的API)。
这和Web也是一样的,HTTP里只有GET,PUT,POST,HEAD等等几个统一的请求(参考:http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html)。
要实现简单的几个操作不难,难在这几个简单操作没法支撑整个系统的需求。但是想想吧,互联网也够复杂了吧,还是不是成功了,而且鱼和熊掌不可兼得。有时候服务器端也不一定要实现所有东西,可以把一些逻辑交给客户端去做。比如显示,Rest里显示是完全交给客户端去处理的,服务器只管数据的存储,不管客户端是网页,还是一个手机应用程序,还是另外一个企业应用。各种各样的客户端进来,他们会有各种各样的需求,服务器端不可能一一满足,只能客户端使用统一的API去组合,实现自己的需求。
3. 规范URL的使用
好了,对资源的操作统一了,但是客户端还是要知道怎么触发对资源的某个具体的操作。Rest用URL的规范来保证这种统一性。
创建并保存一个博客:
[plain] view plaincopy
这个请求需要返回博客的保存后的结果,其中包括博客的标识(ID)。 获取一个已经保存的博客,并更新它:
[plain] view plaincopy
这个博客的标识是345。获取博客的某个回复:
[plain] view plaincopy
对待子资源,通常的做法就是和这个例子一样,是一级一级的往下找。我们还可以有其他方法,比如remove用来删除,merge用来部分更新,list用来查找。
有三种方式可以将参数传给API操作:
第一种是通过URL的地址传递,如前面的例子中把标识放在URL里;
第二种是通过URL的参数,比如,对于一个查找请求,可以把查找的过滤条件放在参数里:
[plain] view plaincopy
第三种是PUT或者POST请求的时候,把内容放在HTTP body里面。这里通常就是博客的内容。
前面我们的例子中有些请求是GET,有些是POST,其实这是有原则的。通常对资源内容没有改变的操作都实用GET,比如获取资源,查找资源;对资源有改变的操作都用POST,比如保存资源。
如果想做的更好,我们应该近一步的使用HTTP的请求方法,直接把HTTP方法和要做的操作映射起来。比如我喜欢认为GET请求就是获取资源(get),PUT方法就是更新整个内容(save,update,我觉得这两个没必要区分),POST方法就是更新部分内容(merge),DELETE方法就是删除资源(remove)。如果这样的话,请求的URL又能简化:
[plain] view plaincopy
当然对于list操作,这里就没法满足了,还是需要在URL层面上做些区别。
对于merge操作,有很多人认为是不必要的,Rest不应该提供这个API,但是我觉得在某些情况下很有用。比如某个资源对象,它的内容在不断的扩充,怎么让老的客户端在内容扩充后还能继续使用呢? 如果我们要求所有更新请求都必须把所有内容都放在请求的body中,对于客户端来说就不是那么好做了,但是如果我们允许merge请求,客户端可以可以完全忽略新增加的字段,而只把自己知道的字段放在请求内容中即可。
4. 资源的多重表述
这一步我觉得不是必须的。
Rest里,资源的内容通常直接作为一段JSON或者XML返回给客户端。资源多重表述指的是,一个资源应该能够支持根据客户端的请求,返回相应的格式给客户端。服务器应该按照请求HTTP头中的Accept属性决定返回格式。比如对于Ajax请求,Accept头是application/json,服务端返回JSON格式;对于android请求,Accept头是application/xhtml+xml,服务器返回XML格式。
我觉得这一步不是必须的因为至少从项目前期来说,我们应该都只会支持一种格式。资源的多重表述给我们一种处理多重请求格式的方式,但是我们不需要一开始就支持它。
5. 进一步合理利用HTTP
前面我们已经应用了HTTP的一些东西,比如请求方法,Accept头。事实上我们可以利用更多。
HTTP支持客户端缓存,在HTTP响应里利用Cache-Control,Expires,Last-Modified三个头字段,我们可以让浏览器缓存资源一段时间。Rest也可以利用这些头,告诉客户端在一定时间内不需要再次请求资源。这对提高性能有很大好处。更多HTTP头信息,可以参考http://en.wikipedia.org/wiki/List_of_HTTP_header_fields。
Rest的请求会出错,HTTP的请求也会出错。我们可以直接利用HTTP的response code来告诉客户端Rest请求出了什么错误。比如500,告诉客户端,服务器出错了;401告诉客户端需要把安全验证信息附上,需要登录系统;404告诉请求的资源不存在,等等。更多HTTP响应码,可以参考http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html。在实际的业务中,HTTP的那些response code肯定是不能满足所有需求的,适当的在response body中加上更详细的错误信息也是必须的。
还有其他很多,总之能利用上的就利用上,不比再次发明轮子。
6. 实现请求的无状态
Rest是无状态的。Rest的请求之间不应该有依赖,在调用一个请求前,不需要一定要去提前调用另外一个请求。Rest里面不应该有session,特别是Rest请求不应该保存信息在sesssion里,以便在后面的调用中使用。甚至包括安全验证,客户端不应该需要提前登录,然后把权限信息保存在session里,后面的请求用同一个session来调用。
实现无状态的方法就是,把所有信息都包含在当前的请求中,包括验证信息。HTTP是无状态的,HTTP里有一个Authorization头,HTTP的要求是在每次请求的时候都把验证信息放在里面,服务器每次处理请求前都去验证这个信息。为了安全,我们可以提供一个生成token的Rest API,客户端调用这个API生成token(可以附上用户名/密码来生成token)。在后面的所有请求中都把这个token放在Authentication头中。
实现无状态最大的好处是能够方便的扩展服务器,也即scalability。否则的话,我们要么把Session绑定到具体服务器上,要么用一个共享的空间存储Session。而实现无状态后,我们可以随意增加,减少服务器数量,都不会对当前用户造成影响。
质文章,第一时间送达!
在本教程的这里,我将向您展示如何在Django REST框架中使用Swagger API。Swagger API为REST API端点提供了结构良好的文档,因此新手可以说如何在不了解其内部实现的情况下测试REST API。
本质上,Swagger做的是简单但非常强大的事情:通过添加一些附加注释,它会生成REST API描述,例如HTTP方法,路径/查询/表单参数,响应,HTTP错误代码等),甚至提供了一个简单的Web UI来对您的API的REST调用。
Swagger规范是描述RESTful API的强大定义格式,它创建RESTful接口,通过有效地映射与之关联的所有资源和操作来轻松开发和使用API。它易于学习,与语言无关,并且可以人工和机器可读。
先决条件
Python 3.8.5,Django 3.0.8,REST框架(pip install djangorestframework),Swagger(pip install django-rest-swagger)
假定您已经在系统上安装并配置了Python。
下一个任务是安装Django。首选方法是使用命令pip install Django进行安装。您可以阅读有关Django安装的更多详细信息。
我们将使用MySQL数据库服务器作为存储数据的持久系统,因此您需要阅读教程,了解如何使用django设置MySQL以执行SQL语句。
另外,您需要使用命令pip install django-rest-swagger安装Swagger模块。
我建议您先阅读Django MySQL REST CRUD API示例教程,然后再继续学习。因为此示例恰好遵循该教程。在此示例中,除了REST API CRUD示例之外,我还添加了Swagger API。
在本示例中,我将不展示项目的每个部分,因为我将与现有项目一起工作,但是我将介绍重要的更改。您以后总是可以从本教程底部的链接从我的Github帐户下载完整的项目。
项目设置
我们需要做的第一件事是创建项目目录。项目名称为djangomysqlrestcrudswagger,我们将使用以下命令创建该项目。
<span class="code-snippet_outer">django-admin startproject djangomysqlrestcrudswagger</span>
下一步是在项目内部创建一个应用程序以执行CRUD操作。使用以下命令创建一个名为restcrudswagger的应用程序。
<span class="code-snippet_outer">django-admin startapp restcrudswagger</span>
现在,我们需要将此restcrudswagger应用程序添加到项目中。因此,编辑文件djangomysqlrestcrudswagger / djangomysqlrestcrudswagger / settings.py并将以下行添加到INSTALLED_APPS部分:
<span class="code-snippet_outer"><span class="code-snippet__attribute">INSTALLED_APPS</span>=[</span></code><code><span class="code-snippet_outer"> ...</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__string">'rest_framework_swagger'</span>,</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__string">'restcrudswagger.apps.RestcrudswaggerConfig'</span>,</span></code><code><span class="code-snippet_outer">]</span>
上一行是使用文件djangomysqlrestcrudswagger / restcrudswagger / apps.py构成的。您将在此文件中看到名为=’restcrudswagger’的RestcrudswaggerConfig类。
您需要将以下行添加到上述文件(settings.py)中,否则您将看到错误“ /’AutoSchema’对象的AttributeError没有属性’get_link’”。
<span class="code-snippet_outer"><span class="code-snippet__attr">REST_FRAMEWORK</span>={ <span class="code-snippet__string">'DEFAULT_SCHEMA_CLASS'</span>: <span class="code-snippet__string">'rest_framework.schemas.coreapi.AutoSchema'</span> }</span>
URLS
接下来,我将更改URL方案以添加用于REST文档的Swagger API。将以下代码写入文件 djangomysqlrestcrudswagger / djangomysqlrestcrudswagger / urls.py中。
<span class="code-snippet_outer"><span class="code-snippet__keyword">from</span> rest_framework_swagger.views <span class="code-snippet__keyword">import</span> get_swagger_view</span></code><code><span class="code-snippet_outer"></span></code><code><span class="code-snippet_outer">schema_view=get_swagger_view(title=<span class="code-snippet__string">'User API'</span>)</span></code><code><span class="code-snippet_outer"></span></code><code><span class="code-snippet_outer">urlpatterns=[</span></code><code><span class="code-snippet_outer"> url(<span class="code-snippet__string">'^$'</span>, schema_view)</span></code><code><span class="code-snippet_outer">]</span>
带有源代码的整个文件如下:
<span class="code-snippet_outer"><span class="code-snippet__keyword">from</span> django.urls <span class="code-snippet__keyword">import</span> include, path</span></code><code><span class="code-snippet_outer"><span class="code-snippet__keyword">from</span> rest_framework <span class="code-snippet__keyword">import</span> routers</span></code><code><span class="code-snippet_outer"><span class="code-snippet__keyword">from</span> restcrudswagger <span class="code-snippet__keyword">import</span> views</span></code><code><span class="code-snippet_outer"><span class="code-snippet__keyword">from</span> django.conf.urls <span class="code-snippet__keyword">import</span> url</span></code><code><span class="code-snippet_outer"><span class="code-snippet__keyword">from</span> rest_framework_swagger.views <span class="code-snippet__keyword">import</span> get_swagger_view</span></code><code><span class="code-snippet_outer"></span></code><code><span class="code-snippet_outer">router=routers.DefaultRouter</span></code><code><span class="code-snippet_outer">router.register(<span class="code-snippet__string">r'users'</span>, views.UserViewSet)</span></code><code><span class="code-snippet_outer"></span></code><code><span class="code-snippet_outer">schema_view=get_swagger_view(title=<span class="code-snippet__string">'User API'</span>)</span></code><code><span class="code-snippet_outer"></span></code><code><span class="code-snippet_outer">urlpatterns=[</span></code><code><span class="code-snippet_outer"> url(<span class="code-snippet__string">'^$'</span>, schema_view),</span></code><code><span class="code-snippet_outer"> url(<span class="code-snippet__string">r'^'</span>, include(router.urls))</span></code><code><span class="code-snippet_outer">]</span>
Swagger UI Template
接下来,您需要创建Swagger模板文件,该文件将在您访问URL时呈现。
以下内容被写入djangomysqlrestcrudswagger / restcrudswagger / templates / rest_framework_swagger / index.html。
<span class="code-snippet_outer"><span class="code-snippet__meta"><!DOCTYPE html></span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__tag"><<span class="code-snippet__name">html</span>></span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__tag"><<span class="code-snippet__name">head</span>></span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__tag"><<span class="code-snippet__name">title</span>></span>Swagger<span class="code-snippet__tag"></<span class="code-snippet__name">title</span>></span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__tag"><<span class="code-snippet__name">meta</span> <span class="code-snippet__attr">charset</span>=<span class="code-snippet__string">"utf-8"</span>/></span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__tag"><<span class="code-snippet__name">meta</span> <span class="code-snippet__attr">name</span>=<span class="code-snippet__string">"viewport"</span> <span class="code-snippet__attr">content</span>=<span class="code-snippet__string">"width=device-width, initial-scale=1"</span>></span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__tag"><<span class="code-snippet__name">link</span> <span class="code-snippet__attr">rel</span>=<span class="code-snippet__string">"stylesheet"</span> <span class="code-snippet__attr">type</span>=<span class="code-snippet__string">"text/css"</span> <span class="code-snippet__attr">href</span>=<span class="code-snippet__string">"//unpkg.com/swagger-ui-dist@3/swagger-ui.css"</span> /></span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__tag"></<span class="code-snippet__name">head</span>></span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__tag"><<span class="code-snippet__name">body</span>></span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__tag"><<span class="code-snippet__name">div</span> <span class="code-snippet__attr">id</span>=<span class="code-snippet__string">"swagger-ui"</span>></span><span class="code-snippet__tag"></<span class="code-snippet__name">div</span>></span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__tag"><<span class="code-snippet__name">script</span> <span class="code-snippet__attr">src</span>=<span class="code-snippet__string">"//unpkg.com/swagger-ui-dist@3/swagger-ui-bundle.js"</span>></span><span class="code-snippet__tag"></<span class="code-snippet__name">script</span>></span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__tag"><<span class="code-snippet__name">script</span>></span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">const</span> ui=SwaggerUIBundle({</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__attr">url</span>: <span class="code-snippet__string">"{% url schema_url %}"</span>,</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__attr">dom_id</span>: <span class="code-snippet__string">'#swagger-ui'</span>,</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__attr">presets</span>: [</span></code><code><span class="code-snippet_outer"> SwaggerUIBundle.presets.apis,</span></code><code><span class="code-snippet_outer"> SwaggerUIBundle.SwaggerUIStandalonePreset</span></code><code><span class="code-snippet_outer"> ],</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__attr">layout</span>: <span class="code-snippet__string">"BaseLayout"</span></span></code><code><span class="code-snippet_outer"> })</span></code><code><span class="code-snippet_outer"><span class="code-snippet__tag"></<span class="code-snippet__name">script</span>></span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__tag"></<span class="code-snippet__name">body</span>></span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__tag"></<span class="code-snippet__name">html</span>></span></span>
已知问题
如果在访问URL http:// localhost:8000时看到以下错误,则可以编辑路径中提到的以下文件,如下图所示:
Replace the line {% load staticfiles %} by {% load static %} at line 2.
部署应用
现在,我准备测试构建的API。让我们使用manage.py runserver从命令行启动服务器。该应用程序将在默认端口8000上运行。如果要更改服务器的默认主机/端口,则可以在此处阅读教程。
测试应用
现在,如果您正确地遵循了教程,那么在访问URL http:// localhost:8000时,您将在浏览器上看到以下屏幕:
来源:https://www.roytuts.com/how-to-use-swagger-with-python-based-django-rest-apis/
回复下方「关键词」,获取优质资源
回复关键词「 pybook03」,立即获取主页君与小伙伴一起翻译的《Think Python 2e》电子版
回复关键词「入门资料」,立即获取主页君整理的 10 本 Python 入门书的电子版
回复关键词「m」,立即获取Python精选优质文章合集
回复关键词「book 数字」,将数字替换成 0 及以上数字,有惊喜好礼哦~
题图:pexels,CC0 授权。
ETL,全称为Extract-Transform-Load,即数据提取(Extract)、数据转换(Transform)和数据加载(Load)。这是数据仓库中数据处理的重要过程。ETL过程中,数据从源系统被提取出来,然后经过清洗、转换和集成等操作,最后加载到目标系统(通常是数据仓库或数据湖)。
ETL的主要目标是将企业中的分散、异构数据集成到一起,为企业的决策提供支持。通过ETL过程,企业可以实现数据的统一视图,提高数据的质量和一致性。
RESTful API是一种软件架构风格,它是一种基于HTTP协议、XML(或JSON、HTML等)数据格式、URI等技术来设计的网络应用程序接口。RESTful API的设计原则是简单、直观、标准化,使得API易于使用、易于理解和易于扩展。
在RESTful API中,每个URL代表一种资源。客户端和服务器之间,传递这种资源的某种表现层。客户端通过四个HTTP动词,对服务器端资源进行操作,实现"表现层状态转换"。
ETL和RESTful API在许多场景中都有广泛的应用。例如,在数据仓库建设、数据集成、数据清洗、数据迁移、系统集成、微服务架构等方面,都有ETL和RESTful API的身影。
特别是在云计算和大数据时代,数据量激增,数据类型多样,数据源分散,这就需要更强大、更灵活的工具来处理数据。而ETL和RESTful API正好可以满足这些需求。
使用ETL工具实现RESTful API有很多好处。首先,ETL工具通常提供了丰富的数据连接器,可以连接各种类型的数据源,包括数据库、文件、消息队列、API等。这意味着,我们可以通过ETL工具,方便地从RESTful API中提取数据。
其次,ETL工具通常提供了强大的数据转换功能,包括数据清洗、数据转换、数据聚合等。这意味着,我们可以通过ETL工具,对从RESTful API中提取的数据进行深度处理。ETL工具通常提供了可视化的操作界面,使得数据处理过程更加直观、易懂。这意味着,我们可以通过ETL工具,更好地理解和控制数据处理过程。
最后、ETL工具通常提供了任务调度、监控、告警等功能。这意味着,我们可以通过ETL工具,更好地管理和维护数据处理任务。
下面,我们以一个具体的ETL工具--ETLCLoud为例,展示如何使用ETL工具实现RESTful API的数据提取和处理。
在流程设计中,我们选择RESTful API作为数据源。我们输入API的URL,选择合适的HTTP方法(如GET或POST),并设置好请求头和请求参数。
配置好后可以测试请求数据:
配置数据过滤组件,过滤出年龄在50到100之间的信息
最后,我们在ETL工具中设置数据加载的目标。我们可以选择将数据加载到数据库、文件、消息队列等目标中。我们这里配置库表输出组件,设置输出目标库。
保存后运行流程
查看目标库表数据:
通过以上步骤,我们就完成了一个ETL任务的配置。我们可以运行这个任务,查看任务的运行状态和结果。如果任务运行出现问题,我们还可以通过ETL工具的监控和告警功能,及时发现和处理问题。
总的来说,ETL和RESTful API是数据处理的重要工具。通过ETL工具,我们可以方便地从RESTful API中提取数据,进行深度处理,然后加载到目标系统。ETL工具的丰富功能和易用性,使得数据处理变得更加简单、高效。
*请认真填写需求信息,我们会在24小时内与您取得联系。