Welcome

首页 / 软件开发 / 数据结构与算法 / 如何设计一套事件日志API

如何设计一套事件日志API2015-03-12 infoq Saul Caganoff 译:邵

简介

业界目前已经在以下这一点上达成了强烈的共识:API的设计应该是按照前端到后端的次序进行的,将重点放在开发者对API的使用上。在某个发展兴旺的商业体中,通常会存在着许多互相竞争的产品与API的实现,而易于使用、并且设计良好的API在吸引与保留开发者这一点更有优势。此外,新的工具不断涌现,它们不仅能够帮助开发者按照迭代方式设计API,而且能够帮助开发者学习与使用这些API。

API设计中的关键因素在于“人”,这意味着API设计工具与文档格式必须便于人的读写,这一段时期以来的API设计标准都在强调“以人为本”。API Blueprint在这一领域是较早使用Markdown作为格式的产品,而进行API设计的广大开发者与商业分析人士都熟悉这种格式。

去年晚些时候,Mulesoft发布了自己的RESTful API建模语言——RAML。这门语言本身只是一种具有专利的第三方语言,但由于它的一系列特色,使得广大的API社区都对它产生了浓厚兴趣:

RAML本身是开源的,并且它内置了一系列工具和对普通语言的解析器。它的开发始终处于一个API的指导委员会和一些用户体验从业人员的高度关注之下,并且围绕着RAML所开发的第三方工具也在形成自己的生态系统。

Mulesoft首先尝试了Swagger这种文档格式,但随即意识到这种格式标准更适用于为一个现有的API进行文档化,而不适用于从头开始设计的新API。而它们所需的是一种支持简洁的、专注于人类语言的API设计方式的格式,RAML正满足了这一需求。

API的描述通常是很冗余并且容易重复的,这有碍于它的结构、可理解性和对它的使用。RAML引入了一些新的语言特性,支持结构化的文件、继承,以及对横切关注点的处理。这些特性正是本文所关注的要点。

RAML本身不会带来良好的API设计,这门语言及其工具也没有任何内置的“最佳实践”。正如MuleSoft的CTO Uri Sarid所说,RAML的目标是:“以一种开放的、简单且简洁的规格对API进行描述,它能够捕捉到API的结构,并鼓励基于模式的设计和重用,它将有助于释放API的商业潜力。”

RAML并不负责API的实现,它仅仅是一门规格说明语言。现在仅有为数不多的一些开源工具能够实现由RAML语言所描述的API。APIKit能够将一个RAML规格转变为Mule ESB流,如果你的运行时平台使用的是Mule ESB,那这一工具能起到些作用。JAX-RS Codegen的使用更加广泛,因为它能够将一个RAML规格转变为JAX-RS Java代码。毫无疑问,对其它语言和平台的支持,将在很大程度上决定RAML最终是否能够取得成功。

本文的目的是以一个示例为你展示如何使用RAML设计一个简单的,但又实用的API,并展现RAML的一些选择性。而不是作为与其它API设计或描述格式进行比较的依据,例如API Blueprint、IO Docs或Swagger。它令人振奋的地方在于,我们现在设计的选择上有了一种可行并且有竞争力的生态系统,它有希望建立起RESTful API设计与规格的共识。

API示例的需求

我们将要设计的这个示例API的功能是将事件日志记录到一个流中,以支持在线分析与报表业务。使用日志文件保存正在运行的软件的状态与进度,这种模式大概与计算机本身历史一样长。但随着系统变得越来越分布式,负载也被分到大量系统中(或许只是短暂的发生),使用文件来管理及分析日志成为了一种不可能的任务。目前流行的设计模式是将日志看作为事件流。这样一来,这个Eventlog API就包括了以下一些基本需求:

允许第三方应用将某个事件写入某个命名的事件流当中。

事件本身带有少量的必要属性,同时还有可扩展的“上下文”属性。

支持获取一个事件流。

获取某个时间段内的一系列事件。

获取一个分页的事件列表。

支持对所获取的事件数量加以限制,合理的默认值设为100。

支持通过Id获取到某个事件。

事件是不可变的,既不能被删除、也不能被修改。

该API的读取是公开的,但写入操作必须由一个OAuth 2.0安全性schema进行保护。

现在让我们开始对RAML的探索,看看如何使用它描述一个满足以上需求的API。

在本文中,我们将使用Anypoint API设计器编写RAML。这个设计器允许我们在设计过程中查看可交互的文档,并且能够对API进行模拟(mock)。我们将从一个简单的规格开始,随后再使用RAML中更高级的特性,以使我们的规格更加DRY。REST API的规格有时重复性很高,包含大量的样板代码,而且对于非常接近的资源信息也不得不重复编写它们的规格。RAML提供的特性能够帮助你避免或是管理这种重复性,包括资源类型(resourceType)、trait和文件中包含的指令。我们会在过程中逐步讲解这些特性,在示例的最后将讲述安全性规格。

一个简单的RAML API

你可以在raml.org网站上下载到RAML的文档与入门指南,包括完整的RAML规格说明。在这个示例的开发中,我使用了Anypoint API设计器,它包含了一个在线的RAML编辑器。

定义资源

首先,这个事件日志API包含了两种主要的资源:一个事件集合,我们将其称为一个事件流;以及每个独立的事件对象自身。对于事件流来说,我们需要一个POST方法,在事件流中创建一个新的事件,还需要一个GET方法以返回流中的事件。可以通过事件流名称和事件Id获取每个独立的事件。下面这段代码片段展示了这个规格的相应RAML代码:

#%RAML 0.8# Basic starter raml with two resources and corresponding methods.title: Eventlog APIversion: 1.0baseUri: http://eventlog.example.org/{version}/streams/{streamName}:displayName: A Named Streamdescription: A stream is a collection of related events. A Named Stream has been defined by the user to contain a list of related events. Named Streams are created by POSTing an event to a Named Stream.get:description: Get a list of events in this stream.post:description: Create a new event in this stream./streams/{streamName}/{eventId}:get:description: Get a particular event by its Id.