第一章 创建 REST 服务简介

第一章 创建 REST 服务简介

本文介绍 IRIS® 中的 RESTREST 服务。

REST 简介

REST 命名自“Representational State Transfer”,具有以下属性:

  • REST 是一种架构风格,而不是一种格式。尽管 REST 经常使用 HTTP 来传输消息并使用 JSON 来传递数据,但也可以将数据作为 XML 或纯文本传递。 REST 利用现有的 Web 标准,例如 HTTPURLXMLJSON
  • REST 是面向资源的。通常,资源由 URL 标识并使用基于 HTTP 方法的操作,例如 GETPOSTPUTDELETE
  • REST 通常有少量开销。虽然它可以使用 XML 来描述数据,但它更常用的是 JSON,它是一种轻量级的数据包装器。 JSON 使用标签标识数据,但标签没有在正式的模式定义中指定,也没有明确的数据类型。

REST 服务简介

IRIS 2019.2 及更高版本中定义 REST 接口有两种方法:

  • 规范优先定义——首先创建一个 OpenAPI 2.0 规范,然后使用 API 管理工具生成 REST 接口的代码。
  • 手动编码 REST 接口。

使用规范优先的定义,REST 服务正式由以下组件组成:

  • 规范类(%REST.Spec 的子类)。此类包含 REST 服务的 OpenAPI 2.0 规范。 支持可以在规范中使用的几个扩展属性。
  • 调度类(%CSP.REST 的子类)。该类负责接收HTTP请求并调用实现类中合适的方法。
  • 一个实现类(%REST.Impl 的子类)。此类定义实现 REST 调用的方法。

API 管理工具生成实现类的存根版本,然后可以扩展它以包含必要的应用程序逻辑。 (逻辑当然可以调用此类之外的代码。)

%REST.Impl 类提供了可以调用的方法,以便设置 HTTP 标头、报告错误等。

Web 应用程序,通过 Web Gateway 提供对 REST 服务的访问。 Web 应用程序配置为启用 REST 访问并使用特定的调度类。 Web 应用程序还控制对 REST 服务的访问。

对这些组件遵循严格的命名约定。给定一个应用程序名称(appname),规范、调度和实现类的名称分别是 appname.specappname.dispappname.impl。 Web 应用程序默认命名为 /csp/appname,但可以使用其他名称。

支持规范优先范式。可以从规范生成初始代码,并且当规范发生变化时(例如,通过获取新的端点),可以重新生成该代码。后面的部分提供了更多细节,但现在,请注意,永远不应该编辑调度类,但可以修改其他类。此外,当重新编译规范类时,调度类会自动重新生成并更新实现类(保留编辑)。

手动编码 REST 服务

在 2019.2 之前的版本中,IRIS 不支持规范优先范式。一个 REST 服务形式上只包含一个调度类和一个 Web 应用程序。引用这种方式将 REST 服务定义为手动编码的 REST 服务。区别在于较新的 REST 服务定义的 REST 服务包含规范类,而手动编码的 REST 服务不包含。本书的“手动创建 REST 服务”附录描述了如何使用手动编码范例创建 REST 服务。同样,一些 API 管理实用程序使您能够使用手动编码的 REST 服务。

API 管理工具简介

为了帮助更轻松地创建 REST 服务, 提供了以下 API 管理工具:

  • 一个名为 /api/mgmntREST 服务,可以使用它来发现服务器上的 REST 服务,为这些 REST 服务生成 OpenAPI 2.0 规范,以及在服务器上创建、更新或删除 REST 服务。
  • ^%REST 例程,它提供了一个简单的命令行界面,可以使用它来列出、创建和删除 REST 服务。
  • %REST.API 类,可以使用它来发现服务器上的 REST 服务,为这些 REST 服务生成 OpenAPI 2.0 规范,以及在服务器上创建、更新或删除 REST 服务。

可以为这些工具设置日志记录,如本章后面所述。

