本文转载自微信公众号《老王加》,老王加作者老王。转载本文请联系老王Plus公众号。说起来,REST已经存在很长时间了。从早期的三层架构到现在的多层和微服务,核心内容之一就是API---从一个非常简单的API到多设备多用途的API,包括一些外部的三方公共服务像BAT,简单又麻烦,都是API。而这些API基本都是基于REST的。今天我们不详细讲解REST,只说说REST应用中间的一些关键点。应用REST的原因有很多。它易于理解、灵活且适用于任何规模的应用程序。当然REST并不是唯一的规范,还有SOAP、GraphQL。然而,这只是规范的字面并列。使用所有规范,您就会知道:SOAP很笨重,有时甚至很古怪:您需要对接口的表示进行大量思考,而不是逻辑本身。至于GraphQL,它被扩展得太多了。考虑和设计调用API的客户端并不是一个好主意。好吧,这个问题每个人都有不同的看法,我们就不讨论了。不管怎样,在我看来,REST依然是API接口规范之王,短时间内不会被取代。在我的习惯中,使用REST有以下限制。1.不要误会,使用JSON数据,这是我的习惯,不是REST。REST没有规定用什么格式来传输数据,XML可以,JSON也可以。但在我的团队中,以JSON格式传递数据是一项硬性要求。相比之下,JSON相对于XML有很多优点:更容易使用,读写速度更快,占用内存空间更少不需要特殊的依赖或包来解析JSON是主流编程语言都支持的如果你不明白这些优点,没关系,随便在网上找一个XML,自己解析试试。熟悉各大厂商各种开放平台的同学也会有一个直观的感受:早期的SOAP、XML已经逐渐被REST、JSON所取代。另外这里说的JSON数据的使用不仅仅是响应数据,还有请求数据。不要使用form-data或者x-www-form-urlencoded来发送数据,转成JSON,会更容易读、写、测试和管理。真诚的,如果你这样做,我会感谢你所有的开发学生。2、认真对待方法想一想,你见过只用GET方法处理一切的API吗?这不是不可能,但是这种写法说明你对这个工具和HTTPWay的具体工作原理还没有深入的了解。请注意,HTTP中的每个方法都旨在处理特定的作业和内容。下面我就一一说说:GET——当只用于读取数据时,应该使用GET。没有写入,没有更新,只有读取数据。这个概念很简单。而且,在这个前提下,同样的请求肯定会返回同样的结果。POST——从字面意思可以理解,就是存储一些东西,比如在数据库中创建一条记录,在某处写入一些内容。一般来说,选择POST数据的方式有很多种:multipart/form-data、x-www-form-urlencoded、application/json或者text/plain等等,很多。但是我们要求只使用application/json方法,这样可以保持开发和调用的一致性。PUT-字面意思是更新内容。所以当我们需要更新数据时,我们需要将其定义为PUT方法。当然,它也可以用来创建新的数据。DELETE——删除,很好理解。PATCH-补丁,更新现有数据。这与PUT有点不同。通常PATCH有一个范围,更新需要更新的内容,而PUT更多的时候是更新整个数据。当然,有些文章中,还会有OPTIONS、HEAD、TRACE等,很少用到,就不说了。如果想知道,可以查看HTTP相关的文档。说了这么多,重要的是---既然HTTP提供了这样的方法定义,我们就可以将任意CRUD操作映射到这些方法上,而不是仅仅使用GET,这绝不是一个好习惯。3、注意语义团队在开发API时,有一个严格的要求,即API名称需要有语义。语义感这个词是我自己创造的。不是什么高大上的东西,只是要求写的API名称能用正确的英文和顺序,让人看得懂。9021年了,还有人用拼音首字。你相信吗?在我看来,从调用端点到参数和JSON键,所有API都应该被调用者理解,而无需阅读注释和说明。在这里,我参考了一些国外的规则。规则也很简单:使用名词,而不是动词。想一想,上面列出的这些方法本身就是动词,比如:GET/clients,很好理解,如果改成GET/getClients,总觉得怪怪的。务必准确使用单数和复数。对于一条数据,使用单数;对于多条数据,使用复数。感受一下GET/client和GET/clients之间的区别。当然,对于个人数据,通常需要某种ID:GET/client/id。让我们用一些例子来理解这个规则。//好的方法GET/clientsPOST/clientsGET/client/23PUT/client/23DELETE/client/23GET/client/23/comments//坏的方法GET/clients/23GET/listAllClientsPOST/client/createPUT/updateClient/23GET/clientComments/23在这里我想多说几句:规则就是规则,不用死记硬背。需要理解这个规律,在编程的过程中习惯性的应用,变成类似于肌肉记忆的东西。4.时刻注意API的安全。即使您不创建公共API,您也必须记住使用一些方法来确保您的API安全。这是API编程的基本要求。有几个要求:1)。使用HTTPsHTTPs已经出来很久了,如果你对接过大厂的API,你会发现使用HTTPs是基本要求。HTTPs提供了一种比HTTP更安全的方法,它可以在基础网络层面消除中间人攻击,并对调用者和API之间的通信进行加密。在编程时,使用HTTPs是最便宜但最有效的安全形式。让使用HTTPs成为一种标准和习惯,总有一天您会感谢自己。2).从构建API开始,有必要控制访问。你是对的,从构建API开始。它不一定很麻烦,但您需要控制谁可以访问API。通常,可以先添加一个简单的JWTAuth,等API成型后再转为OAuth。目的很简单,控制访问。如果有API攻击什么的,直接关掉暴露的key即可。当然,我们也可以使用keys来跟踪API的调用情况,包括调用量、调用异常等。3).小心敏感数据API代表网络,代表通信。在线和通信中传递敏感数据时要小心。前面我们提到必须使用HTTPs,也是因为这个。如果你不想在监狱里编程,你必须确保这些敏感数据以正确的方式提供给正确的调用者。看了资料,被追究刑事责任。这是我身边真实的事情。4).确保运行环境的安全网关和防火墙,有就用,不要因为麻烦就关掉。更深层次的内容可以丢给运维,但是基础的部分还是要自己去了解。5、版本控制API的迭代升级是每个开发者都会面临的。有时,升级只是逻辑上的改变,更多时候,它会改变输入输出结构。在这种情况下,保持和维护API的版本很重要。作为后端开发者,我们无法保证调用方随时会同步做出相应的更改。在极端情况下,改变内部逻辑也可能影响调用者。API版本控制,不要犹豫,马上开始使用吧。不要觉得某个API比较小,或者调用端少,就不要做。请记住,对于不更新应用程序或其他内容的调用者来说,任何代码更改都是有风险的。您不仅需要确保您的代码不会破坏任何东西或任何人,而且您还需要知道特定版本的应用程序的行为方式。这一点都不好玩。关于API版本控制的详细实现,可以查看我之前的推文。至于门户的版本,并没有那么重要。看个人习惯,v1、v2、v3也有,v1.0、v1.1、v1.2也有。按照微软的建议,使用了Major.Minor.Patch方式。但是个人觉得Patch部分有点太长了。所以,按照我的习惯,应用版本控制后,API的URL会是这样的:GET/v1.7/clientsPOST/v1.7/clientsGET/v1.7/client/23PUT/v1.7/client/23DELETE/v1.7/client/23GET/v1.7/client/23/comments听我的,马上开始API版本控制。6.响应一致性一致性是一个好的API的优良品质。在开发中,我们应该在各个方面保持一致,包括命名、URI、请求、响应等。而这里,响应的一致性是对群成员的硬性要求。API是给别人调用的。保持资源响应一致是对调用者最大的善意。在一个论坛上,我看到它建议每个端点返回不同的资源结构。如果你见过类似的东西,算了,你错了。记住这句话:保持资源响应一致,是对调用者最大的善意。开发API时,尽可能发送相同的响应结构。如果没有数据,则将其作为null、空对象或空数据发送。我们以论坛的文章结构为例。文章数据的结构通常是这样的(化繁为简,不要纠结):{"title":"文章标题","description":"文章内容","comments":[{"text":"Reply1","user":"张三"},{"text":"Reply1","user":"张三"}]}如果需要返回一条数据和列表评论,结果会像这样:{"message":"fetchdatasuccessed","status":true,"article":{"title":"文章标题","description":"文章内容","comments":[{"text":"Reply1","user":"张三"},{"text":"Reply1","user":"张三"}]}}如果需要返回文章列表还有没有评论,会是这样:{"message":"fetchdatasuccessed","status":true,"articles":[{"title":"文章标题1","description":"文章内容1","comments":[]},{"title":"文章标题2","description":"文章内容2","comments":[]}]}看到了吗?这样,我们对于内层元素文章的结构完全一样,对于整个返回结构,我们也坚持这样做,这样可以为自己和他人节省很多时间。7、注意出错后的返回信息。API开发应该能够处理正确的请求和错误的请求。错误的请求并不可怕,可怕的是你没有考虑过,或者考虑过,但没有给来电者足够的细节。在API返回中,很多人会忽略这里的HTTP状态码,即HttpStatus。HTTP协议为我们定义了50多种不同的状态码,几乎涵盖了所有场景。每个代码都有独特的含义,应该在独特的场景中使用。这个内容网上很多,我简单列一下:1xx——信息响应码,简单的说就是状态通知。2xx-成功响应代码。所有的成功都会在这个范围内。通常我们看到200,但也有其他成功案例。3xx-重定向响应代码。服务器将请求重定向到另一个URL,并返回该URL。4xx-客户端错误响应代码。最常见的是400,请求协议格式或内容错误。5xx-服务器错误响应。最常见的是500,服务端程序,也就是API里面,内存溢出或者抛出异常。在开发过程中,我们可以充分准确地使用这些状态码。这样,所有的开发者都会在同一个理解层次上了解问题的状态和原因,使API具有普遍的可理解性、一致性和标准性。这不是REST的标准,但它应该是我们开发REST所依据的标准。对于状态码,这只是第一步。当出现问题时,我们需要向调用者提供尽可能多的详细信息。当然,这并不容易,我们需要能够思考和预测API会怎么出错,调用者会做什么,不会做什么。因此,通常一个API的第一步都是对请求数据进行严格的校验:数据是否存在,值是否在我们预期的范围内,是否可以入库。以上面的例子为例,GET/client/23,获取clientId=23的数据,我们需要做如下工作:检查请求是否有clientId参数,如果没有,应该是400状态检查传入的clientId=23记录是否存在?如果没有,则返回404的响应。如果找到该记录,则返回200的响应。这只是一个简单的例子。在真正的编程中,会有更多的考虑。而且,除了状态码之外,还应该返回相应的错误信息,例如:没有输入入参clientId,ID为23的数据记录不存在等。重要的是,提供详细的错误信息可以帮助开发人员和调用者准确了解出了什么问题。不用担心,调用方不会将这些信息显示给最终用户,但他们可以利用这些信息快速定位和解决问题。8、尽可能优化在现代编程中,API在系统中的作用绝对是整个运行的大脑。因此,API开发最基本的要求就是速度和优化,API不能成为整个系统和生态的痛点。请求就是这么简单。我们可以做很多事情来确保交付高性能和可扩展的API。让我们看看我们能做什么?首先是数据库级别的优化。一般说API慢的时候,十之八九都和数据库有关。糟糕的数据库设计、复杂的查询、缓慢的硬件环境,甚至缺乏缓存都是导致速度慢的原因。因此,在开发过程中,您应该始终关注并始终优化数据库结构、查询、索引以及与数据库交互的一切。接下来是缓存。许多人不愿意使用缓存,因为它会使代码复杂化。但在实际效果中,系统越大越复杂,通过缓存传递的数据就越多。有时,缓存数据库查询可以将加载时间减少100%。大多数数据不会经常更改。使用缓存,调用端的兄弟会把你当兄弟。影响性能的另一个因素是API发送给调用者的数据量。确保API只返回调用者需要的数据,而不是全部。如果可能,不要每次都返回完整的模型详细信息和关系。试一试,但要与响应中的返回模型保持一致。最后,不要忘记压缩。如果可以,请使用Brotli,或者至少也使用Gzip来压缩数据。简单的配置可以减少50-75%的传输数据,多好啊!9.做一个贴心开发者的要求,跟技术无关,但还是想写出来。作为开发人员,我们需要明白,项目不是一个人的事情。当我们写完最后一行代码,提交并合并时,你可能认为工作已经完成了。但不,对于许多其他人来说,这仅仅是个开始。在我们完成之前,很多人无法开始他们的工作。所以,我们需要通过多种方式来准备API。我们需要确保API有效,有良好的文档,更重要的是,我们需要准备好集成支持。但是,文档写得再好,在集成的过程中和后续的过程中总会出现问题,出现各种各样的问题。所以,设身处地为他人着想,努力让他们的工作更轻松。构建良好的API,遵循我们在此定义的规则,编写出色的文档,并为所有人服务。10.结束了。结束了。以上九项是我团队执行的标准和要求。在这里我还要说一下,R??EST本身并不是一个标准,所以没有人会告诉你什么是对的,什么是错的。在开发时多想想:作为开发人员,我们每天都在寻找模式来让我们的代码更好、更漂亮、更高效,那么为什么不在我们的API中做同样的事情呢?
