Background
InterSystems IRIS 2019 is going to introduce new and exciting features. One of the areas with new interesting must-to-know things is the API Management.
OpenAPI initiative (https://www.openapis.org/) is the organization supporting a standard specification to define APIs (https://github.com/OAI/OpenAPI-Specification). The OpenAPI Specification (OAS) defines a standard, programming language-agnostic interface description for REST APIs, which allows both humans and computers to discover and understand the capabilities of a service without requiring access to source code, additional documentation, or inspection of network traffic. When properly defined via OpenAPI, a consumer can understand and interact with the remote service with a minimal amount of implementation logic. Similar to what interface descriptions have done for lower-level programming, the OpenAPI Specification removes guesswork in calling a service.
InterSystems introduces in InterSystems IRIS support for an API-design first approach, this approach allows to design your specification first and then generate server-side from it. If we design the API first, normally we use Swagger Editor or another similar tool to create the specification and get the OAS specification in JSON format whenever we want.
Once we have the API designed and ready to implement then we can create the server side API logic using the OAS specification. In InterSystems IRIS 2019.1 we can use the new routine ^%REST to scaffold the API and automatically generate the classes where put the code that will call the business logic. The methods of this classes will be based on naming conventions although you can define the method and class in your specification (operationId).
Example of use of the InterSystems IRIS REST Command Line Interface:
REST Command Line Interface (CLI) helps you CREATE or DELETE a REST application
REST application not found: acmeapi
Do you want to create a new REST application? Y or N (Y):
File path or absolute URL of a swagger document.
If no document specified, then create an empty application.
OpenAPI 2.0 swagger: C:\myspec\acme.swagger.json
OpenAPI 2.0 swagger document: C:\myspec\notification.swagger.json
Confirm operation, Y or N (Y):
-----Creating REST application: acmeapi-----
CREATE acmeapi.spec
GENERATE acmeapi.disp
CREATE acmenapi.impl
REST application successfully created.
Create a web application for the REST application? Y or N (Y):
Specify web application name. Default is /csp/api/acme
Web application name: /csp/api/acme/v1
-----Deploying REST application: acmeapi-----
Application acmeapi deployed to /csp/api/acme/v1
At this moment the creation of a REST API only can use the OpenAPI 2.0 Swagger specification in order to build the scaffold of the API.
As you see this routine create three classes:
- <application>.spec: this class is the container for the swagger spec (XData OpenAPI block). This class is read-only.
- <application>.disp: dispatch class ready to use in the CSP application. It extends %CSP.REST and define the XData UrlMap. This class is read-only and marked as system class (by default is hidden in Atelier).
- <application>.impl: class defining all the necessary signature methods. This class should be complete in order to make the API works.
What if I have my API developed already?
In InterSystems IRIS 2018.1 InterSystems introduced the service discovery that enables developers to explore the API capabilities remotely. Also the Swagger integration allowing you to generate an Open API Specification (OAS) from your existing REST application. So, any API that we modify in InterSystems IRIS it can auto-generate the swagger specification.
It is possible to query all the available APIs in the system through a management API:
Returns:
[
...,
{
"name": "/csp/petstore/v2",
"dispatchClass": "petstore.disp",
"namespace": "USER",
"resource": "",
"swaggerSpec": "/api/mgmnt/v1/USER/spec/csp/petstore/v2",
"enabled": true
}
]
Moreover the Swagger specification of the API can be retrieve doing a HTTP GET to the URL show by the property swaggerSpec. Any API operation defined by the original swagger specification has a new property defining the name of the method that should implement the action:
Example:
A really funny stuff is that we can make use of this api/mgmnt not only for discovery, also for API creation/query/delete using
HTTP GET to /api/mgmnt/v2/<namespace>/<applicationName>
HTTP DELETE to /api/mgmnt/v2/<namespace>/<applicationName>
IRIS API Explorer
IRIS Explorer is an Angular 5 application that take advantage of this API in order to provide a nice visual tool to manage IRIS APIs. Let's do a quick tour:
First we need to do a login into an InterSystems IRIS instance (by default look for a local instance in port 52773):
After login the app make a query to retrieve all the existing APIS:
We can delete an existing APIs or we can create a new one. To create a New Application we need to provide the Namespace, the Application Name and the Swagger specification from a .json file:
Once we have the API created we can view the specification. In order to make this more funny I embedded a Swager-UI (https://github.com/swagger-api/swagger-ui).
And of course we can retrieve the JSON OAS Spec:
All the code is open and is up to you to use or modify as your convenience. The App is available in Open Exchange:
https://openexchange.intersystems.com/index.html#!/package/IRIS%20API%20EXPLORER
And also in GitHub:
https://github.com/drechema/iris-explorer
I hope it will be useful
Looks great David!
I think for the "background" part this Global Summit presentation - "API Design for REST" (by @Michael Smart) could be helpful.
Thanks for the post. I am looking forward to 2019.1.
Regarding the following statement:
"application>.disp: dispatch class ready to use in the CSP application. It extends %CSP.REST and define the XData UrlMap. This class is read-only and marked as system class (by default is hidden in Atelier)."
- My opinion is that is should not be hidden by default. I would like to add it to the git repo to package it with a version.
A question on the "impl" file. What happens if I have implementation code in it already and get an updates Swagger and generate it again? Does is overwrite the code or does it keep my code and add the new methods, etc.?
Regarding your question on the *.impl generated class -
if you already added code to this class and later update the swagger and consume it again - indeed the code you added will remain.
If you review the video recording of the Global Summit Solution Developer Conference session I mentioned above - you can see a live demonstration of this specific case. [I recommend you see all of it, but this particular part starts at about 33:30]
Thanks. I think that is one of the sessions I wanted to attend, but never got to it. I still need to go watch all the ones I wanted to attend, but had to choose between sessions or got pulled into meetings.
Generated files are hidden by default, and the .disp class is marked as generated. However to show the class, you have to click the little arrow on the row of buttons at the top right of the Server Explorer to open the customization menu. It’s this one:
From there, choose “Filters and Customization” and then uncheck the “Generated files” option (to disable the filter that hides generated classes) and click OK. After that to can added to the Git repo without problem.
David!
Could you please update the links to the OEX application? I guess the name was changed?
Updated. Yes, the OEX name changed, thanks @Evgeny Shvarov
Hi, David, I found your app looking for an example of an API definition that can be used to define a REST app. I cloned your app and tried to build it, but the web image did not complete build. I tried to build IRIS image here:
oliverwilms/iris-explorer: Angular Application that use the standard API discovery in InterSystems IRIS in order to inspect existing APIs and create new APIs using Swagger 2.0 OpenAPI specification (github.com)
I added iris.script where I use ^%REST. It works doing something, but something is missing?
Hello @Oliver Wilms
Can you share here logs of the problem and more detail. Or if you want you can open a Issue at https://github.com/drechema/iris-explorer
Hi, David,
I wonder if the problem is that there is a specific version hardcoded in Dockerfile:
FROM node:8.17.0-alpine3.9 as node
I am not familiar with node. Should the FROM line be updated? What is a good replacement?
I am trying docker pull node and will use that image it retrieves
I also used nginx latest image. The build for web image failed again
Hello @Oliver Wilms I have test using the original Dockerfile:
# Stage 1 FROM node:8.17.0-alpine3.9 as node LABEL maintainer "david.reche@intersystems.com" WORKDIR /usr/src/app COPY package*.json ./ RUN npm install COPY . . RUN npm run build # Stage 2 FROM nginx:1.13.12-alpine COPY --from=node /usr/src/app/dist/ /usr/share/nginx/html/ COPY ./nginx.conf /etc/nginx/conf.d/default.conf
and the image for web app is build ok
Thank you, David, for your responses. I wonder why it did not build in my AWS environment. Maybe I will try it again with your repo and see if it still fails if I can capture any errors.
Hello, David, it looks like you get a nice small image.
I use a AWS free tier account. My screen seems to get stuck and all I can see is this:
Step 5/10 : RUN npm install
---> Running in 58ae96e0c62a
> node-sass@4.10.0 install /usr/src/app/node_modules/node-sass
> node scripts/install.js
Downloading binary from https://github.com/sass/node-sass/releases/download/v4.10.0/linux_musl-x...
Download complete
Binary saved to /usr/src/app/node_modules/node-sass/vendor/linux_musl-x64-57/binding.node
Caching binary to /root/.npm/node-sass/4.10.0/linux_musl-x64-57_binding.node
> circular-json@0.5.7 postinstall /usr/src/app/node_modules/circular-json
> echo ''; echo "\x1B[1mCircularJSON\x1B[0m is in \x1B[4mmaintenance only\x1B[0m, \x1B[1mflatted\x1B[0m is its successor."; echo ''
\x1B[1mCircularJSON\x1B[0m is in \x1B[4mmaintenance only\x1B[0m, \x1B[1mflatted\x1B[0m is its successor.
> node-sass@4.10.0 postinstall /usr/src/app/node_modules/node-sass
> node scripts/build.js
Binary found at /usr/src/app/node_modules/node-sass/vendor/linux_musl-x64-57/binding.node
Testing binary
Binary is fine
npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@1.2.4 (node_modules/karma/node_modules/fsevents):
npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for fsevents@1.2.4: wanted {"os":"darwin","arch":"any"} (current: {"os":"linux","arch":"x64"})
npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@1.2.4 (node_modules/fsevents):
npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for fsevents@1.2.4: wanted {"os":"darwin","arch":"any"} (current: {"os":"linux","arch":"x64"})
added 1474 packages from 1384 contributors and audited 1611 packages in 53.388s
found 407 vulnerabilities (15 low, 122 moderate, 200 high, 70 critical)
run `npm audit fix` to fix them, or `npm audit` for details
Removing intermediate container 58ae96e0c62a
---> 4b0022ce43ef
Step 6/10 : COPY . .
---> ede198788bb5
Step 7/10 : RUN npm run build
---> Running in 7007e62b7eb2
> iris-explorer@1.1.0 build /usr/src/app
> ng build --prod
Browserslist: caniuse-lite is outdated. Please run next command `npm update caniuse-lite browserslist`