This section shows how to setup and implement a first UM plugin that provides Goal: Implement a simple REST API.
Create your first plugin
Creating an empty UM plugin is as simple as creating a directory structure following a specific naming rule and putting a plugin.desc.json
file in the right place.-Service and expose it via REST Proxy.
Info |
---|
You can download the whole Kickstarter-based sample application from our GitLab repository: um-public/tutorial-functional-rest-endpoints |
Start a new Kickstarter project
First, choose a Java-style package name for your new plugin – e.g. de.acme.firststepstutorial
. (See also ACME Corporation)
Please note that com...
, net...
and org...
denote reserved namespaces and can not be used as top-level package names.
Assuming you already have a running UM (version 7.29.0 or later) installed in ~/UM
, create a directory named after your chosen package name under ~/UM/cmsbs-conf/cse/plugins/
with a plugin descriptor file in itSecond, use UM-Kickstarter to begin a new UM project:
Codeblock | ||
---|---|---|
| ||
mkdirumkickstarter ~/UM/cmsbs-conf/cse/plugins/-n de.acme.firststeps touch ~/UM/tutorial cd umkickstarter gradle setup run |
Implement REST controller
Create an .es6
or .mjs
file in your plugin’s rest/
folder:
cmsbs-conf/cse/plugins/de.acme.
...
tutorial/rest/
...
api.
...
Edit the newly created plugin descriptor file with your favorite text editor to make it look something like this:
mjs
Codeblock | ||
---|---|---|
| ||
{
"name": "de.acme.firststeps",
"title": "First steps",
"description": "Provides a simple REST API for demonstration purposes",
"version": "0.9.0",
"um": ">=7.29.0"
} |
Restart your UM instance and visit Tools / Apps to find your new plugin listed among a bunch of vendor supplied plugins. Note, however, that the icon displayed in front of your plugin's title looks broken. We'll fix this later on.
Create your first REST controller
Each REST endpoint you want to provide needs its own controller class with a name following a certain convention. Create and edit a new ES6 file with the following name: ~/UM/cmsbs-conf/cse/plugins/de.acme.firststeps/rest/controllers/ListsController.es6
.
Codeblock | ||
---|---|---|
| ||
class ListsController {
constructor() {
}
} |
...
| |
/// <reference path="../../../.vscode.js"/>
import { RouterBuilder } from "@de.pinuts.apirouter/shared/routing.es6";
de.acme.tutorialController = new RouterBuilder()
.get('/hello', (req, res) => {
res.json({
msg: 'Hello world!',
params: req.params,
headers: req.headers,
});
})
.build(); |
Restart your UM instance:
Codeblock |
---|
gradle run |
Invoke REST service
Try to invoke the new REST service in your browser:
http://localhost:8080/cmsbs/rest/de.acme.firststeps.Lists/index
This yields a 404 and the logfile ~/UM/cmsbs-work/sys.log
says:
Codeblock |
---|
Undefined REST controller class: de.acme.firststeps.ListsController |
You have created the new controller class but the UM cannot see it because it is not contained in the expected name space object. Add the following line to the end of your ES6 file:
Codeblock | ||
---|---|---|
| ||
de.acme.firststeps.ListsController = ListsController; |
This puts the class into the namespace object you chose when writing the plugin descriptor file.
Restart your UM instance and try to run the GET request again.
This still yields a 404 and the logfile says:
Codeblock |
---|
Undefined REST action method: de.acme.firststeps.ListsController.prototype.index |
So the controller class could be found but it does not define an index action method.
Fix this by allowing the index action with the GET verb and adding an empty method named index_GET
to your controller:
...
language | js |
---|
...
tutorial/hello?a=Hello&b=world
URL mapping
Please note, that de.acme.tutorialController
corresponds to the name of your plugin as defined in plugin.desc.json
plus the special Controller
suffix that tells the backend that this should be exposed as a REST controller.
Setup REST Proxy and expose new endpoint
Create a file named rest-proxy/cmsbs-restproxy.properties
that configures the REST Proxy:
Codeblock | ||
---|---|---|
| ||
cmsbs.resturl=http://localhost:8080/cmsbs/rest
cmsbs.restproxy.limit.controller.whitelist.tut1 = "de.acme.tutorial" |
Insert the following cp lines to your build.gradle
file:
Codeblock | ||
---|---|---|
| ||
setup.doLast { constructor() {... allowActions(this, 'index_GET'); // UM REST Proxy } index_GET() { } } ... |
Reload and you should get an empty page with a status code of 200.
Enable auto-reloading
If you are tired of restarting your UM instance for each and every little code manipulation to take effect, simply add the following line to your ~/UM/cmsbs-conf/cmsbs.properties
file and restart one more time:
Codeblock |
---|
cmsbs.cse.autoreload = true |
From now on CSE scripts will be reloaded automatically as soon as one of the .js or .es6 files changes.
JSON response
Now, make your index action return a static JSON response:
Codeblock | ||
---|---|---|
| ||
index_GET() {
renderJson({
shoutOut: 'This is a working REST endpoint!'
}, 200);
} |
You can replace the 200 by whichever status code you want to return.
Include the global params
and request
variable in your response to make it a little more dynamic:
Codeblock | ||
---|---|---|
| ||
...
index_GET() {
renderJson({
shoutOut: 'This is a working REST endpoint!',
params,
request
}, 200);
}
... |
...
cp('UM/web-integration/cmsbs-restproxy.war', new File(pinuts.um.webappsDir, 'p.war'))
cp('rest-proxy/cmsbs-restproxy.properties', new File(pinuts.um.serverHome, 'cmsbs-restproxy.properties'))
} |
Setup and run your UM instance:
Codeblock |
---|
gradle setup run |
Your new REST endpoint should now be publicly available via REST proxy:
http://localhost:8080/cmsbs/restp/de.acme.firststeps.Lists/index/aaa/bbb/ccc?a=123&b=456 in your browser and try to identify the additional path components and URL parameters in the request property returned within the response body.tutorial/hello
Next steps
You can now progress to implement more useful endpoints. See also: Functional REST endpoints