为您的铁路应用编程接口制作文档


为什么和Stripe或者Shopify一起工作作为开发者是如此的快乐?这可能有很多原因,但其中之一肯定是他们有很好的文档。

对于这些公司来说,文档不是事后才想到的——你可以看出他们显然在这方面花费了大量的时间和资源。这是为什么?原因之一是,它们都是由开发人员启动的业务,但这也有很好的商业意义。当API易于理解和集成时,开发人员能够在更短的时间内启动和运行。

当开始设计一个新的API时,文档可能不是你考虑的第一件事,但也许它应该是。在本文中,让我们来谈谈Ruby/Rails生态系统中存在的一些工具(以及一些更通用的工具),用于为您的应用编程接口生成文档。我们将讨论一些通过测试生成文档的例子。

“Documentation shouldn’t be an afterthought for your API.” via @leighchalliday


推荐

在我们深入了解我们可以用来记录和发布文档的一些工具的细节之前,让我们后退一步,谈谈记录我们的应用编程接口的一些建议。

优先考虑文档

为您的应用编程接口编写好的文档不应该是事后的想法。事实上,有一个想法叫做Documentation Driven Development这表明,很像TDD(在实现之前编写测试),您应该在编写实际实现之前编写文档。

通过对文档进行优先排序,您将保证您永远不会没有时间去做它。当你试图向别人解释的时候,它也会让你放慢速度去思考实现是否有意义。

“Prioritize documentation and you’ll never run out of time for it.” via @leighchalliday


简化文档

为您的应用编程接口编写文档应该不难。我不是说写好文档不需要时间和努力。相反,我们应该消除可能阻止开发人员记录他们正在使用的应用编程接口的障碍或烦恼。如果同步很困难,如果很难部署,如果格式化很困难或者太重复,人们就不会想这么做。

但不一定要痛苦。文档应该尽可能地自动化,并且应该通过某种连续的集成系统来部署。它还应该保存在源代码管理库中,以便于查看对它所做的更改。

“Documentation should be automated as much as possible.” via @leighchalliday


保持文档更新

唯一比没有文档更糟糕的是过时的文档。就像跟着一张方向不正确或者不完整的地图。更新app/API时,应同时更新相应的文档。

更新应用编程接口文档应该是开发过程的一部分。就像代码在被测试和同行评审之前是不完整的一样,它也不应该被标记为已完成,直到文档被更新。

写你自己的客户

一旦有了文档,让不熟悉代码工作方式的人使用该文档来构建某种连接到应用编程接口的客户端是一个好主意。这就是你的客户和客户会经历的。

如果它令人困惑,缺少细节,或者需要你的开发团队来来回回地工作,那么它告诉你两件事之一:要么你的文档需要工作和进一步的清晰,要么应用编程接口本身设计得很差。在你成为客户之前,很难知道这些。用微软在80年代创造的一句话:吃自己的狗粮。

“When it comes to documentation, eat your own dog food.” via @leighchalliday


您的文档应该包括哪些内容

完整地记录您的应用编程接口和只提供应用编程接口引用(端点、参数、头、响应、错误等)是有区别的。)。提供一个API引用是一个很好的开始,但不应该是全部。

Stripe刚刚发布了一个新的Getting Started guide这是一个很好的例子。这一切都是为了给开发者提供入门所需的指导和知识。应用编程接口参考是为那些已经熟悉应用编程接口如何工作并需要细节的人准备的。

以下是您的应用编程接口可以而且应该有的不同部分的一些想法:

  • 入门:快速介绍,仅包括如何开始的基本知识。连接和使用应用编程接口所需的最低限度。
  • 教程:这些可以包括围绕不同公共流程或应用程序使用的用例。例如:支付账单、退款、更新用户设置等。
  • API参考:这是关于可用端点的文档所在的地方,它们接收哪些参数和头,HTTP状态代码,响应看起来像什么,可能触发什么错误,以及可能在多种编程语言中的示例。
  • 认证:你的API是可供公众消费的,还是需要API令牌?在这里,您可以谈论节流和其他围绕安全性/公平使用的领域。

