REST easy with kbmMW #20 – OpenAPI and Swagger UI
2021-06-22 07:07
标签:路径 pos 因此 top file 17. margin and 是什么 即将推出的kbmMW更新不仅是一些bug修正,同时将包含一个新的主要功能:客户端存根生成器框架。 那什么是客户端存根生成器框架呢? 他是一个基于smart services基础上,可以生成由各种类型的客户端直接使用的代码,以访问基于kbmMW应用服务器的HTTP smart services。 当前,kbmMW已经实现智能客户端(smart client)功能,通过这个功能,可以轻松实现客户端来访问smart services中的功能。由于智能客户端依赖于后期绑定,所以开发者无法通过IDE及编译器的帮助,来获得有关参数及其类型。因此,编译器还需要生成一些代码,为IDE及编译器,来解释服务端发布的函数及方法。 上面这个问题,正是客户端存根生成器要解决的问题,但是,本文不会讨论如何为智能服务生成Delphi客户端存根,因为尽管已经做了这方面的准备工作,但这个特定功能可能不会在即将发布的版本中完整实现。相反,我将介绍利用存根生成器框架来实现另一个更复杂的代码集,满足REST世界中的典型需求。一年多前,当我咨询大公司做Java代码时,认识到了这一点。 在Java世界中,使用当时被称为Swagger的东西来记录REST接口是一个事实上的标准。后来它被重命名为OpenAPI,现在得到了绝大多数支持REST的开发者的认可和支持。 OpenAPI提供了REST接口的描述,可以用于文档,也可以用于为各种开发环境自动生成(存根)代码,使这些环境可以轻松利用通过REST接口发布的功能。(Swagger 是一个规范和完整的框架,用于生成、描述、调用和可视化 RESTful 风格的 Web 服务。总体目标是使客户端和文件系统作为服务器以同样的速度来更新。文件的方法,参数和模型紧密集成到服务器端的代码,允许API来始终保持同步。) 您可以在此处阅读有关OpenAPI的更多信息: https://swagger.io/ https://blog.csdn.net/sanyaoxu_2/article/details/80555328 OpenAPI计划不仅生成了事实上的标准,还生成了可用于生成,编辑,查看和测试REST接口描述的各种工具(通常称为Swagger文件)。 其中一个工具是Swagger-UI(用户界面),它由Javascript和HTML组成,可以由Web服务器提供,为服务器中公开的REST接口提供简单易用的用户界面。 kbmMW现在完全支持所有这些。 让我们简单地开始使用Swagger-UI展示kbmMW SimpleInvocation演示服务器的REST接口是什么样的:
在左侧,可以看到公开的REST接口的OpenAPI声明,右侧可以看到用户友好的界面,通过简单的按钮点击可以调用这些界面。填充参数甚至REST方法也很容易。 如果我向右滚动到AddNumbers方法,然后单击该栏,它会打开其他信息,以及一个让我们尝试REST调用的按钮。
这非常酷! 那么我们如何使OpenAPI启用支持REST的应用服务器呢? 这真的很容易。 要返回REST服务的OpenAPI规范,我们只需在Unit2中向服务添加另一个REST公开方法。 我们可以根据您的喜好命名方法及其REST路径,但我们应该提供正确的responseMimeType。OpenAPI描述的标准用YAML表示,幸运的是kbmMW完全支持。它也允许在JSON中生成OpenAPI描述,但它更像是一种与不支持YAML的系统兼容的方法。所以在这个例子中,我们在mimetype中指定响应将是YAML。 OpenAPI函数中的代码非常简单。它只调用OpenAPI存根生成器的GenerateOpenAPI方法,服务为“OpenAPI‘ified”,并可选择设置字符串。设置字符串可以为空 在此示例中,设置字符串包含值 原因是有两种有效的方法可以为REST接口生成OpenAPI规范,这些接口可以内联或通过引用获取或返回对象。 内联意味着每个对象都会详细解释它可以在REST调用的所有描述中使用的每个位置,而引用意味着在需要时描述和引用OpenAPI样式组件(对象)。引用是默认值。但是在示例代码中,我选择在kbmMW配置框架的帮助下对其进行配置。我们可以编写:inline:false或inline:true,但是样本会询问配置OpenAPI.inline值的当前值,该值可以是true或false。如果没有找到这样的值,kbmMW将使用默认值false(如=后面所示)。 也可以指定JSON是首选。这只需要将json:true添加到设置字符串,如下所示: 显然,这也可以像内联一样进行配置。 但是我们保持原样,因此OpenAPI函数的输出将是对服务中REST方法的YAML格式化OpenAPI描述。 因此,如果我们使用浏览器打开URL:// localhost:888 / myserver / api,我们将获得完整的OpenAPI描述: 如果你愿意,可以随意学习。您可能会注意到有几个地方,有设施可以添加摘要和说明。例如,检查addnumbers调用: 摘要和描述来自哪里? 看一下Unit2.pas中AddNumbers函数的定义,很明显: kbmMW_Rest属性中甚至有一个id值。OpenAPI要求每个REST路径必须具有唯一ID。kbmMW将自动尝试生成一个,但您可以通过id语法选择自己的ID名称,如上所示。id,summary,description和resultDescription都是(以kbmMW为单位)全部可选。如果OpenAPI需要描述性值且未给出任何值,则kbmMW提供默认值。 所以现在我们可以生成有效的OpenAPI描述。我们如何让我们的基于kbmMW的应用服务器使用Swagger-UI呈现它们 因为kbmMW可以充当Web服务器,所以这实际上也很容易。我们只需将TkbmMWFilePool实例添加到主窗体(Unit1)并将服务数据模块(Unit2)的FilePool属性设置为指向它。
现在,kbmMW将作为常规Web服务器工作,并在未找到要调用的REST函数时尝试提供文件。 在与SimpleInvocation服务器可执行文件相同的目录中,您应该创建一个名为MyServer的目录(以匹配服务),在其下面,我们添加一个api目录,两者都只是为了匹配Unit2中OpenAPI函数的逻辑路径。实际上,您不必使用此特定路径层次结构,但我已选择此类演示。
在api目录中,我们将放置从https://swagger.io/tools/swagger-ui/下载的文件
然后 和 您可以将dist文件夹中的所有文件逐个下载到api \ dist目录,也可以通过克隆或下载按钮下载所有文件。如果您执行稍后操作,则打开下载的zip文件并将包含内容的dist文件夹解压缩到api目录。 最后将一个名为index.html的文件添加到api目录中。您可以从以下位置复制/粘贴其内容: 现在你准备摇滚了。 启动服务器。然后启动浏览器并输入: 这指示kbmMW提供index.html文件,该文件反过来请求生成Swagger-UI接口所需的剩余文件。最后,我们告诉Swagger-UI从/ myserver / api URL加载OpenAPI描述(如果你记得的话,将在Unit2中调用OpenAPI函数)。 您现在应该得到类似于此博客文章开头所示的视图。 在Swagger-UI界面中,您可以为kbmMW公开的所有REST功能生成服务器骨架和客户端存根。 快乐的摇摆!!! 如果你喜欢kbmMW,请分享这个词。转发博客文章,让其他人了解该产品! https://components4developers.blog/2018/12/31/rest-easy-with-kbmmw-20-openapi/ REST easy with kbmMW #20 – OpenAPI and Swagger UI 标签:路径 pos 因此 top file 17. margin and 是什么 原文地址:https://www.cnblogs.com/kinglandsoft/p/rest-easy-with-kbmmw-20-openapi.html [kbmMW_Rest(‘method:get, path: "api", responseMimeType:"application/x-yaml"‘)]
function OpenAPI:string;
// Return OpenAPI specification.
function TkbmMWCustomService2.OpenAPI:string;
begin
// Return OpenAPI specification for all REST methods in this service
// as YAML. Add the ASettings value: ‘json:true‘ to return the specification
// as JSON.
// Add ‘servers: [ "url1", "url2",.. "urln" ]‘ to ASettings if you want to
// embed server location information in the specification.
// Add ‘inline:true‘ to inline object definitions instead of using $ref.
// The example in the next line utilize the configuration framework to make
// the setting easily configurable.
Result:=TkbmMWSmartOpenAPIStubGenerator.GenerateOpenAPI(‘‘,self,‘inline:$(OpenAPI.inline=false)‘);
end;
inlinei :$(OpenAPI.inline=false)
inline:$(OpenAPI.inline=false), json:true
openapi: "3.0.0"
info:
title: SMARTDEMO
description: "HTTP smart service supp. FastCGI"
version: "1"
paths:
/myserver/api:
get:
operationId: get_myserver_api
responses:
"200":
content:
application/x-yaml:
schema:
type: string
description: "Success response"
/myserver/helloworld:
get:
operationId: get_myserver_helloworld
responses:
"200":
content:
text/plain:
schema:
type: string
description: "Success response"
/myserver/now1:
get:
operationId: get_myserver_now1
responses:
"200":
content:
text/plain:
schema:
type: string
format: date-time
description: "Success response"
/myserver/now2:
get:
operationId: get_myserver_now2
responses:
"200":
content:
text/plain:
schema:
type: number
format: double
description: "Success response"
/myserver/echostring/{AString}:
get:
operationId: get_myserver_echostring__AString_
parameters:
-
in: path
name: AString
required: true
schema:
type: string
responses:
"200":
content:
text/plain:
schema:
type: string
description: "Success response"
/myserver/myechostring/{AString}:
get:
operationId: get_myserver_myechostring__AString_
parameters:
-
in: path
name: AString
required: true
schema:
type: string
responses:
"200":
content:
text/plain:
schema:
type: string
description: "Success response"
/myserver/echourl:
get:
operationId: get_myserver_echourl
responses:
"200":
content:
text/plain:
schema:
type: string
description: "Success response"
/myserver/echoheader:
get:
operationId: get_myserver_echoheader
parameters:
-
in: header
name: Accept
required: true
schema:
type: string
responses:
"200":
content:
text/plain:
schema:
type: string
description: "Success response"
/myserver/echoanyheader/{AHeaderName}:
get:
operationId: get_myserver_echoanyheader__AHeaderName_
parameters:
-
in: path
name: AHeaderName
required: true
schema:
type: string
responses:
"200":
content:
text/plain:
schema:
type: string
description: "Success response"
/myserver/echocookie:
get:
operationId: get_myserver_echocookie
parameters:
-
in: cookie
name: MyCookie
required: true
schema:
type: string
responses:
"200":
content:
text/plain:
schema:
type: string
description: "Success response"
/myserver/echoreversedstring:
post:
operationId: post_myserver_echoreversedstring
requestBody:
required: true
content:
text/plain:
schema:
type: string
responses:
"200":
content:
text/plain:
schema:
type: string
description: "Success response"
/myserver/echobytes:
post:
operationId: post_myserver_echobytes
requestBody:
required: true
content:
text/plain:
schema:
type: string
format: byte
responses:
"200":
content:
text/plain:
schema:
type: string
format: byte
description: "Success response"
/myserver/echoreversedconfigstring:
get:
operationId: get_myserver_echoreversedconfigstring
responses:
"200":
content:
text/plain:
schema:
type: string
description: "Success response"
/someabspath/addnumbers:
get:
summary: "Adds two numbers and returns result"
operationId: add_numbers
parameters:
-
in: query
name: arg1
required: true
description: "First numeric argument"
schema:
type: integer
format: int32
-
in: query
name: arg2
required: true
description: "Second numeric argument"
schema:
type: integer
format: int32
responses:
"200":
content:
text/plain:
schema:
type: integer
format: int32
description: "The result of the added numbers"
/myserver/storeperson:
post:
operationId: post_myserver_storeperson
requestBody:
required: true
content:
text/plain:
schema:
"$ref": "#/components/schemas/person"
responses:
"200":
content:
text/plain:
schema:
type: integer
format: int32
description: "Success response"
/myserver/getperson/{id}:
get:
operationId: get_myserver_getperson__id_
parameters:
-
in: path
name: id
required: true
schema:
type: integer
format: int32
responses:
"200":
content:
application/json:
schema:
"$ref": "#/components/schemas/person"
description: "Success response"
/myserver/getpersons:
get:
operationId: get_myserver_getpersons
responses:
"200":
content:
application/json:
schema:
type: array
items:
"$ref": "#/components/schemas/person"
description: "Success response"
components:
schemas:
person:
properties:
Name:
type: string
Address:
type: string
Age:
type: integer
format: int32
type: object
title: person
如果你愿意,可以随意学习。您可能会注意到有几个地方,有设施可以添加摘要和说明。例如,检查addnumbers调用:
YAML
/someabspath/addnumbers:
get:
summary: "Adds two numbers and returns result"
operationId: add_numbers
parameters:
-
in: query
name: arg1
required: true
description: "First numeric argument"
schema:
type: integer
format: int32
-
in: query
name: arg2
required: true
description: "Second numeric argument"
schema:
type: integer
format: int32
responses:
"200":
content:
text/plain:
schema:
type: integer
format: int32
description: "The result of the added numbers"
/someabspath/addnumbers:
get:
summary: "Adds two numbers and returns result"
operationId: add_numbers
parameters:
-
in: query
name: arg1
required: true
description: "First numeric argument"
schema:
type: integer
format: int32
-
in: query
name: arg2
required: true
description: "Second numeric argument"
schema:
type: integer
format: int32
responses:
"200":
content:
text/plain:
schema:
type: integer
format: int32
description: "The result of the added numbers"
/someabspath/addnumbers:
get:
summary: "Adds two numbers and returns result"
operationId: add_numbers
parameters:
-
in: query
name: arg1
required: true
description: "First numeric argument"
schema:
type: integer
format: int32
-
in: query
name: arg2
required: true
description: "Second numeric argument"
schema:
type: integer
format: int32
responses:
"200":
content:
text/plain:
schema:
type: integer
format: int32
description: "The result of the added numbers"
// Add two numbers.
// It can be called from regular clients, smart clients
// and REST clients.
// It can be called from a browser like this:
// http://.../someabspath/addnumbers?arg1=10&arg2=20
[kbmMW_Method]
[kbmMW_Rest(‘method:get, path: "/someabspath/addnumbers", ‘+
‘id:"add_numbers", ‘+
‘summary:"Adds two numbers and returns result", ‘+
‘resultDescription:"The result of the added numbers"‘)]
function AddNumbers([kbmMW_Rest(‘value: "$arg1", required: true, description:"First numeric argument"‘)] const AValue1:integer;
[kbmMW_Rest(‘value: "$arg2", required: true, description:"Second numeric argument"‘)] const AValue2:integer;
[kbmMW_Arg(mwatRemoteLocation)] const ARemoteLocation:string):integer;
DOCTYPE html>
html lang="en">
head>
meta charset="UTF-8">
title>Swagger Editortitle>
style>
* {
box-sizing: border-box;
}
body {
font-family: Roboto,sans-serif;
font-size: 9px;
line-height: 1.42857143;
color: #444;
margin: 0px;
}
#swagger-editor {
font-size: 1.3em;
}
.container {
height: 100%;
max-width: 880px;
margin-left: auto;
margin-right: auto;
}
#editor-wrapper {
height: 100%;
border:1em solid #000;
border:none;
}
.Pane2 {
overflow-y: scroll;
}
style>
link href="./dist/swagger-editor.css" rel="stylesheet">
link rel="icon" type="image/png" href="./dist/favicon-32x32.png" sizes="32x32" />
link rel="icon" type="image/png" href="./dist/favicon-16x16.png" sizes="16x16" />
head>
body>
div id="swagger-editor">div>
script src="./dist/swagger-editor-bundle.js"> script>
script src="./dist/swagger-editor-standalone-preset.js"> script>
script>
window.onload = function() {
// Build a system
const editor = SwaggerEditorBundle({
dom_id: ‘#swagger-editor‘,
layout: ‘StandaloneLayout‘,
presets: [
SwaggerEditorStandalonePreset
]
})
window.editor = editor
}
script>
svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="position:absolute;width:0;height:0">
defs>
symbol viewBox="0 0 20 20" id="unlocked">
path d="M15.8 8H14V5.6C14 2.703 12.665 1 10 1 7.334 1 6 2.703 6 5.6V6h2v-.801C8 3.754 8.797 3 10 3c1.203 0 2 .754 2 2.199V8H4c-.553 0-1 .646-1 1.199V17c0 .549.428 1.139.951 1.307l1.197.387C5.672 18.861 6.55 19 7.1 19h5.8c.549 0 1.428-.139 1.951-.307l1.196-.387c.524-.167.953-.757.953-1.306V9.199C17 8.646 16.352 8 15.8 8z">path>
symbol>
symbol viewBox="0 0 20 20" id="locked">
path d="M15.8 8H14V5.6C14 2.703 12.665 1 10 1 7.334 1 6 2.703 6 5.6V8H4c-.553 0-1 .646-1 1.199V17c0 .549.428 1.139.951 1.307l1.197.387C5.672 18.861 6.55 19 7.1 19h5.8c.549 0 1.428-.139 1.951-.307l1.196-.387c.524-.167.953-.757.953-1.306V9.199C17 8.646 16.352 8 15.8 8zM12 8H8V5.199C8 3.754 8.797 3 10 3c1.203 0 2 .754 2 2.199V8z"/>
symbol>
symbol viewBox="0 0 20 20" id="close">
path d="M14.348 14.849c-.469.469-1.229.469-1.697 0L10 11.819l-2.651 3.029c-.469.469-1.229.469-1.697 0-.469-.469-.469-1.229 0-1.697l2.758-3.15-2.759-3.152c-.469-.469-.469-1.228 0-1.697.469-.469 1.228-.469 1.697 0L10 8.183l2.651-3.031c.469-.469 1.228-.469 1.697 0 .469.469.469 1.229 0 1.697l-2.758 3.152 2.758 3.15c.469.469.469 1.229 0 1.698z"/>
symbol>
symbol viewBox="0 0 20 20" id="large-arrow">
path d="M13.25 10L6.109 2.58c-.268-.27-.268-.707 0-.979.268-.27.701-.27.969 0l7.83 7.908c.268.271.268.709 0 .979l-7.83 7.908c-.268.271-.701.27-.969 0-.268-.269-.268-.707 0-.979L13.25 10z"/>
symbol>
symbol viewBox="0 0 20 20" id="large-arrow-down">
path d="M17.418 6.109c.272-.268.709-.268.979 0s.271.701 0 .969l-7.908 7.83c-.27.268-.707.268-.979 0l-7.908-7.83c-.27-.268-.27-.701 0-.969.271-.268.709-.268.979 0L10 13.25l7.418-7.141z"/>
symbol>
symbol viewBox="0 0 24 24" id="jump-to">
path d="M19 7v4H5.83l3.58-3.59L8 6l-6 6 6 6 1.41-1.41L5.83 13H21V7z"/>
symbol>
symbol viewBox="0 0 24 24" id="expand">
path d="M10 18h4v-2h-4v2zM3 6v2h18V6H3zm3 7h12v-2H6v2z"/>
symbol>
defs>
svg>
body>
html>
http://localhost:888/myserver/api/index.html?url=/myserver/api
下一篇:UWP 和 WPF 对比
文章标题:REST easy with kbmMW #20 – OpenAPI and Swagger UI
文章链接:http://soscw.com/essay/97270.html