RESTful API 设计的最佳实践示范

    作者:课课家教育更新于: 2017-05-25 14:33:45

    Web开发

      目前互联网上充斥着大量的关于RESTfulAPI(为了方便,以后API和RESTfulAPI一个意思)如何设计的文章,然而却没有一个”万能“的设计标准:如何鉴权?API格式如何?你的API是否应该加入版本信息?当你开始写一个app的时候,特别是后端模型部分已经写完的时候,你不得不殚精竭虑的设计和实现自己app的publicAPI部分。因为一旦发布,对外发布的API将会很难改变。

      即使如此,Facebook、谷歌、Github、Netflix和几个其他的科技巨头已经允许开发者和其产品通过API调用他们的数据,并为他们提供平台。即使你不是写API的专业人士,拥有精美的API也对你的应用程序有好处。

      关于设计API的最好方法,网络上有较长一段时间的争论,但官方也没有对此给出解释。

      API是一个接口,通过它许多开发者可与数据交互。设计优良的API使用起来很方便,并给开发者的工作带来便利。API是开发者的GUI,如果它设计不合理,开发者会将它替换。所以,开发者的经验是衡量API质量的最重要的指标。

    RESTful API 设计最佳实践_web开发_RESTful API _API_课课家教育

      一、术语

      以下是与RESTAPI相关的重要术语:

      资源(Resource)是一个对象或对某物的表示。它有一些相关联的数据,并有一组方法进行操作。例如:动物,学校和员工是资源。这些资源都有着删除,添加,更新操作。

      集合(Collection)是一系列资源,例如:公司集合是很多公司的集合。

      URL(统一资源定位符)是一种路径,可以通过它定位资源并且也可以对它执行一些动作。

      二、API设计的基本要求

      1.当标准合理的时候遵守标准。

      2.API应该对程序员友好,并且在浏览器地址栏容易输入。

      3.API应该简单,直观,容易使用的同时优雅。

      4.API应该具有足够的灵活性来支持上层ui。

      5.API设计权衡上述几个原则。

      三、使用RESTfulURLs和action.

      虽然前面我说没有一个万能的API设计标准。但确实有一个被普遍承认和遵守:RESTfu设计原则。它被RoyFelding提出(在他的”基于网络的软件架构“论文中第五章)。而REST的核心原则是将你的API拆分为逻辑上的资源。这些资源通过http被操作(GET,POST,PUT,DELETE)。

      四、那么我应该如何拆分出这些资源呢?

      显然从API用户的角度来看,”资源“应该是个名词。即使你的内部数据模型和资源已经有了很好的对应,API设计的时候你仍然不需要把它们一对一的都暴露出来。这里的关键是隐藏内部资源,暴露必需的外部资源。

      在SupportFu里,资源是ticket、user、group。

      一旦定义好了要暴露的资源,你可以定义资源上允许的操作,以及这些操作和你的API的对应关系:

      1.GET/tickets#获取ticket列表

      2.GET/tickets/12#查看某个具体的ticket

      3.POST/tickets#新建一个ticket

      4.PUT/tickets/12#更新ticket12.

      5.DELETE/tickets/12#删除ticekt12

      可以看出使用REST的好处在于可以充分利用http的强大实现对资源的CURD功能。而这里你只需要一个endpoint:/tickets,再没有其他什么命名规则和url规则了,cool!

      五、API端点(路径)

      为了更好理解,我们给公司写API,这些公司都有一些员工。/getAllEmployees是对员工列表进行回应的API。公司其他API大致如下:

      /addNewEmployee

      /updateEmployee

      /deleteEmployee

      /deleteAllEmployees

      /promoteEmployee

      /promoteAllEmployees

      并且将有大量的和这些操作不同的API端点,它们包含大量冗余的行为。因此,当API数量增加时,这些API端点将很难维护。

      哪里不对?

      每个URL代表一种资源(Resource),所以URL中只能有名词,不能有动词。API路径/addNewEmployee包含了操作addNew和资源名称Employee。

      那么怎样算是正确的方式?

      /companies是一个很好的不包含操作的例子。但是问题来了,我们该怎样告诉服务器我们要进行的操作呢?新增,删除,还是更新?

      这时HTTP方法(GET,POST,DELETE,PUT)(也称为动词)就可以起到作用了。

      资源在API端点中应该总是复数,如果我们想访问资源的一个实例,我们可以传递URL中的id。

      方法GET路径/companies是获取所有公司的列表。

      方法GET路径/companies/34是获取公司34的详细信息。

      方法DELETE路径/companies/34是删除公司34.

      在其他的一些使用案例中,如果我们有一些资源在某个资源之下,例如,一个公司的员工,那么在这样的例子中API的endpoint(端点)就应该是这样的:

      GET/companies/3/employees可以取得编号为3的公司的员工列表

      GET/companies/3/employees/45可以取得编号为3的公司的45号员工的细节信息

      DELETE/companies/3/employees/45可以删除编号为3的公司的45号员工

      POST/companies可以创建一个新公司并返回新创建公司的细节信息

      现在这样,API是不是更严谨和一致了呢?

      结论:路径应该包含资源的复数形式,HTTP方法应该定义成各种行为在资源上执行。

      六、HTTP方法(动词)

      HTTP定义了几组方法,这些方法给出了对资源要执行的操作类型。

      URL是一个句子,其中资源是名词,HTTP方法是动词。

      主要的HTTP方法如下:

      GET方法从资源请求数据,不产生多余结果。

      例如:/companies/3/employees会返回公司3的所有雇员列表。

      POST方法请求服务器在数据库中创建资源,这主要用于提交Web表单时。

      例如:/companies/3/employees创建一个公司3的新雇员。

      POST是非幂等的,这意味着多个请求将会有不同的效果。

      PUT方法请求服务器更新资源或创建资源(如果不存在的话)。

      例如:/companies/3/employees/john将请求服务器在公司3的雇员集合中更新或在不存在的情况下创建关于john的资源。

      PUT是幂等的,这意味着多次请求具有相同的效果。

      DELETE方法将请求的资源或实例从数据库中删除。

      例如:/companies/3/employees/john/将请求服务器从公司3的雇员集中删除john资源。

      HTTP中还有很多其他方法,我们将在另一篇文章中讨论。

      七、HTTP响应状态码

      当客户端通过API向服务器发起请求时,无论请求是失败的、通过的还是错误的,客户端应该获得反馈。HTTP状态码是一堆标准化的数值码,在不同的情况下具有不同的解释。服务器应始终返回正确的状态码。

      以下是HTTP状态码的主要分类:

      2xx(成功类别)

      这些状态代码表示请求的操作已被服务器接收到并成功处理。

      200Ok:标准的HTTP响应,表示GET、PUT或POST的处理成功。

      201Created:在创建新实例时,应返回此状态代码。例如,使用POST方法创建一个新的实例,应该始终返回201状态码。

      204内容不存在:表示请求已被成功处理,但并未返回任何内容。

      DELETE算是其中一个很好的例子。

      APIDELETE/companies/43/employees/2将删除员工2,作为响应,我们不需要在该API的响应正文中的任何数据,因为我们明确地要求系统将其删除。如果有任何错误发生,例如,如果员工2在数据库中不存在,那么响应码将不是2xx对应的成功类别,而是4xx客户端错误类别。

      3xx(重定向类别)

      304未修改:表示客户端的响应已经在其缓存中。因此,不需要再次传送相同的数据。

      4xx(客户端错误类别)

      这些状态代码表示客户端发起了错误的请求。

      400错误请求:表示客户端的请求没有被处理,因为服务器不能理解客户端请求的是什么。

      401未授权:表示客户端不被允许访问该资源,需要使用指定凭证重新请求。

      403禁止访问:表示请求是有效的并且客户端已通过身份验证,但客户端不被允许以任何理由访问对应页面或资源。例如有时授权的客户端不被允许访问服务器上的目录。

      404未找到:表示所请求的资源现在不可用。

      410资源不可用:表示所请求的资源后续不再可用,该资源已被移动。

      5xx(服务器错误类别)

      500是服务器内部错误,表示请求已经被接收到了,但服务器被要求处理某些未预设的请求而完全混乱。

      503服务不可用表示服务器已关闭或无法接收和处理请求。大多数情况是服务器正在进行维护。

      八、字段套管约定

      您可以遵循任何套管约定,但要确保其在应用程序中一致。如果请求主体或响应类型是JSON,那么请按照camelCase(驼峰命名法)来保持一致。

      九、搜索、排序、过滤和分页

      这些行为都只是针对一个数据集进行的查询。由于还没有一套新的API来处理这些行为。因此,我们需要向GET方法的API附加查询参数。

      我们来理解几个例子看它们是如何实现这些行为的。

      排序(sorting),客户端想要获得排序后的公司列表,GET/companies端点应当接受多个查询排序参数。

      例如,GET/companies?sort=rank_asc将根据等级以升序的方式对公司进行排序。

      过滤(Filtering),用来过滤数据集,我们可以通过查询参数传递不同的选项。

      例如,GET/companies?category=banking&location=india将根据公司类别为银行以及所处位置为印度来过滤公司的列表数据。

      搜索(Searching),当需要在公司列表中搜索公司名称时,API端点应当是GET/companies?search=DigitalMckinsey。

      分页(Pagination),当数据集太大时,我们将数据集分成更小的块,这样有助于提高性能,并且更易于处理响应。例如,GET/companies?page=23表示获取第23页的公司列表。

      如果在GET方法中附加了很多查询参数,会造成URI太长,服务器可能会响应414的HTTP状态,表示这个URI太长,在这种情况下,我们也可以将参数传递给POST方法的请求体中。

      十、限制API返回值的域

      有时候API使用者不需要所有的结果,在进行横向限制的时候(例如值返回API结果的前十项)还应该可以进行纵向限制。并且这个功能能有效的提高网络带宽使用率和速度。可以使用fields查询参数来限制返回的域例如:

      GET/ticketsfields=id,subject,customer_name,updated_at&state=open&sort=-updated_at

      十一、更新和创建操作应该返回资源

      PUT、POST、PATCH操作在对资源进行操作的时候常常有一些副作用:例如created_at,updated_at时间戳。为了防止用户多次的API调用(为了进行此次的更新操作),我们应该会返回更新的资源(updatedrepresentation.)例如:在POST操作以后,返回201created状态码,并且包含一个指向新资源的url作为返回头

      十二、是否需要“HATEOAS“

      网上关于是否允许用户创建新的url有很大的异议(注意不是创建资源产生的url)。为此REST制定了HATEOAS来描述了和endpoint进行交互的时候,行为应该在资源的metadata返回值里面进行定义。

      十三、只提供json作为返回格式

      现在开始比较一下XML和json了。XML即冗长,难以阅读,又不适合各种编程语言解析。当然XML有扩展性的优势,但是如果你只是将它来对内部资源串行化,那么他的扩展优势也发挥不出来。很多应用(youtube,twitter,box)都已经开始抛弃XML了,我也不想多费口舌。给了google上的趋势图吧:

    现在开始比较一下XML和json了。XML即冗长,难以阅读,又不适合各种编程语言解析。当然XML有扩展性的优势,但是如果你只是将它来对内部资源串行化,那么他的扩展优势也发挥不出来。很多应用(youtube,twitter,box)都已经开始抛弃XML了,我也不想多费口舌。给了google上的趋势图吧:

      当然如果的你使用用户里面企业用户居多,那么可能需要支持XML。如果是这样的话你还有另外一个问题:你的http请求中的media类型是应该和accept头同步还是和url?为了方便(browserexplorability),应该是在url中(用户只要自己拼url就好了)。如果这样的话最好的方法是使用.xml或者.json的后缀。

      十四、版本控制

      当你的API被开始被广泛使用后,突然升级API会打破现有的产品、服务。

      如果有任何重大的中断更新,我们可以将新的API集命名为v2或v1.x.x

      小编结语:

      更多内容尽在课课家教育!

课课家教育

未登录