通过测试生成文档

生成文档的一种流行方式,更具体地说,是通过测试来生成一个应用编程接口引用。Rails在这方面有几个流行的亮点:apipie-railsrspec_api_documentation

让我们看看它是如何使用rspec_api_documentation

首先,我们需要使用RSpec而不是Rails附带的默认测试框架。这不是一个大问题;它非常受欢迎,通常是我在生成新的Rails应用程序后首先改变的事情之一。之后,我们可以安装rspec_api_documentation宝石。

这个宝石有很多配置选项可以设置。其中之一包括你想要生产的产品类型。

默认情况下,它会生成一组相当普通/没有样式的HTML文档,放在doc/api文件夹。通过将输出格式切换到:json,我们可以结合其他工具使用这些数据来生成更复杂的样式。

apitome是其中之一。它接受文档输出,并将其转换成更好的格式,包括许多常见的库,例如bootstraphighlight.js。它可以是单页或多页。

# config/initializers/rspec_api_documentation.rb
RspecApiDocumentation.configure do |config|
  # Output folder
  config.docs_dir = Rails.root.join("doc", "api")

  # An array of output format(s).
  # Possible values are :json, :html, :combined_text, :combined_json,
  #   :json_iodocs, :textile, :markdown, :append_json
  config.format = [:json]
end

让我们看看实际的测试是什么样子的。这些是文档的生成来源。

我们正在使用的应用程序/模型是一个(虚构的)房地产应用编程接口,允许我们对房屋、公寓等进行分类和查询。这部分代码在这里不太重要,所以我们只看测试本身。

# spec/acceptance/residences_spec.rb
require 'rails_helper'
require 'rspec_api_documentation/dsl'

resource "Residences" do
  let(:user) { create(:user) }
  let(:auth_token) { user.auth_token }

  # Headers which should be included in the request
  header "Accept", "application/vnd.api+json"
  header "X-Api-Key", :auth_token

  # A specific endpoint
  get "/residences" do
    # Which GET/POST params can be included in the request and what do they do?
    parameter :sort, "Sort the response. Can be sorted by #{ResidencesIndex::SORTABLE_FIELDS.join(',')}. They are comma separated and include - in front to sort in descending order. Example: -rooms,cost"
    parameter :number, "Which page number of results would you like.", scope: :page

    let(:number) { 1 }
    let(:sort) { "-rooms,cost" }

    # We can provide multiple examples for each endpoint, highlighting different aspects of them.
    example "Listing residences" do
      explanation "Retrieve all of the residences. They can be sorted, filtered and will be paginated."

      2.times { create(:residence, rooms: (1..6).to_a.sample) }

      do_request

      expect(status).to eq(200)
    end
  end
end

默认情况下,它看起来类似于RSpec提供的DSL,但引入了一些额外的方法:

  • header
  • parameter
  • explanation
  • 除了别的以外

这些允许我们描述端点如何工作,提供例子,并记录每个端点的不同输入和输出。

通过跑步bundle exec rake docs:generate,我们不仅可以看到测试是否通过(如果一个测试失败,它将阻止我们生成文档),还可以生成我们在配置文件中指定的输出文件。

下面是它生成的索引文件,它指向特定于单个资源的其他JSON文件:

