├── .dockerignore ├── .gitattributes ├── .github └── workflows │ ├── build-push-gcr.yaml │ ├── github-registry.yml │ ├── iris-contest-workflows.yml │ └── objectscript-quality.yml ├── .gitignore ├── .vscode ├── extensions.json ├── launch.json └── settings.json ├── Dockerfile ├── LICENSE ├── README.md ├── dev.md ├── docker-compose.yml ├── iris.script ├── module.xml └── src └── dc └── Sample ├── Person.cls ├── PersonREST.cls └── REST └── Base.cls /.dockerignore: -------------------------------------------------------------------------------- 1 | **/.DS_Store -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.sh text eol=lf 2 | *.cls text eol=lf 3 | *.mac text eol=lf 4 | *.int text eol=lf 5 | *.xml text eol=lf 6 | Dockerfil* text eol=lf -------------------------------------------------------------------------------- /.github/workflows/build-push-gcr.yaml: -------------------------------------------------------------------------------- 1 | name: Cloud Run Deploy 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | - main 8 | workflow_dispatch: 9 | 10 | jobs: 11 | deploy: 12 | uses: intersystems-community/demo-deployment/.github/workflows/deployment.yml@master 13 | with: 14 | # Replace the name: parameter below to have your application deployed at 15 | # https://project-name.demo.community.intersystems.com/ 16 | name: project-name 17 | secrets: 18 | # Do not forget to add Secret in GitHub Repoository Settings with name SERVICE_ACCOUNT_KEY 19 | SERVICE_ACCOUNT_KEY: ${{ secrets.SERVICE_ACCOUNT_KEY }} -------------------------------------------------------------------------------- /.github/workflows/github-registry.yml: -------------------------------------------------------------------------------- 1 | name: Build and publish a Docker image to ghcr.io 2 | on: 3 | 4 | # publish on pushes to the main branch (image tagged as "latest") 5 | # image name: will be: ghcr.io/${{ github.repository }}:latest 6 | # e.g.: ghcr.io/intersystems-community/intersystems-iris-dev-template:latest 7 | push: 8 | branches: 9 | - master 10 | 11 | jobs: 12 | docker_publish: 13 | runs-on: "ubuntu-20.04" 14 | 15 | steps: 16 | - uses: actions/checkout@v2 17 | 18 | # https://github.com/marketplace/actions/push-to-ghcr 19 | - name: Build and publish a Docker image for ${{ github.repository }} 20 | uses: macbre/push-to-ghcr@master 21 | with: 22 | image_name: ${{ github.repository }} 23 | github_token: ${{ secrets.GITHUB_TOKEN }} 24 | # optionally push to the Docker Hub (docker.io) 25 | # docker_io_token: ${{ secrets.DOCKER_IO_ACCESS_TOKEN }} # see https://hub.docker.com/settings/security -------------------------------------------------------------------------------- /.github/workflows/iris-contest-workflows.yml: -------------------------------------------------------------------------------- 1 | name: objectscriptquality 2 | on: push 3 | 4 | jobs: 5 | linux: 6 | name: Linux build 7 | runs-on: ubuntu-latest 8 | 9 | steps: 10 | - name: Execute ObjectScript Quality Analysis 11 | run: wget https://raw.githubusercontent.com/litesolutions/objectscriptquality-jenkins-integration/master/iris-community-hook.sh && sh ./iris-community-hook.sh 12 | -------------------------------------------------------------------------------- /.github/workflows/objectscript-quality.yml: -------------------------------------------------------------------------------- 1 | name: objectscriptquality 2 | on: push 3 | 4 | jobs: 5 | linux: 6 | name: Linux build 7 | runs-on: ubuntu-latest 8 | 9 | steps: 10 | - name: Execute ObjectScript Quality Analysis 11 | run: wget https://raw.githubusercontent.com/litesolutions/objectscriptquality-jenkins-integration/master/iris-community-hook.sh && sh ./iris-community-hook.sh 12 | 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | iris-main.log 3 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "eamodio.gitlens", 4 | "georgejames.gjlocate", 5 | "github.copilot", 6 | "intersystems-community.servermanager", 7 | "intersystems-community.sqltools-intersystems-driver", 8 | "intersystems-community.vscode-objectscript", 9 | "intersystems.language-server", 10 | "mohsen1.prettify-json", 11 | "ms-azuretools.vscode-docker", 12 | "ms-python.python", 13 | "ms-python.vscode-pylance", 14 | "ms-vscode-remote.remote-containers" 15 | ] 16 | } -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "type": "objectscript", 6 | "request": "launch", 7 | "name": "ObjectScript Debug Class", 8 | "program": "##class(PackageSample.ObjectScript).Test()", 9 | }, 10 | { 11 | "type": "objectscript", 12 | "request": "attach", 13 | "name": "ObjectScript Attach", 14 | "processId": "${command:PickProcess}", 15 | "system": true 16 | } 17 | ] 18 | } -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.associations": { 3 | 4 | "iris.script": "objectscript" 5 | }, 6 | "objectscript.conn" :{ 7 | "ns": "USER", 8 | "username": "_SYSTEM", 9 | "password": "SYS", 10 | "docker-compose": { 11 | "service": "iris", 12 | "internalPort": 52773 13 | }, 14 | "active": true, 15 | "links": { 16 | "Swagger": "${serverUrl}/swagger-ui/index.html" 17 | } 18 | } 19 | 20 | 21 | } -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | ARG IMAGE=intersystemsdc/iris-community:2020.3.0.221.0-zpm 2 | ARG IMAGE=intersystemsdc/iris-community 3 | FROM $IMAGE 4 | 5 | WORKDIR /home/irisowner/dev 6 | 7 | RUN --mount=type=bind,src=.,dst=. \ 8 | iris start IRIS && \ 9 | iris session IRIS < iris.script && \ 10 | iris stop IRIS quietly 11 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 InterSystems Developer Community 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## intersystems-iris-rest-api-template 2 | 3 | [![Gitter](https://img.shields.io/badge/Available%20on-Intersystems%20Open%20Exchange-00b2a9.svg)](https://openexchange.intersystems.com/package/iris-rest-api-template) 4 | [![Quality Gate Status](https://community.objectscriptquality.com/api/project_badges/measure?project=intersystems_iris_community%2Firis-rest-api-template&metric=alert_status)](https://community.objectscriptquality.com/dashboard?id=intersystems_iris_community%2Firis-rest-api-template) 5 | GitHub last commit 6 | 7 | This is a template of a REST API application built with ObjectScript in InterSystems IRIS. 8 | It also has OPEN API spec, 9 | can be developed with Docker and VSCode, 10 | can ve deployed as ZPM module. 11 | 12 | ## Prerequisites 13 | Make sure you have [git](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git) and [Docker desktop](https://www.docker.com/products/docker-desktop) installed. 14 | 15 | ## Installation with ZPM 16 | 17 | zpm:USER>install rest-api-template 18 | 19 | ## Installation for development 20 | 21 | Create your repository from template. 22 | 23 | Clone/git pull the repo into any local directory e.g. like it is shown below (here I show all the examples related to this repository, but I assume you have your own derived from the template): 24 | 25 | ``` 26 | $ git clone git@github.com:intersystems-community/iris-rest-api-template.git 27 | ``` 28 | 29 | Open the terminal in this directory and run: 30 | 31 | ``` 32 | $ docker-compose up -d --build 33 | ``` 34 | 35 | or open the folder in VSCode and do the following: 36 | ![rest](https://user-images.githubusercontent.com/2781759/78183327-63569800-7470-11ea-8561-c3b547ce9001.gif) 37 | 38 | 39 | ## How to Work With it 40 | 41 | This template creates /crud REST web-application on IRIS which implements 4 types of communication: GET, POST, PUT and DELETE aka CRUD operations. 42 | These interface works with a sample persistent class dc.Sample.Person. 43 | 44 | Open http://localhost:52773/swagger-ui/index.html to test the REST API 45 | 46 | # Testing GET requests 47 | 48 | To test GET you need to have some data. You can create it with POST request (see below), or you can create some fake testing data. to do that open IRIS terminal or web terminal on /localhost:52773/terminal/ and call: 49 | 50 | ``` 51 | USER>do ##class(dc.Sample.Person).AddTestData(10) 52 | ``` 53 | This will create 10 random records in dc.Sample.Person class. 54 | 55 | 56 | You can get swagger Open API 2.0 documentation on: 57 | ``` 58 | localhost:52773/crud/_spec 59 | ``` 60 | 61 | This REST API exposes two GET requests: all the data and one record. 62 | To get all the data in JSON call: 63 | 64 | ``` 65 | localhost:52773/crud/persons/all 66 | ``` 67 | 68 | To request the data for a particular record provide the id in GET request like 'localhost:52773/crud/persons/id' . E.g.: 69 | 70 | ``` 71 | localhost:52773/crud/persons/1 72 | ``` 73 | 74 | This will return JSON data for the person with ID=1, something like that: 75 | 76 | ``` 77 | {"Name":"Elon Mask","Title":"CEO","Company":"Tesla","Phone":"123-123-1233","DOB":"1982-01-19"} 78 | ``` 79 | 80 | # Testing POST request 81 | 82 | Create a POST request e.g. in Postman with raw data in JSON. e.g. 83 | 84 | ``` 85 | {"Name":"Elon Mask","Title":"CEO","Company":"Tesla","Phone":"123-123-1233","DOB":"1982-01-19"} 86 | ``` 87 | 88 | Adjust the authorisation if needed - it is basic for container with default login and password for IRIR Community edition container 89 | 90 | and send the POST request to localhost:52773/crud/persons/ 91 | 92 | This will create a record in dc.Sample.Person class of IRIS. 93 | 94 | # Testing PUT request 95 | 96 | PUT request could be used to update the records. This needs to send the similar JSON as in POST request above supplying the id of the updated record in URL. 97 | E.g. we want to change the record with id=5. Prepare in Postman the JSON in raw like following: 98 | 99 | ``` 100 | {"Name":"Jeff Besos","Title":"CEO","Company":"Amazon","Phone":"123-123-1233","DOB":"1982-01-19"} 101 | ``` 102 | 103 | and send the put request to: 104 | ``` 105 | localhost:52773/crud/persons/5 106 | ``` 107 | 108 | # Testing DELETE request 109 | 110 | For delete request this REST API expects only the id of the record to delete. E.g. if the id=5 the following DELETE call will delete the record: 111 | 112 | ``` 113 | localhost:52773/crud/persons/5 114 | ``` 115 | 116 | ## How to start coding 117 | This repository is ready to code in VSCode with ObjectScript plugin. 118 | Install [VSCode](https://code.visualstudio.com/) and [ObjectScript](https://marketplace.visualstudio.com/items?itemName=daimor.vscode-objectscript) plugin and open the folder in VSCode. 119 | Open /src/cls/PackageSample/ObjectScript.cls class and try to make changes - it will be compiled in running IRIS docker container. 120 | 121 | Feel free to delete PackageSample folder and place your ObjectScript classes in a form 122 | /src/cls/Package/Classname.cls 123 | 124 | The script in Installer.cls will import everything you place under /src/cls into IRIS. 125 | 126 | ## What's insde the repo 127 | 128 | # Dockerfile 129 | 130 | The simplest dockerfile to start IRIS and load ObjectScript from /src/cls folder 131 | Use the related docker-compose.yml to easily setup additional parametes like port number and where you map keys and host folders. 132 | 133 | # .vscode/settings.json 134 | 135 | Settings file to let you immedietly code in VSCode with [VSCode ObjectScript plugin](https://marketplace.visualstudio.com/items?itemName=daimor.vscode-objectscript)) 136 | 137 | # .vscode/launch.json 138 | Config file if you want to debug with VSCode ObjectScript 139 | -------------------------------------------------------------------------------- /dev.md: -------------------------------------------------------------------------------- 1 | # useful commands 2 | ## clean up docker 3 | use it when docker says "There is no space left on device". It will remove built but not used images and other temporary files. 4 | ``` 5 | docker system prune -f 6 | ``` 7 | 8 | ``` 9 | docker rm -f $(docker ps -qa) 10 | ``` 11 | 12 | ## build container with no cache 13 | ``` 14 | docker-compose build --no-cache --progress=plain 15 | ``` 16 | ## start iris container 17 | ``` 18 | docker-compose up -d 19 | ``` 20 | 21 | ## open iris terminal in docker 22 | ``` 23 | docker exec iris iris session iris -U IRISAPP 24 | ``` 25 | 26 | 27 | ## import objectscirpt code 28 | 29 | do $System.OBJ.LoadDir("/home/irisowner/dev/src","ck",,1) 30 | ## map iris key from Mac home directory to IRIS in container 31 | - ~/iris.key:/usr/irissys/mgr/iris.key 32 | 33 | ## install git in the docker image 34 | ## add git in dockerfile 35 | USER root 36 | RUN apt update && apt-get -y install git 37 | 38 | USER ${ISC_PACKAGE_MGRUSER} 39 | 40 | 41 | ## install docker-compose 42 | ``` 43 | sudo curl -L "https://github.com/docker/compose/releases/download/1.26.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose 44 | 45 | sudo chmod +x /usr/local/bin/docker-compose 46 | 47 | ``` 48 | 49 | ## load and test module 50 | ``` 51 | 52 | zpm "load /home/irisowner/dev" 53 | 54 | zpm "test dc-sample" 55 | ``` 56 | 57 | ## select zpm test registry 58 | ``` 59 | repo -n registry -r -url https://test.pm.community.intersystems.com/registry/ -user test -pass PassWord42 60 | ``` 61 | 62 | ## get back to public zpm registry 63 | ``` 64 | repo -r -n registry -url https://pm.community.intersystems.com/ -user "" -pass "" 65 | ``` 66 | 67 | ## export a global in runtime into the repo 68 | ``` 69 | d $System.OBJ.Export("GlobalD.GBL","/irisrun/repo/src/gbl/GlobalD.xml") 70 | ``` 71 | 72 | ## create a web app in dockerfile 73 | ``` 74 | zn "%SYS" \ 75 | write "Create web application ...",! \ 76 | set webName = "/csp/irisweb" \ 77 | set webProperties("NameSpace") = "IRISAPP" \ 78 | set webProperties("Enabled") = 1 \ 79 | set webProperties("CSPZENEnabled") = 1 \ 80 | set webProperties("AutheEnabled") = 32 \ 81 | set webProperties("iKnowEnabled") = 1 \ 82 | set webProperties("DeepSeeEnabled") = 1 \ 83 | set sc = ##class(Security.Applications).Create(webName, .webProperties) \ 84 | write "Web application "_webName_" has been created!",! 85 | ``` 86 | 87 | 88 | 89 | ``` 90 | do $SYSTEM.OBJ.ImportDir("/opt/irisbuild/src",, "ck") 91 | ``` 92 | 93 | 94 | ### run tests described in the module 95 | 96 | IRISAPP>zpm 97 | IRISAPP:zpm>load /irisrun/repo 98 | IRISAPP:zpm>test package-name 99 | 100 | ### install ZPM with one line 101 | // Install ZPM 102 | set $namespace="%SYS", name="DefaultSSL" do:'##class(Security.SSLConfigs).Exists(name) ##class(Security.SSLConfigs).Create(name) set url="https://pm.community.intersystems.com/packages/zpm/latest/installer" Do ##class(%Net.URLParser).Parse(url,.comp) set ht = ##class(%Net.HttpRequest).%New(), ht.Server = comp("host"), ht.Port = 443, ht.Https=1, ht.SSLConfiguration=name, st=ht.Get(comp("path")) quit:'st $System.Status.GetErrorText(st) set xml=##class(%File).TempFilename("xml"), tFile = ##class(%Stream.FileBinary).%New(), tFile.Filename = xml do tFile.CopyFromAndSave(ht.HttpResponse.Data) do ht.%Close(), $system.OBJ.Load(xml,"ck") do ##class(%File).Delete(xml) 103 | 104 | 105 | 106 | 107 | docker run --rm --name iris-sql -d -p 9091:1972 -p 9092:52773  -e IRIS_PASSWORD=demo -e IRIS_USERNAME=demo intersystemsdc/iris-community 108 | 109 | 110 | docker run --rm --name iris-ce -d -p 9091:1972 -p 9092:52773 -e IRIS_PASSWORD=demo -e IRIS_USERNAME=demo intersystemsdc/iris-community -a "echo 'zpm \"install webterminal\"' | iriscli" 111 | 112 | 113 | 114 | docker run --rm --name iris-sql -d -p 9092:52773 containers.intersystems.com/intersystems/iris-community:2023.1.0.229.0 115 | 116 | 117 | docker run --rm --name iris-ce -d -p 9092:52773 containers.intersystems.com/intersystems/iris-community:2023.1.0.229.0 118 | 119 | 120 | list all the specs: 121 | http://localhost:52773/api/mgmnt/ -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.6' 2 | services: 3 | iris: 4 | build: 5 | context: . 6 | dockerfile: Dockerfile 7 | restart: always 8 | ports: 9 | - 51773:1972 10 | - 52773:52773 11 | - 53773 12 | volumes: 13 | - ./:/home/irisowner/dev 14 | -------------------------------------------------------------------------------- /iris.script: -------------------------------------------------------------------------------- 1 | ;do $System.OBJ.LoadDir("/opt/irisapp/src","ck",,1) 2 | 3 | zn "%SYS" 4 | Do ##class(Security.Users).UnExpireUserPasswords("*") 5 | zpm "install passwordless" 6 | 7 | zn "USER" 8 | zpm "load /home/irisowner/dev/ -v":1 9 | 10 | 11 | halt 12 | -------------------------------------------------------------------------------- /module.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | rest-api-template 6 | 1.1.0 7 | module 8 | src 9 | 10 | 11 | 12 | swagger-ui 13 | 1.*.* 14 | 15 | 16 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /src/dc/Sample/Person.cls: -------------------------------------------------------------------------------- 1 | Class dc.Sample.Person Extends (%Persistent, %JSON.Adaptor, %Populate) 2 | { 3 | 4 | Property Name As %VarString; 5 | 6 | Property Title As %String; 7 | 8 | Property Company As %String; 9 | 10 | Property Phone As %VarString; 11 | 12 | Property DOB As %Date(MAXVAL = "$piece($horolog, "","", 1)"); 13 | 14 | /// Index for property DOB 15 | Index DOBIndex On DOB; 16 | 17 | ClassMethod AddTestData(amount As %Integer = 10) 18 | { 19 | d ..Populate(amount) 20 | } 21 | 22 | Storage Default 23 | { 24 | 25 | 26 | %%CLASSNAME 27 | 28 | 29 | Name 30 | 31 | 32 | Title 33 | 34 | 35 | Company 36 | 37 | 38 | Phone 39 | 40 | 41 | DOB 42 | 43 | 44 | ^Sample.PersonD 45 | PersonDefaultData 46 | ^Sample.PersonD 47 | ^Sample.PersonI 48 | ^Sample.PersonS 49 | %Storage.Persistent 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /src/dc/Sample/PersonREST.cls: -------------------------------------------------------------------------------- 1 | Class dc.Sample.PersonREST Extends Sample.REST.Base 2 | { 3 | 4 | Parameter Version = "1.0.6"; 5 | 6 | XData UrlMap [ XMLNamespace = "http://www.intersystems.com/urlmap" ] 7 | { 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | } 29 | 30 | /// PersonsREST general information 31 | ClassMethod GetInfo() As %Status 32 | { 33 | SET version = ..#Version 34 | SET info = { 35 | "version": (version) 36 | } 37 | RETURN ..%ProcessResult($$$OK, info) 38 | } 39 | 40 | /// Retreive all the records of dc.Sample.Person 41 | ClassMethod GetAllPersons() As %Status 42 | { 43 | 44 | #dim tSC As %Status = $$$OK 45 | 46 | Set rset = ##class(dc.Sample.Person).ExtentFunc() 47 | 48 | Set %response.ContentType = ..#CONTENTTYPEJSON 49 | Write "[" 50 | if rset.%Next() { 51 | Set person = ##class(dc.Sample.Person).%OpenId(rset.ID) 52 | Do person.%JSONExport() 53 | } 54 | While rset.%Next() { 55 | Write "," 56 | Set person = ##class(dc.Sample.Person).%OpenId(rset.ID) 57 | Do person.%JSONExport() 58 | } 59 | Write "]" 60 | Quit tSC 61 | } 62 | 63 | /// Return one record fo dc.Sample.Person 64 | ClassMethod GetPerson(id As %Integer) As %Status 65 | { 66 | #dim tSC As %Status = $$$OK 67 | #dim e As %Exception.AbstractException 68 | 69 | 70 | #; Set the response header to plain text 71 | Set %response.ContentType = ..#CONTENTTYPEJSON 72 | 73 | Set person = ##class(dc.Sample.Person).%OpenId(id) 74 | 75 | If '$IsObject(person) Quit ..Http404() 76 | 77 | Do person.%JSONExport() 78 | 79 | Quit tSC 80 | } 81 | 82 | /// Creates a new dc.Sample.Person record 83 | ClassMethod CreatePerson() As %Status 84 | { 85 | #dim tSC As %Status = $$$OK 86 | #dim e As %Exception.AbstractException 87 | Set person = ##class(dc.Sample.Person).%New() 88 | Set data=%request.Content 89 | 90 | 91 | $$$TOE(tSC,person.%JSONImport(data)) 92 | $$$TOE(tSC,person.%Save()) 93 | 94 | Set %response.Status = 204 95 | Set %response.ContentType = ..#CONTENTTYPEJSON 96 | //d data.%ToJSON() 97 | Do person.%JSONExport() 98 | 99 | Quit tSC 100 | } 101 | 102 | /// Update a record in dc.Sample.Person with id 103 | ClassMethod UpdatePerson(id As %Integer) As %Status 104 | { 105 | #dim tSC As %Status = $$$OK 106 | #dim e As %Exception.AbstractException 107 | Set person = ##class(dc.Sample.Person).%OpenId(id) 108 | If '$IsObject(person) Return ..Http404() 109 | Set data=%request.Content 110 | 111 | $$$TOE(tSC,person.%JSONImport(data)) 112 | $$$TOE(tSC,person.%Save()) 113 | 114 | Set %response.Status = 200 115 | 116 | Set %response.ContentType = ..#CONTENTTYPEJSON 117 | Do person.%JSONExport() 118 | 119 | Quit tSC 120 | } 121 | 122 | /// Delete a record with id in dc.Sample.Person 123 | ClassMethod DeletePerson(id As %Integer) As %Status 124 | { 125 | #dim tSC As %Status = $$$OK 126 | #dim e As %Exception.AbstractException 127 | Set person = ##class(dc.Sample.Person).%OpenId(id) 128 | If '$IsObject(person) Return ..Http404() 129 | 130 | $$$TOE(tSC,person.%DeleteId(id)) 131 | 132 | Set %response.Status = 200 133 | 134 | Set %response.ContentType = ..#CONTENTTYPEJSON 135 | 136 | Quit tSC 137 | } 138 | 139 | ClassMethod CreateRandomPersons(amount As %Integer) as %Status 140 | { 141 | #dim tSC As %Status = $$$OK 142 | Set %response.ContentType = ..#CONTENTTYPEJSON 143 | 144 | Try { 145 | set status = ##class(dc.Sample.Person).AddTestData(amount) 146 | $$$ThrowOnError(status) 147 | Set message = "Created "_amount_" random persons in Sample.Person data" 148 | } Catch(ex) { 149 | Set tSC = ex.Code 150 | } 151 | Return tSC 152 | } 153 | 154 | ClassMethod SwaggerSpec() As %Status 155 | { 156 | Set tSC = ##class(%REST.API).GetWebRESTApplication($NAMESPACE, %request.Application, .swagger) 157 | Do swagger.info.%Remove("x-ISC_Namespace") 158 | Set swagger.basePath = "/crud" 159 | Set swagger.info.title = "InterSystems IRIS REST CRUD demo" 160 | Set swagger.info.version = "0.1" 161 | Set swagger.host = "localhost:52773" 162 | Return ..%ProcessResult($$$OK, swagger) 163 | } 164 | 165 | } 166 | -------------------------------------------------------------------------------- /src/dc/Sample/REST/Base.cls: -------------------------------------------------------------------------------- 1 | Class Sample.REST.Base Extends %CSP.REST [ System = 3 ] 2 | { 3 | 4 | Parameter CHARSET = "utf-8"; 5 | 6 | Parameter CONTENTTYPE = "application/json"; 7 | 8 | Parameter HandleCorsRequest = 1; 9 | 10 | Parameter PAGESIZE As INTEGER = 20; 11 | 12 | ClassMethod OnPreDispatch(pUrl As %String, pMethod As %String, ByRef pContinue As %Boolean) As %Status 13 | { 14 | SET tSC = $$$OK 15 | TRY { 16 | 17 | // Set the return type according to the Accept type in the request. Default is application/json. 18 | IF ('..AcceptsContentType(..#CONTENTTYPEJSON)) { 19 | SET tSC = ..ReportHttpStatusCode(..#HTTP406NOTACCEPTABLE), pContinue=0 20 | QUIT 21 | } ELSE { 22 | // This always returns json 23 | SET %response.ContentType=..#CONTENTTYPEJSON 24 | } 25 | 26 | 27 | // read request object into %DynamicObject format 28 | IF ((pMethod'="POST") && (pMethod'="PUT")) || (%request.Content="") { 29 | SET %request.Content = {} 30 | } ELSE { 31 | IF '$isobject(%request.Content) { 32 | SET tContent = %request.Content 33 | } ELSE { 34 | SET tContent = "" 35 | WHILE '%request.Content.AtEnd { 36 | SET tContent = tContent_%request.Content.Read() 37 | } 38 | } 39 | IF (tContent="") { 40 | SET %request.Content = {} 41 | } ELSE { 42 | SET tContent = $zconvert(tContent, "I", "UTF8") 43 | SET %request.Content = ##class(%Library.DynamicObject).%FromJSON(tContent) 44 | } 45 | } 46 | 47 | } CATCH ex { 48 | SET tSC = ex.AsStatus() 49 | } 50 | QUIT ##class(%iKnow.REST.Base).%ErrorHandler(tSC, .pContinue) 51 | } 52 | 53 | ClassMethod %ProcessResult(pStatus As %Status = {$$$OK}, pResult As %DynamicObject = "") As %Status [ Internal ] 54 | { 55 | #dim %response As %CSP.Response 56 | SET tSC = $$$OK 57 | IF $$$ISERR(pStatus) { 58 | SET %response.Status = 500 59 | SET tSC = ..StatusToJSON(pStatus, .tJSON) 60 | IF $isobject(tJSON) { 61 | SET pResult = tJSON 62 | } ELSE { 63 | SET pResult = { "errors": [ { "error": "Unknown error parsing status code" } ] } 64 | } 65 | } 66 | ELSEIF pStatus=1 { 67 | IF '$isobject(pResult){ 68 | SET pResult = { 69 | } 70 | } 71 | } 72 | ELSE { 73 | SET %response.Status = pStatus 74 | SET error = $PIECE(pStatus, " ", 2, *) 75 | SET pResult = { 76 | "error": (error) 77 | } 78 | } 79 | 80 | IF pResult.%Extends("%Library.DynamicAbstractObject") { 81 | WRITE pResult.%ToJSON() 82 | } 83 | ELSEIF pResult.%Extends("%JSON.Adaptor") { 84 | DO pResult.%JSONExport() 85 | } 86 | ELSEIF pResult.%Extends("%Stream.Object") { 87 | DO pResult.OutputToDevice() 88 | } 89 | 90 | QUIT tSC 91 | } 92 | 93 | ClassMethod ReportHttpStatusCode(pHttpStatus, pSC As %Status = {$$$OK}) As %Status 94 | { 95 | Set %response.Status=pHttpStatus 96 | 97 | If $$$ISERR(pSC) Do ..outputStatus(pSC) 98 | /* 99 | If (+pHttpStatus>=400) { 100 | Set %response.ContentType = "application/json" 101 | SET pResult = { 102 | "error": ($PIECE(pHttpStatus, " ", 2, *)) 103 | } 104 | Return ..%ProcessResult($$$OK, pResult) 105 | }*/ 106 | 107 | Return $$$OK 108 | } 109 | 110 | } 111 | --------------------------------------------------------------------------------