有用的第三方工具包括 REST 测试工具,例如 PostMan (https://www.getpostman.com/) 和 Swagger 编辑器 (https://swagger.io/tools/swagger-editor/download/)。

创建 REST 服务概述

创建 REST 服务的推荐方式大致如下:

  1. 获取(或编写)服务的 OpenAPI 2.0 规范。
  2. 使用 API 管理工具生成 REST 服务类和关联的 Web 应用程序。请参阅以下章节:
  • “使用 /api/mgmnt/ 服务创建 REST 服务”
  • “使用 ^%REST 例程创建 REST 服务”
  • “使用 %REST.API 类创建 REST 服务”
  1. 修改实现类,使方法包含合适的业务逻辑。请参阅“修改实现类”一章。
  2. 可以选择修改规范类。请参阅“修改规范类”一章。例如,如果需要支持 CORS 或使用 Web 会话,请执行此操作。
  3. 如果需要安全性,请参阅“保护 REST 服务”一章。
  4. 使用服务的 OpenAPI 2.0 规范,生成文档,如“发现和记录 REST API”一章中所述。

对于第 2 步,另一种选择是手动创建规范类(将规范粘贴到其中),然后编译该类;此过程生成调度和存根实现类。也就是说,使用 /api/mgmnt 服务或 ^%REST 例程都不是绝对必要的。本书没有进一步讨论这种技术。

详细了解 REST 服务类

本节详细介绍了规范、调度和实现类。

Specification Class

规范类旨在定义 REST 服务要遵循的契约。此类扩展 %REST.Spec 并包含一个 XData 块,该块包含 REST 服务的 OpenAPI 2.0 规范。下面显示了一个部分示例:

Class YX.SPEC Extends %REST.Spec
{

XData OpenAPI [ MimeType = application/json ]
{
    {
      "swagger":"2.0",
      "info":{
        "version":"1.0.0",
        "title":"Swagger Petstore",
        "description":"A sample API that uses a petstore as an example to demonstrate features in the swagger-2.0 specification",
        "termsOfService":"http://swagger.io/terms/",
        "contact":{
          "name":"Swagger API Team"
        },
        "license":{
          "name":"MIT"
        }
      }
    }
}

}

可以通过替换或编辑 XData 块中的规范来修改此类。还可以根据需要添加类参数、属性和方法。每当编译规范类时,编译器都会重新生成调度类并更新实现类。

Dispatch Class

调用 REST 服务时直接调用调度类。下面显示了一个部分示例:

Class YX.DISP Extends %CSP.REST [ GeneratedBy = YX.SPEC.cls, ProcedureBlock ]
{

/// The class containing the RESTSpec which generated this class
Parameter SpecificationClass = "petstore.spec";

/// Default the Content-Type for this application.
Parameter CONTENTTYPE = "application/json";

/// By default convert the input stream to Unicode
Parameter CONVERTINPUTSTREAM = 1;

/// The default response charset is utf-8
Parameter CHARSET = "utf-8";

XData UrlMap [ XMLNamespace = "http://www.intersystems.com/urlmap" ]
{
<Routes>
  <Route Url="/pets" Method="get" Call="findPets" />
  <Route Url="/pets" Method="post" Call="addPet" />
  <Route Url="/pets/:id" Method="get" Call="findPetById" />
  <Route Url="/pets/:id" Method="delete" Call="deletePet" />
</Routes>
}

}

请注意,SpecificationClass 参数指示相关规范类的名称。 URLMap XData 块(URL 映射)定义此 REST 服务中的调用。

在这些项目之后,该类包含 URL 映射中列出的方法的定义。这是一个例子:

ClassMethod deletePet(pid As %String) As %Status
{
    Try {
        If '##class(%REST.Impl).%CheckAccepts("application/json") Do ##class(%REST.Impl).%ReportRESTError(..#HTTP406NOTACCEPTABLE,$$$ERROR($$$RESTBadAccepts)) Quit
        If ($number(pid,"I")="") Do ##class(%REST.Impl).%ReportRESTError(..#HTTP400BADREQUEST,$$$ERROR($$$RESTInvalid,"id",id)) Quit
        Set response=##class(petstore.impl).deletePet(pid)
        Do ##class(petstore.impl).%WriteResponse(response)
    } Catch (ex) {
        Do ##class(%REST.Impl).%ReportRESTError(..#HTTP500INTERNALSERVERERROR,ex.AsStatus())
    }
    Quit $$$OK
}

请注意以下几点:

  • 此方法调用实现类中的同名方法(本例中为 petstore.impl)。它从该方法获取响应并调用 %WriteResponse() 将响应写回调用者。 %WriteResponse() 方法是一种继承方法,存在于所有实现类中,这些实现类都是 %REST.Impl 的子类。
  • 此方法进行其他检查,并在出现错误时调用 %REST.Impl 的其他方法。

重要提示:因为调度类是一个生成的类,你永远不应该编辑它。 提供了覆盖部分调度类而不对其进行编辑的机制。

Implementation Class

实现类旨在保存 REST 服务的实际内部实现。可以(并且应该)编辑此类。它最初类似于以下示例:

/// A sample API that uses a petstore as an example to demonstrate features in the swagger-2.0 specification<br/>
/// Business logic class defined by RESTSpec in petstore.spec<br/>
Class petstore.impl Extends %REST.Impl [ ProcedureBlock ]
{

/// If ExposeServerExceptions is true, then details of internal errors will be exposed.
Parameter ExposeServerExceptions = 0;

/// Returns all pets from the system that the user has access to<br/>
/// The method arguments hold values for:<br/>
///     tags, tags to filter by<br/>
///     limit, maximum number of results to return<br/>
ClassMethod findPets(tags As %ListOfDataTypes(ELEMENTTYPE="%String"), limit As %Integer) As %Stream.Object
{
    //(Place business logic here)
    //Do ..%SetStatusCode(<HTTP_status_code>)
    //Do ..%SetHeader(<name>,<value>)
    //Quit (Place response here) ; response may be a string, stream or dynamic object
}

...

实现类的其余部分包含与此类似的附加存根方法。在每种情况下,这些存根方法都具有遵循 REST 服务规范定义的契约的签名。请注意,对于 options 方法, 不会生成存根方法供实现。相反,%CSP.REST 类会自动执行所有选项处理。

为 API 管理功能启用日志记录

要启用 API 管理功能的日志记录,请在终端中输入以下内容:

 set $namespace="%SYS"
 kill ^ISCLOG
 set ^%ISCLOG=5
 set ^%ISCLOG("Category","apimgmnt")=5

然后系统将条目添加到 ^ISCLOG 全局,以用于对 API 管理端点的任何调用。

要将日志写入文件(为了便于阅读),请输入以下内容(仍在 %SYS 命名空间内):

 do ##class(%OAuth2.Utils).DisplayLog("filename")

其中 filename 是要创建的文件的名称。该目录必须已经存在。如果文件已存在,则将其覆盖。

要停止记录,请输入以下内容(仍在 %SYS 命名空间中):

 set ^%ISCLOG=0
 set ^%ISCLOG("Category","apimgmnt")=0

查看日志

启用 HTTP 请求的日志记录后,日志条目将存储在 ^ISCLOG 全局中,该全局位于 %SYS 命名空间中。

要使用管理门户查看日志,请导航到 System Explorer > Globals 并查看 ISCLOG 全局(不是 %ISCLOG)。确保位于 %SYS 命名空间中。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,039评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,426评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,417评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,868评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,892评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,692评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,416评论 3 419
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,326评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,782评论 1 316
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,957评论 3 337
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,102评论 1 350
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,790评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,442评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,996评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,113评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,332评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,044评论 2 355

推荐阅读更多精彩内容