清除过滤器
文章
Michael Lei · 五月 20, 2022
本文向你推荐一些使用IRIS创建REST API应用程序的模式。
注:所有源代码在https://github.com/yurimarx/movie
类模式到REST应用
首先,请看我对创建IRIS API应用程序所需类的建议:
IRISRESTApplication: CSP.REST 类会作为中央控制者来控制业务服务处理的所有REST请求和响应.
BusinessService: 具有业务主题的类实现。它可以使用一个或多个持久化域类来持久化和查询业务主题要求的数据。
Persistent Domain: 管理SQL表的持久化类.
环境准备
VSCode;
Docker Desktop;
InterSystems ObjectScript Extension Pack.
示例应用的类图
我将创建一个电影目录应用程序来演示文章中建议的模式:
Note: 感谢IRIS API 模版应用 https://openexchange.intersystems.com/package/iris-rest-api-template . 这是本教程的基础.
搭建样本应用
1. 在你的文件系统中创建一个movie文件夹。在一个新的VSCode窗口中打开这个文件夹。
2. 在movie 文件夹中创建 Dockerfile 文件来在Docker container实例中运行IRIS社区版. 内容:
Docker file content
ARG IMAGE=intersystemsdc/iris-community:2020.3.0.221.0-zpm
ARG IMAGE=intersystemsdc/iris-community:2020.4.0.524.0-zpm
ARG IMAGE=intersystemsdc/iris-community
FROM $IMAGE
USER root
WORKDIR /opt/irisapp
RUN chown ${ISC_PACKAGE_MGRUSER}:${ISC_PACKAGE_IRISGROUP} /opt/irisapp
USER ${ISC_PACKAGE_MGRUSER}
COPY src src
COPY module.xml module.xml
COPY iris.script /tmp/iris.script
RUN iris start IRIS \
&& iris session IRIS < /tmp/iris.script \
&& iris stop IRIS quietly
3. 在movie 文件夹中创建 docker-compose.yml 文件来让你同时运行你的docker 和其他实例 (不在本例子中, 但是从docker-compose而不是 dockerfile运行是很好的习惯。内容:
Docker composer content
version: '3.6'
services:
iris:
build:
context: .
dockerfile: Dockerfile
restart: always
ports:
- 51773
- 1972:1972
- 52773:52773
- 53773
volumes:
- ./:/irisdev/app
4. 在movie文件夹中创建iris.script文件,在运行IRIS之前做一些操作。这个文件对于做应用程序所需的自定义终端操作非常重要,比如禁用密码过期。内容:
iris.script content
;do $System.OBJ.LoadDir("/opt/irisapp/src","ck",,1)
zn "%SYS"
Do ##class(Security.Users).UnExpireUserPasswords("*")
zn "USER"
zpm "load /opt/irisapp/ -v":1:1
halt
5. 在movie文件夹中创建module.xml文件,使用ZPM安装和运行你的应用程序。这个文件对于应用程序的端点配置和安装swagger-ui(用于使用swagger文件运行和测试你的API的web应用程序)非常重要。内容:
Module.xml content
<?xml version="1.0" encoding="UTF-8"?>
<Export generator="Cache" version="25">
<Document name="movie.ZPM">
<Module>
<Name>movie</Name>
<Version>1.0.0</Version>
<Packaging>module</Packaging>
<SourcesRoot>src</SourcesRoot>
<Resource Name="dc.movie.PKG"/>
<Dependencies>
<ModuleReference>
<Name>swagger-ui</Name>
<Version>1.*.*</Version>
</ModuleReference>
</Dependencies>
<CSPApplication
Url="/movie-api"
DispatchClass="dc.movie.MovieRESTApp"
MatchRoles=":{$dbrole}"
PasswordAuthEnabled="1"
UnauthenticatedEnabled="0"
Recurse="1"
UseCookies="2"
CookiePath="/movie-api"
/>
</Module>
</Document>
</Export>
You can see CSPApplication tag, used to run the application API in the /movie-api URI and enable or disable password to consume the API.
6. 在movie文件夹中创建LICENSE文件,设置你的应用程序的许可证。内容:
LICENSE content
MIT License
Copyright (c) 2019 InterSystems Developer Community Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
7. 在movie文件夹中创建README.md文件,用markdown语言向用户记录你的应用程序。:
## movie-rest-application
This is a sample of a REST API application built with ObjectScript in InterSystems IRIS.
8. 在movie文件夹内创建.vscode文件夹。在.vscode文件夹中创建settings.json文件,以配置VSCode和你的IRIS实例之间的服务器连接。内容:
Settings content
{
"files.associations": {
"Dockerfile*": "dockerfile",
"iris.script": "objectscript"
},
"objectscript.conn" :{
"ns": "USER",
"username": "_SYSTEM",
"password": "SYS",
"docker-compose": {
"service": "iris",
"internalPort": 52773
},
"active": true
},
"sqltools.connections": [
{
"namespace": "USER",
"connectionMethod": "Server and Port",
"showSystem": false,
"previewLimit": 50,
"server": "localhost",
"port": 32770,
"askForPassword": false,
"driver": "InterSystems IRIS",
"name": "objectscript-docker",
"username": "_SYSTEM",
"password": "SYS"
}
]
}
9. 在movie文件夹内创建src文件夹,放置你的源代码文件夹和文件。
10. 在src文件夹内创建dc文件夹。当你建立项目到InterSystems开发者社区时,这是个传统,否则就没有必要。
11. 在dc文件夹内创建movie文件夹。这个文件夹将是你的objectscript类的文件夹。
12. 在 src\dc\movie 文件夹中创建我们的第一个类,MovieRESTApp.cls 文件。这个文件将是IRISRESTApplication类。内容:
MovieRESTApp content
Class dc.movie.MovieRESTApp Extends %CSP.REST
{
Parameter CHARSET = "utf-8";
Parameter CONVERTINPUTSTREAM = 1;
Parameter CONTENTTYPE = "application/json";
Parameter Version = "1.0.0";
Parameter HandleCorsRequest = 1;
XData UrlMap [ XMLNamespace = "http://www.intersystems.com/urlmap" ]
{
<Routes>
<!-- Server Info -->
<Route Url="/" Method="GET" Call="GetInfo" Cors="true"/>
<!-- Swagger specs -->
<Route Url="/_spec" Method="GET" Call="SwaggerSpec" />
</Routes>
}
ClassMethod %ProcessResult(pStatus As %Status = {$$$OK}, pResult As %DynamicObject = "") As %Status [ Internal ]
{
#dim %response As %CSP.Response
SET tSC = $$$OK
IF $$$ISERR(pStatus) {
SET %response.Status = 500
SET tSC = ..StatusToJSON(pStatus, .tJSON)
IF $isobject(tJSON) {
SET pResult = tJSON
} ELSE {
SET pResult = { "errors": [ { "error": "Unknown error parsing status code" } ] }
}
}
ELSEIF pStatus=1 {
IF '$isobject(pResult){
SET pResult = {
}
}
}
ELSE {
SET %response.Status = pStatus
SET error = $PIECE(pStatus, " ", 2, *)
SET pResult = {
"error": (error)
}
}
IF pResult.%Extends("%Library.DynamicAbstractObject") {
WRITE pResult.%ToJSON()
}
ELSEIF pResult.%Extends("%JSON.Adaptor") {
DO pResult.%JSONExport()
}
ELSEIF pResult.%Extends("%Stream.Object") {
DO pResult.OutputToDevice()
}
QUIT tSC
}
ClassMethod SwaggerSpec() As %Status
{
Set tSC = ##class(%REST.API).GetWebRESTApplication($NAMESPACE, %request.Application, .swagger)
Do swagger.info.%Remove("x-ISC_Namespace")
Set swagger.basePath = "/movie-api"
Set swagger.info.title = "Movie API"
Set swagger.info.version = "1.0"
Set swagger.host = "localhost:52773"
Return ..%ProcessResult($$$OK, swagger)
}
}
注1:该类扩展了CSP.REST,以作为REST Endpoint使用。
注2:参数chaset是用来对请求和响应进行UTF-8编码的。
注3:CONVERTINPUTSTREAM用于强制要求的内容为UTF-8,如果没有这个参数,你可能会遇到特殊拉丁字母的问题。
注4:CONTENTTYPE用于使用JSON而不是XML声明内容。
注5:HandleCorsRequest = 1是必要的,它允许你从不同于IRIS服务器的其他服务器上消费API。
注意 6: Routes用于声明每个类方法的API URI。
注7:CSP.REST类的SwaggerSpec允许你生成API swagger(API网络文档)内容。
现在你有以下的文件夹和文件:
13. 打开VSCode终端 (menu Terminal > New Terminal) 并键入:
docker-compose up -d --build
这样就建立一个docker示例并运行。
14. 用Swagger-UI测试API。打开浏览器键入: http://localhost:52773/swagger-ui/index.html. 注意地址栏。
在VSCode和 IRIS 之间建立联系
1. 点击ObjectScript 栏 ( VSCode footer)
2. 在顶部选择Toogle 链接:
3. 在ObjectScript Explorer里检查链接状态 (你能看到文件夹和创建的类):
Movie 目录应用的持久化类
在这个部分我们会创立持久化域的类来存储和查询业务数据.查看DBeaver图:
1. 在src\dc\movie 目录内创建文件folder模型.
2. 在model目录内创建Actor.cls 文件. 写以下内容:
Class dc.movie.model.Actor Extends (%Persistent, %JSON.Adaptor)
{
Parameter %JSONREFERENCE = "ID";
Property actorId As %Integer [ Calculated, SqlComputeCode = { set {*}={%%ID}}, SqlComputed ];
Property name As %VarString(MAXLEN = 120);
Property dob As %Date;
Property genre As %Integer(VALUELIST = ",1,2");
}
3. 在model 目录内创建 Movie.cls 文件,写内容:
Class dc.movie.model.Movie Extends (%Persistent, %JSON.Adaptor)
{
Parameter %JSONREFERENCE = "ID";
Property movieId As %Integer [ Calculated, SqlComputeCode = { set {*}={%%ID}}, SqlComputed ];
Property name As %VarString(MAXLEN = 120);
Property releaseDate As %Date;
Property duration As %Integer;
Property imdb As %String(MAXLEN = 300);
Property movieCategory As dc.movie.model.MovieCategory;
ForeignKey MovieCategoryFK(movieCategory) References dc.movie.model.MovieCategory();
}
4. 在model 目录内创建MovieCategory.cls 文件. 写下如下内容:
Class dc.movie.model.MovieCategory Extends (%Persistent, %JSON.Adaptor)
{
Parameter %JSONREFERENCE = "ID";
Property movieCategoryId As %Integer [ Calculated, SqlComputeCode = { set {*}={%%ID}}, SqlComputed ];
Property name As %VarString(MAXLEN = 120);
}
5. 在model 目录内创建Casting.cls 文件. 写下如下内容:
Class dc.movie.model.Casting Extends (%Persistent, %JSON.Adaptor)
{
Parameter %JSONREFERENCE = "ID";
Property castingId As %Integer [ Calculated, SqlComputeCode = { set {*}={%%ID}}, SqlComputed ];
Property movie As dc.movie.model.Movie;
ForeignKey MovieFK(movie) References dc.movie.model.Movie();
Property actor As dc.movie.model.Actor;
ForeignKey ActorFK(actor) References dc.movie.model.Actor();
Property characterName As %String(MAXLEN = 100);
Index CastingIndex On (movie, actor) [ Unique ];
}
查看创建的文件:
注1: 参数 %JSONREFERENCE = "ID" 允许在JSON回复内返回ID 值.
注2: 属性actorId 作为 %Integer [ Calculated, SqlComputeCode = { set {*}={%%ID}}, SqlComputed ] 和一些其他的类似的属性被用来返回class+id 到 JSON响应中去.
注3: (VALUELIST = "1,2") 设置可能的值到1或者 2。
注4: 外健 MovieFK(movie) 参考 dc.movie.model.Movie() 和类似的用来创建SQL 外键参照.
注5: 在 (movie, actor) [ Unique ]上建立索引CastingIndex和类似的用来不允许在合并On (movie 和 actor)时重复值
注6: 我使用 Camel Case 做属性名称因为这是JSON属性命名的最佳实践.
业务服务类到Classes to the Movie Catalog Application
在本节中,我们将创建具有业务逻辑的类(做持久性、查询和计算的方法)。
1. 在src/dc/movie中创建服务文件夹。
2. 在服务文件夹中创建CrudUtilService.cls文件。写下内容:
CrudUtilService content
Class dc.movie.service.CrudUtilService Extends %CSP.REST
{
Parameter CHARSET = "utf-8";
Parameter CONVERTINPUTSTREAM = 1;
Parameter CONTENTTYPE = "application/json";
Parameter Version = "1.0.0";
Parameter HandleCorsRequest = 1;
/// Return all the records
ClassMethod GetAll(DomainClass As %Persistent) As %Status
{
#dim tSC As %Status = $$$OK
Set rset = DomainClass.ExtentFunc()
Set %response.ContentType = ..#CONTENTTYPEJSON
Set %response.Headers("Access-Control-Allow-Origin")="*"
Write "["
if rset.%Next() {
Set actor = DomainClass.%OpenId(rset.ID)
Do actor.%JSONExport()
}
While rset.%Next() {
Write ","
Set actor = DomainClass.%OpenId(rset.ID)
Do actor.%JSONExport()
}
Write "]"
Quit tSC
}
/// Return one record
ClassMethod GetOne(DomainClass As %Persistent, id As %Integer) As %Status
{
#dim tSC As %Status = $$$OK
#dim e As %Exception.AbstractException
#; Set the response header to plain text
Set %response.ContentType = ..#CONTENTTYPEJSON
Set %response.Headers("Access-Control-Allow-Origin")="*"
Set domain = DomainClass.%OpenId(id)
If '$IsObject(domain) Quit ..Http404()
Do domain.%JSONExport()
Quit tSC
}
/// Creates a new record
ClassMethod Create(DomainClass As %Persistent) As %Status
{
#dim tSC As %Status = $$$OK
#dim e As %Exception.AbstractException
Set domain = DomainClass.%New()
Set data = {}.%FromJSON(%request.Content)
$$$TOE(tSC, domain.%JSONImport(data))
$$$TOE(tSC, domain.%Save())
Write domain.%JSONExport()
Set %response.Status = 204
Set %response.ContentType = ..#CONTENTTYPEJSON
Set %response.Headers("Access-Control-Allow-Origin")="*"
Quit tSC
}
/// Update a record with id
ClassMethod Update(DomainClass As %Persistent, id As %Integer) As %Status
{
#dim tSC As %Status = $$$OK
#dim e As %Exception.AbstractException
Set domain = DomainClass.%OpenId(id)
If '$IsObject(domain) Return ..Http404()
Set data = {}.%FromJSON(%request.Content)
$$$TOE(tSC, domain.%JSONImport(data))
$$$TOE(tSC, domain.%Save())
Write domain.%JSONExport()
Set %response.Status = 200
Set %response.ContentType = ..#CONTENTTYPEJSON
Set %response.Headers("Access-Control-Allow-Origin")="*"
Quit tSC
}
/// Delete a record with id
ClassMethod Delete(DomainClass As %Persistent, id As %Integer) As %Status
{
#dim tSC As %Status = $$$OK
#dim e As %Exception.AbstractException
Set domain = DomainClass.%OpenId(id)
If '$IsObject(domain) Return ..Http404()
$$$TOE(tSC, domain.%DeleteId(id))
Set %response.Status = 200
Set %response.ContentType = ..#CONTENTTYPEJSON
Set %response.Headers("Access-Control-Allow-Origin")="*"
Quit tSC
}
}
3. 在服务文件夹中创建MovieService.cls文件。编写内容:
MovieService content
Class dc.movie.service.MovieService Extends %CSP.REST
{
ClassMethod GetAll() As %Status
{
Return ##class(dc.movie.service.CrudUtilService).GetAll(##class(dc.movie.model.Movie).%New())
}
ClassMethod GetOne(id As %Integer) As %Status
{
Return ##class(dc.movie.service.CrudUtilService).GetOne(##class(dc.movie.model.Movie).%New(), id)
}
ClassMethod Create() As %Status
{
Return ##class(dc.movie.service.CrudUtilService).Create(##class(dc.movie.model.Movie).%New())
}
ClassMethod Update(id As %Integer) As %Status
{
Return ##class(dc.movie.service.CrudUtilService).Update(##class(dc.movie.model.Movie).%New(), id)
}
ClassMethod Delete(id As %Integer) As %Status
{
Return ##class(dc.movie.service.CrudUtilService).Delete(##class(dc.movie.model.Movie).%New(), id)
}
/// Return casting from the movie
ClassMethod GetMovieCasting(id As %Integer) As %Status
{
#dim tSC As %Status = $$$OK
Set qry = "SELECT actor->name AS actorName, characterName, movie->name AS movieName FROM dc_movie_model.Casting WHERE movie = ?"
Set tStatement = ##class(%SQL.Statement).%New()
Set qStatus = tStatement.%Prepare(qry)
If tSC'=1 {WRITE "%Prepare failed:" DO $System.Status.DisplayError(qStatus) QUIT}
Set rset = tStatement.%Execute(id)
Set %response.ContentType = ..#CONTENTTYPEJSON
Set %response.Headers("Access-Control-Allow-Origin")="*"
Set result = []
While rset.%Next() {
Set item = {}
Set item.actorName = rset.actorName
Set item.movieName = rset.movieName
Set item.characterName = rset.characterName
Do result.%Push(item)
}
Write result.%ToJSON()
Quit tSC
}
}
4. 在服务文件夹中创建MovieCategoryService.cls文件。编写内容:
MovieCategoryService content
Class dc.movie.service.MovieCategoryService
{
ClassMethod GetAll() As %Status
{
Return ##class(dc.movie.service.CrudUtilService).GetAll(##class(dc.movie.model.MovieCategory).%New())
}
ClassMethod GetOne(id As %Integer) As %Status
{
Return ##class(dc.movie.service.CrudUtilService).GetOne(##class(dc.movie.model.MovieCategory).%New(), id)
}
ClassMethod Create() As %Status
{
Return ##class(dc.movie.service.CrudUtilService).Create(##class(dc.movie.model.MovieCategory).%New())
}
ClassMethod Update(id As %Integer) As %Status
{
Return ##class(dc.movie.service.CrudUtilService).Update(##class(dc.movie.model.MovieCategory).%New(), id)
}
ClassMethod Delete(id As %Integer) As %Status
{
Return ##class(dc.movie.service.CrudUtilService).Delete(##class(dc.movie.model.MovieCategory).%New(), id)
}
}
5. 在服务文件夹中创建ActorService.cls文件。编写内容:
ActorService content
Class dc.movie.service.ActorService
{
ClassMethod GetAll() As %Status
{
Return ##class(dc.movie.service.CrudUtilService).GetAll(##class(dc.movie.model.Actor).%New())
}
ClassMethod GetOne(id As %Integer) As %Status
{
Return ##class(dc.movie.service.CrudUtilService).GetOne(##class(dc.movie.model.Actor).%New(), id)
}
ClassMethod Create() As %Status
{
Return ##class(dc.movie.service.CrudUtilService).Create(##class(dc.movie.model.Actor).%New())
}
ClassMethod Update(id As %Integer) As %Status
{
Return ##class(dc.movie.service.CrudUtilService).Update(##class(dc.movie.model.Actor).%New(), id)
}
ClassMethod Delete(id As %Integer) As %Status
{
Return ##class(dc.movie.service.CrudUtilService).Delete(##class(dc.movie.model.Actor).%New(), id)
}
}
6. 在服务文件夹中创建CastingService.cls文件。编写内容:
CastingService content
Class dc.movie.service.CastingService
{
ClassMethod GetAll() As %Status
{
Return ##class(dc.movie.service.CrudUtilService).GetAll(##class(dc.movie.model.Casting).%New())
}
ClassMethod GetOne(id As %Integer) As %Status
{
Return ##class(dc.movie.service.CrudUtilService).GetOne(##class(dc.movie.model.Casting).%New(), id)
}
ClassMethod Create() As %Status
{
Return ##class(dc.movie.service.CrudUtilService).Create(##class(dc.movie.model.Casting).%New())
}
ClassMethod Update(id As %Integer) As %Status
{
Return ##class(dc.movie.service.CrudUtilService).Update(##class(dc.movie.model.Casting).%New(), id)
}
ClassMethod Delete(id As %Integer) As %Status
{
Return ##class(dc.movie.service.CrudUtilService).Delete(##class(dc.movie.model.Casting).%New(), id)
}
}
7. 更新MovieRESTApp.cls文件,创建所有新服务类方法的路径。编写内容:
MovieRESTApp updated content
Class dc.movie.MovieRESTApp Extends %CSP.REST
{
Parameter CHARSET = "utf-8";
Parameter CONVERTINPUTSTREAM = 1;
Parameter CONTENTTYPE = "application/json";
Parameter Version = "1.0.0";
Parameter HandleCorsRequest = 1;
XData UrlMap [ XMLNamespace = "http://www.intersystems.com/urlmap" ]
{
<Routes>
<!-- Server Info -->
<Route Url="/" Method="GET" Call="GetInfo" Cors="true"/>
<!-- Swagger specs -->
<Route Url="/_spec" Method="GET" Call="SwaggerSpec" />
<!-- List all movies -->
<Route Url="/movies" Method="GET" Call="GetAllMovies" />
<!-- Get a movie -->
<Route Url="/movies/:id" Method="GET" Call="GetMovie" />
<!-- Get the movie casting -->
<Route Url="/movies/casting/:id" Method="GET" Call="GetMovieCasting" />
<!-- Create new movie -->
<Route Url="/movies" Method="POST" Call="CreateMovie" />
<!-- Update a movie -->
<Route Url="/movies/:id" Method="PUT" Call="UpdateMovie" />
<!-- Delete a movie -->
<Route Url="/movies/:id" Method="DELETE" Call="DeleteMovie" />
<!-- List all movie categories -->
<Route Url="/categories" Method="GET" Call="GetAllMovieCategories" />
<!-- Get a movie category -->
<Route Url="/categories/:id" Method="GET" Call="GetMovieCategory" />
<!-- Create new movie category -->
<Route Url="/categories" Method="POST" Call="CreateMovieCategory" />
<!-- Update a movie category -->
<Route Url="/categories/:id" Method="PUT" Call="UpdateMovieCategory" />
<!-- Delete a movie category -->
<Route Url="/categories/:id" Method="DELETE" Call="DeleteMovieCategory" />
<!-- List all actors -->
<Route Url="/actors" Method="GET" Call="GetAllActors" />
<!-- Get a actor -->
<Route Url="/actors/:id" Method="GET" Call="GetActor" />
<!-- Create new actor -->
<Route Url="/actors" Method="POST" Call="CreateActor" />
<!-- Update a actor -->
<Route Url="/actors/:id" Method="PUT" Call="UpdateActor" />
<!-- Delete a actor -->
<Route Url="/actors/:id" Method="DELETE" Call="DeleteActor" />
<!-- List all castings -->
<Route Url="/castings" Method="GET" Call="GetAllCastings" />
<!-- Get a actor -->
<Route Url="/castings/:id" Method="GET" Call="GetCasting" />
<!-- Create new actor -->
<Route Url="/castings" Method="POST" Call="CreateCasting" />
<!-- Update a actor -->
<Route Url="/castings/:id" Method="PUT" Call="UpdateCasting" />
<!-- Delete a actor -->
<Route Url="/castings/:id" Method="DELETE" Call="DeleteCasting" />
</Routes>
}
/// List movies
ClassMethod GetAllMovies() As %Status
{
Return ##class(dc.movie.service.MovieService).GetAll()
}
/// Get movie casting
ClassMethod GetMovieCasting(id As %Integer) As %Status
{
Return ##class(dc.movie.service.MovieService).GetMovieCasting(id)
}
/// Get a movie
ClassMethod GetMovie(id As %Integer) As %Status
{
Return ##class(dc.movie.service.MovieService).GetOne(id)
}
// Create a new movie
ClassMethod CreateMovie() As %Status
{
Return ##class(dc.movie.service.MovieService).Create()
}
// Update a movie
ClassMethod UpdateMovie(id As %Integer) As %Status
{
Return ##class(dc.movie.service.MovieService).Update(id)
}
// Delete a movie
ClassMethod DeleteMovie(id As %Integer) As %Status
{
Return ##class(dc.movie.service.MovieService).Delete(id)
}
/// List movies categories
ClassMethod GetAllMovieCategories() As %Status
{
Return ##class(dc.movie.service.MovieCategoryService).GetAll()
}
/// Get a movie category
ClassMethod GetMovieCategory(id As %Integer) As %Status
{
Return ##class(dc.movie.service.MovieCategoryService).GetOne(id)
}
// Create a new movie category
ClassMethod CreateMovieCategory() As %Status
{
Return ##class(dc.movie.service.MovieCategoryService).Create()
}
// Update a movie category
ClassMethod UpdateMovieCategory(id As %Integer) As %Status
{
Return ##class(dc.movie.service.MovieCategoryService).Update(id)
}
// Delete a movie category
ClassMethod DeleteMovieCategory(id As %Integer) As %Status
{
Return ##class(dc.movie.service.MovieCategoryService).Delete(id)
}
/// List actors
ClassMethod GetAllActors() As %Status
{
Return ##class(dc.movie.service.TestActorService).GetAll()
}
/// Get an actor
ClassMethod GetActor(id As %Integer) As %Status
{
Return ##class(dc.movie.service.ActorService).GetOne(id)
}
// Create a new actor
ClassMethod CreateActor() As %Status
{
Return ##class(dc.movie.service.ActorService).Create()
}
// Update an actor
ClassMethod UpdateActor(id As %Integer) As %Status
{
Return ##class(dc.movie.service.ActorService).Update(id)
}
// Delete an actor
ClassMethod DeleteActor(id As %Integer) As %Status
{
Return ##class(dc.movie.service.ActorService).Delete(id)
}
/// List castings
ClassMethod GetAllCastings() As %Status
{
Return ##class(dc.movie.service.CastingService).GetAll()
}
/// Get a casting
ClassMethod GetCasting(id As %Integer) As %Status
{
Return ##class(dc.movie.service.CastingService).GetOne(id)
}
// Create a new casting item
ClassMethod CreateCasting() As %Status
{
Return ##class(dc.movie.service.CastingService).Create()
}
// Update a casting
ClassMethod UpdateCasting(id As %Integer) As %Status
{
Return ##class(dc.movie.service.CastingService).Update(id)
}
// Delete a casting
ClassMethod DeleteCasting(id As %Integer) As %Status
{
Return ##class(dc.movie.service.CastingService).Delete(id)
}
/// General information
ClassMethod GetInfo() As %Status
{
SET version = ..#Version
SET fmt=##class(%SYS.NLS.Format).%New("ptbw")
SET info = {
"Service": "Movie API",
"version": (version),
"Developer": "Yuri Gomes",
"Status": "Ok",
"Date": ($ZDATETIME($HOROLOG))
}
Set %response.ContentType = ..#CONTENTTYPEJSON
Set %response.Headers("Access-Control-Allow-Origin")="*"
Write info.%ToJSON()
Quit $$$OK
}
ClassMethod %ProcessResult(pStatus As %Status = {$$$OK}, pResult As %DynamicObject = "") As %Status [ Internal ]
{
#dim %response As %CSP.Response
SET tSC = $$$OK
IF $$$ISERR(pStatus) {
SET %response.Status = 500
SET tSC = ..StatusToJSON(pStatus, .tJSON)
IF $isobject(tJSON) {
SET pResult = tJSON
} ELSE {
SET pResult = { "errors": [ { "error": "Unknown error parsing status code" } ] }
}
}
ELSEIF pStatus=1 {
IF '$isobject(pResult){
SET pResult = {
}
}
}
ELSE {
SET %response.Status = pStatus
SET error = $PIECE(pStatus, " ", 2, *)
SET pResult = {
"error": (error)
}
}
IF pResult.%Extends("%Library.DynamicAbstractObject") {
WRITE pResult.%ToJSON()
}
ELSEIF pResult.%Extends("%JSON.Adaptor") {
DO pResult.%JSONExport()
}
ELSEIF pResult.%Extends("%Stream.Object") {
DO pResult.OutputToDevice()
}
QUIT tSC
}
ClassMethod SwaggerSpec() As %Status
{
Set tSC = ##class(%REST.API).GetWebRESTApplication($NAMESPACE, %request.Application, .swagger)
Do swagger.info.%Remove("x-ISC_Namespace")
Set swagger.basePath = "/movie-api"
Set swagger.info.title = "Movie API"
Set swagger.info.version = "1.0"
Set swagger.host = "localhost:52773"
Return ..%ProcessResult($$$OK, swagger)
}
}
8. 最终项目的文件和文件夹是:
9. 访问 http://localhost:52773/swagger-ui/index.html测试你的新方法
注 1: REST路径是以/id为复数的业务主题,当我们需要将id传递给Camel 和Case的情况下,将路径传递到.
注 2: 我们使用动词GET进行查询,POST用于新记录,PUT用于更新记录,DELETE用于删除记录。
注 3: 在<Route Url="/movies/casting/:id" Method="GET" Call="GetMovieCasting" /> 我使用/casting表示第二个目的(获得Movie和Casting)。这个方法运行ToJSON(),因为它是一个动态数组([])和动态项目({})。
注 4: 我创建了 CrudUtilService ,遵循 "避免重复 "的原则,做通用CRUD方法的小工具。
谢谢观赏!
文章
Jingwei Wang · 六月 8, 2023
数据分集 (测试数据可以在网上下载 https://catalog.data.gov/dataset/)
1. 创建训练集,80%用于训练集。
CREATE TABLE DataMining.DiabetesTraining AS SELECT top 641 Pregnancies, Glucose, BloodPressure, SkinThickness, Insulin,BMI, Age, Outcome from DataMining.DSTable order by ID
2. 创建测试集,20%用于测试集。
CREATE TABLE DataMining.DiabetesTest AS SELECT top 127 Pregnancies, Glucose, BloodPressure, SkinThickness, Insulin, BMI,Age, Outcome from DataMining.DSTable order by ID DESC
Integrated ML
1. 创建ML配置
此步骤用来配置Provider 及不同Provider所使用的配置参数。
InterSystems IRIS提供三种Provider,AutoML、H2O和DataRobot,本实验使用默认Provider - AutoML ,所以可以忽略创建ML配置步骤。如果想尝试开源工具H2O,可以在此实验完成后,按照扩展实验手册进行配置。
2. ML配置
SET ML CONFIGURATION %AutoML
此步骤是用来确定选用的Provider,AutoML是系统自带的Provider。
3. 建模
CREATE MODEL DiabetesModel PREDICTING (Outcome) FROM DataMining.DiabetesTraining
DiabetesModel 为模型名称 (模型名称可随意设置)。 DataMining.DiabetesTraining 为糖尿病患者预测模型的训练数据集。 Outcome 为要预测的结果的列名。
4. 训练模型
TRAIN MODEL DiabetesModel
DiabetesModel为模型名称。
5. 验证模型
VALIDATE MODEL DiabetesModel FROM DataMining.DiabetesTest
DataMining.DiabetesTest为糖尿病患者预测模型的测试集。
6. 查看模型信息
SELECT * FROM INFORMATION_SCHEMA.ML_TRAINED_MODELS
在返回的数据PROVIDER列中,可以或者 在返回的数据MODEL_INFO列中,可以获得ModelType 算法名称, Package 机器学习处理包, ProblemType 算法类型等结果。
6. 查看验证结果
SELECT * FROM INFORMATION_SCHEMA.ML_VALIDATION_METRICS
可以获得Accuracy,Precision,Recall 和 F-Measure 计算结果。 现在,你可以通过Accuracy,Precision,Recall 和 F-Measure 来分析你的模型训练结果。如果训练模型准确率较低,可以重新训练数据集。
7. 查看测试集的预测结果和真实结果
SELECT PREDICT(DiabetesModel) AS PredictedDiabetes, Outcome AS ActualDiabetes FROM DataMining.DiabetesTest
8. 删除模型
DROP MODEL DiabetesModel