作者

Sales Engineer at Intersystems
文章 Jeff Liu · 6 hr 前 6m read

如何将您的应用程序接口添加到互操作性产品中

我以前可能提到过这一点:我认为可视化跟踪(Visual Traces),即包含每个步骤完整内容的序列图,是 IRIS 数据平台的一项神奇功能!以可视化跟踪的方式提供有关 API 内部工作原理的详细信息,对 IRIS 平台上的项目非常有用。当然,这适用于我们没有开发高负荷解决方案的情况,在这种情况下,我们根本没有时间保存/读取信息。对于所有其他情况,欢迎阅读本教程!

 

我将采用 "规范先行 "的方法,因此第一步将是创建规范。我让 Codex 创建了一个 OpenAPI 规范示例,得到了以下 JSON:

{
  "swagger": "2.0",
  "info": {
    "version": "1.0.0",
    "title": "Sample Spec API",
    "description": "Example Swagger 2.0 specification"
  },
  "basePath": "/sample-api",
  "schemes": [
    "http"
  ],
  "consumes": [
    "application/json"
  ],
  "produces": [
    "application/json"
  ],
  "paths": {
    "/sample/echo": {
      "post": {
        "summary": "Accepts JSON payload and returns another JSON payload",
        "operationId": "postSampleEcho",
        "parameters": [
          {
            "in": "body",
            "name": "body",
            "required": true,
            "schema": {
              "$ref": "#/definitions/SampleRequest"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "schema": {
              "$ref": "#/definitions/SampleResponse"
            }
          }
        }
      }
    }
  },
  "definitions": {
    "SampleRequest": {
      "type": "object",
      "required": [
        "name",
        "count"
      ],
      "properties": {
        "name": {
          "type": "string",
          "example": "test"
        },
        "count": {
          "type": "integer",
          "format": "int32",
          "example": 1
        }
      }
    },
    "SampleResponse": {
      "type": "object",
      "properties": {
        "status": {
          "type": "string",
          "example": "ok"
        },
        "message": {
          "type": "string",
          "example": "Request processed successfully"
        }
      }
    }
  }
}

接下来是创建缓存类:specdispimpl。我将为此使用 IRIS 系统 API。让我们在 Postman(或 CURL)中运行以下请求,并将生成的文件导出到项目中:

curl --location 'http://localhost:52773/api/mgmnt/v2/dev/Sample.REST.API?IRISUsername=_system&IRISPassword=SYS' \
--header 'Content-Type: application/json' \
--data '/// your spec here ///'

其中:

  • dev - 我的命名空间
  • Sample.REST.API - API 类包

之后,我们将需要一个业务服务。我建议创建一个通用的基础服务,并在此基础上扩展我们的特定服务。这对于为我们未来的每个 API 提供进入互操作性产品的单独入口是必要的。以下是该基础服务的完整代码:

Class Sample.REST.Service.Core Extends (Ens.BusinessService, %REST.Impl)
{

/// Call this method from your .impl class</br> 
/// pTarget - the Business Process that processes the message</br>
/// pPayload - the body of the HTTP request
ClassMethod OnMessage(pTarget As %String, pPayload As %DynamicObject) As %DynamicObject
{
    Do ..%SetContentType("application/json")
    
    Set input = ##class(Ens.StreamContainer).%New()
    Set input.Stream = ##class(%Stream.GlobalCharacter).%New()
    Do input.Attributes.SetAt(pTarget, "Target")
    
    Do pPayload.%ToJSON(input.Stream)
    
    Return:$CLASSNAME()'=$GET($$$ConfigClassName($CLASSNAME())) ..Error($$$ERROR($$$EnsErrBusinessDispatchNameNotRegistered, $CLASSNAME()))
	
	Set tSC = ##class(Ens.Director).CreateBusinessService($CLASSNAME(), .service)
	Return:$$$ISERR(tSC) ..Error(tSC)
	
	Set tSC = service.ProcessInput(input, .output)
	Return:$$$ISERR(tSC) ..Error(tSC)

    Return ..Success(output)
}

ClassMethod Error(pStatus As %Status) As %DynamicObject
{
    Do ..%SetStatusCode(##class(%CSP.REST).#HTTP500INTERNALSERVERERROR)
    Do ##class(%CSP.REST).StatusToJSON(pStatus, .json)
    Return json
}

ClassMethod Success(pOutput As Ens.StreamContainer) As %DynamicObject
{
    Do ..%SetStatusCode(##class(%CSP.REST).#HTTP200OK)

    If $iso(pOutput) {
        // HTTP status can be set during the processing of the call in the Business Process
        Do:pOutput.Attributes.GetAt("Status")'="" ..%SetStatusCode(pOutput.Attributes.GetAt("Status"))
        Set stream = pOutput.StreamGet()
		Return:$iso(stream)&&(stream.Size>0) {}.%FromJSON(stream)
	}

    Return ""
}

Method OnProcessInput(pInput As Ens.StreamContainer, Output pOutput As Ens.StreamContainer) As %Status
{
    Return ..SendRequestSync(pInput.Attributes.GetAt("Target"), pInput, .pOutput)
}
}

一些实现细节。我使用 Ens.StreamContainer 在业务服务和业务流程之间传递 JSON。OnMessage() 方法:

  1. impl 类调用
  2. 接收作为 %DynamicObject 的 HTTP 请求体
  3. 创建业务服务实例
  4. 通过 OnProcessInput() 将消息从服务发送到处理程序业务流程(请参阅 pTarget 参数)。
  5. 并将从业务流程收到的 %DynamicObject 作为 HTTP 响应返回

接下来,让我们为消息创建一个简单的处理程序:

Class Sample.REST.Process.Echo Extends Ens.BusinessProcess
{

Method OnRequest(pRequest As Ens.StreamContainer, Output pResponse As Ens.StreamContainer) As %Status
{
    Set jsonIn = {}.%FromJSON(pRequest.StreamGet())
    Set jsonOut = {"status": "ok", "message": ($$$FormatText("Request processed for %1 with count %2", jsonIn.name, jsonIn.count))}

    Set pResponse = ##class(Ens.StreamContainer).%New()
    Set pResponse.Stream = ##class(%Stream.GlobalCharacter).%New()
    Do jsonOut.%ToJSON(pResponse.Stream)

    Return $$$OK
}
}

最后一个缓存类是 Sample.REST.Service.Core 的子类:

Class Sample.REST.Service.API Extends Sample.REST.Service.Core
{

ClassMethod OnGetConnections(Output pArray As %String, pItem As Ens.Config.Item)
{
	Set pArray(##class(Sample.REST.Process.Echo).%ClassName(1)) = ""
}
}

在这里,您只需覆盖 OnGetConnections() 以描述与生产中业务流程的连接。这不会影响功能,但对于在生产用户界面中建立正确的链接是必要的。

⚠️ 这里最重要的是:必须为生产中的业务主机使用类名。这对我们的示例能否正常运行至关重要,而且我认为这是一个好的做法。

现在,我们可以为 impl 类添加实现:

ClassMethod postSampleEcho(body As %DynamicObject) As %DynamicObject
{
    Return ##class(Sample.REST.Service.API).OnMessage(##class(Sample.REST.Process.Echo).%ClassName(1), body)
}

编码部分已经完成。接下来,我们需要添加一个名为 /sample-api 的 Web 应用程序(与规范中的 basePath 相同),将 Sample.REST.API.disp 类设置为派发类,并在生产中创建以下业务主机:

  1. Sample.REST.Service.API
  2. Sample.REST.Process.Echo

我们应该得到生产系统的外观:

Production UI

让我们尝试执行请求:

curl --location 'http://localhost:52773/sample-api/sample/echo' \
--header 'Content-Type: application/json' \
--data '{
  "name": "test",
  "count": 1
}'

我们将得到响应:

{
    "status": "ok",
    "message": "Request processed for test with count 1"
}

此外,在 Sample.REST.Service.API 服务消息中,我们还将获得一个可视化跟踪,详细说明我们的调用。

以上就是我今天要向大家介绍的关于互操作性产品中 REST API 的全部内容。我建议大家使用iris-web-swagger-ui以方便的形式向外部团队提供 OpenAPI 规范。并使用内置的JWT 身份验证来保证安全性。我相信这就是 IRIS 数据平台上和谐的 API 的样子。

欢迎提出任何问题。