{
  "resource": "Residences",
  "http_method": "GET",
  "route": "/residences",
  "description": "Listing residences",
  "explanation": "Retrieve all of the residences. They can be sorted, filtered and will be paginated.",
  "parameters": [
    {
      "name": "sort",
      "description": "Sort the response. Can be sorted by rooms,cost,bathrooms,square_feet. They are comma separated and include - in front to sort in descending order. Example: -rooms,cost"
    },
    {
      "scope": "page",
      "name": "number",
      "description": "Which page number of results would you like."
    }
  ],
  "response_fields": [

  ],
  "requests": [
    {
      "request_method": "GET",
      "request_path": "/residences?sort=-rooms%2Ccost&page[number]=1",
      "request_body": null,
      "request_headers": {
        "Accept": "application/vnd.api+json",
        "X-Api-Key": "bddc333e-dffc-44a9-b2dc-244dfd1f2abf",
        "Host": "example.org",
        "Cookie": ""
      },
      "request_query_parameters": {
        "sort": "-rooms,cost",
        "page": {
          "number": "1"
        }
      },
      "request_content_type": null,
      "response_status": 200,
      "response_status_text": "OK",
      "response_body": "{\n  \"data\": [\n    {\n      \"id\": \"1\",\n      \"type\": \"residences\",\n      \"attributes\": {\n        \"residence_type\": \"Detached\",\n        \"square_feet\": 2500,\n        \"rooms\": 5,\n        \"bathrooms\": 3,\n        \"address\": \"123 Blue Jays Way\",\n        \"city\": \"Toronto\",\n        \"province\": \"ON\",\n        \"country\": \"CA\",\n        \"postal_code\": \"M8X5B2\",\n        \"latitude\": null,\n        \"longitude\": null,\n        \"cost\": \"600000.0\"\n      }\n    },\n    {\n      \"id\": \"2\",\n      \"type\": \"residences\",\n      \"attributes\": {\n        \"residence_type\": \"Detached\",\n        \"square_feet\": 2500,\n        \"rooms\": 1,\n        \"bathrooms\": 3,\n        \"address\": \"123 Blue Jays Way\",\n        \"city\": \"Toronto\",\n        \"province\": \"ON\",\n        \"country\": \"CA\",\n        \"postal_code\": \"M8X5B2\",\n        \"latitude\": null,\n        \"longitude\": null,\n        \"cost\": \"600000.0\"\n      }\n    }\n  ],\n  \"links\": {\n    \"self\": \"http://example.org/residences?page%5Bnumber%5D=1&sort=-rooms%2Ccost\",\n    \"first\": \"http://example.org/residences?page%5Bnumber%5D=1&sort=-rooms%2Ccost\",\n    \"prev\": \"http://example.org/residences?page%5Bnumber%5D=1&sort=-rooms%2Ccost\",\n    \"next\": \"http://example.org/residences?page%5Bnumber%5D=1&sort=-rooms%2Ccost\",\n    \"last\": \"http://example.org/residences?page%5Bnumber%5D=1&sort=-rooms%2Ccost\"\n  }\n}",
      "response_headers": {
        "X-Frame-Options": "SAMEORIGIN",
        "X-XSS-Protection": "1; mode=block",
        "X-Content-Type-Options": "nosniff",
        "Content-Type": "application/json; charset=utf-8",
        "ETag": "W/\"4475a76defed21679ee33bd17c2b9fe2\"",
        "Cache-Control": "max-age=0, private, must-revalidate",
        "X-Request-Id": "0fb2f89c-9e60-4487-a5f2-e566aa31002f",
        "X-Runtime": "0.020782",
        "Content-Length": "969"
      },
      "response_content_type": "application/json; charset=utf-8",
      "curl": null
    }
  ]
}

因为它只是JSON,所以我们可以自由地使用静态网站构建器生成文档,例如Jekyll。这让我们可以自由灵活地用不同的编程语言添加示例,让我们的文档像我们希望的那样具有交互性,但同时也让它与我们的应用程序正在生成的文档保持同步。

我们可以手动将文件移动到杰基尔项目中,或者设置输出目录,将它们放在正确的位置data自动文件夹。

工具/产品

如果您不使用Rails或者不想让您的测试与您的文档混合在一起,有一个很棒的工具叫做SlateTripit这让我们可以用markdown编写文档。它非常类似于Stripe这样漂亮的三面板(带有多语言示例)文档。

其他几个需要调查的工具是API BlueprintApiary,这是一个付费解决方案,还附带免费层。

结论

我希望通过这篇文章,我能够介绍一些新的工具,这些工具可以用来为您的应用编程接口生成优秀的文档。

通过让需要使用您的应用编程接口的开发人员的生活更容易,您不仅在社区中建立了良好的信誉,而且很可能为您的公司带来更多的业务。开发人员越快理解并完成与您的应用编程接口的集成,您的团队在提供支持时就越少遇到麻烦。