Creating a custom REST Service in Mirth 3.0.x - rbeckman-nextgen/test-mc GitHub Wiki

  1. Mirth Connect
  2. Home
  3. Examples and Tutorials

Mirth Connect : Creating a custom REST Service in Mirth 3.0.x

Created by Christopher Schultz, last modified on Aug 30, 2016

Some clients will want a REST interface, and you'll want to host it within Mirth Connect. It's quite straightforward to build a rest-based service in Mirth Connect, but you have to know how to put the various pieces together.

Step-by-step guide

  1. Create a channel for your REST service
    1. Use an HTTP Listener as the Source
    2. Use a JavaScript Writer as a single destination (you can of course have other destinations if you want)
  2. Go back to your Source and configure a few more settings:
    1. The "Response" should be set to the destination created in step 1b
    2. Choose a reasonable context path like /myrestservice
    3. Choose "Headers, Query, and Body as XML" for the "Message Content" setting. This will give us access to all the incoming data from the client
    4. Set the "Response Content Type" to text/plain; charset=UTF-8. This will be the default setting that we can override later.
    5. Set the "Response Status Code" to ${responseStatusCode}. We will set this dynamically from our service handler.
    6. Add a "Response Header" called "Content-Type" with a value of ${responseContentType}. This will override the "Response Content Type" set above, but this time we can use dynamic values available from the channel map. Like the status code, this will be set dynamically from our service handler.
  3. Write your service handler in the destination's JavaScript
    1. Fetch the incoming request using var xml = new XML(connectorMessage.getRawData())
    2. Set the response's content  type using e.g. channelMap.put('responseContentType', 'application/json')
    3. Set the response's status code using e.g. channelMap.put('responseStatusCode', '201')
    4. Set the response's content (the response "entity") by returning a string value from the script
  4. Handle error conditions by notifying both Mirth and the client
    1. Catch exceptions or otherwise identify errors
    2. Return a Response object created with a call to com.mirth.connect.server.userutil.ResponseFactory.getTYPEResponse(string)

Sample Code

This sample code receives a REST-style request (with parameters in the URL itself) checks whether the client wants to receive XML or JSON and replies appropriately. What you do for the actual service is up to you.

Sample Code

// Mirth strings don't support startsWith() in Mirth 3.0.3.
// If necessary, add a method to the String prototype.
if (!String.prototype.startsWith) {
    String.prototype.startsWith = function(searchString, position){
      position = position || 0;
      return this.substr(position, searchString.length) === searchString;
  };
}

/*
Incoming message looks like this:

<HttpRequest>
<RemoteAddress>71.127.40.115</RemoteAddress>
<RequestUrl>http://www.example.com:8080/myrestservice</RequestUrl>
<Method>GET</Method>
<RequestPath>foo=bar</RequestPath>
<RequestContextPath>/myrestservice/param1/param2</RequestContextPath>
<Parameters>
<foo>bar</foo>
</Parameters>
<Header>
<Host>www.example.com:8080</Host>
<Accept-Encoding>identity</Accept-Encoding>
<User-Agent>Wget/1.18 (darwin15.5.0)</User-Agent>
<Connection>keep-alive</Connection>
<Accept>* / *</Accept>
</Header>
<Content/>
</HttpRequest>
*/

// Just in case we fail, set a sane responseContentType
channelMap.put('responseContentType', 'text/plain');

var msg = XML(connectorMessage.getRawData());

// Get the REST data from the "context path" which is actually
// the "path info" of the request, so it will start with '/myrestservice'.
var rest = msg['RequestContextPath'];
var myServicePrefix = '/myrestservice';
var minimumURLParameterCount = 4; // This is the minimum you require to do your work
var maximumExpectedURLParameterCount = 5; // however many you expect to get
var params = rest.substring(myServicePrefix.length).split('/', maximumExpectedURLParameterCount);
if(params.length < minimumURLParameterCount)
 return Packages.com.mirth.connect.server.userutil.ResponseFactory.getErrorResponse('Too few parameters in request');
var mrn = params[1]; // params[0] will be an empty string

// Now, determine the client's preference for what data type to return (XML vs. JSON).
// We will default to XML.
var clientWantsJSON = false;
var responseContentType = 'text/xml';

// If we see any kind of JSON before any kind of XML, we'll use
// JSON. Otherwise, we'll use XML.
//
// Technically, this is incorrect resolution of the "Accept" header,
// but it's good enough for an example.
var mimeTypes = msg['Header']['Accept'].split(/\s*,\s*/);
for(var i=0; i<mimeTypes.length; ++i) {
  var mimeType = mimeTypes[i].toString();
  if(mimeType.startsWith('application/json')) {
    clientWantsJSON = true;
    responseContentType = 'application/json';
    break;
  } else if(mimeType.startsWith('application/xml')) {
    clientWantsJSON = false;
    responseContentType = 'application/xml';
    break;
  } else if(mimeType.startsWith('text/xml')) {
    clientWantsJSON = false;
    responseContentType = 'text/xml';
    break;
  }
}

var xml;
var json;

if(clientWantsJSON)
  json = { status : '' };
else
  xml = new XML('<response></response>');

try {
    /*
      Here is where you do whatever your service needs to actually do.
     */

  if(clientWantsJSON) {
   json.data = { foo: 1,
                  bar: 'a string',
                  baz: [ 'list', 'of', 'strings']
                };
  } else {
    xml['@foo'] = 1;
    xml['bar'] = 'a string';
    xml['baz'][0] = 'list';
    xml['baz'][1] = 'of';
    xml['baz'][3] = 'strings';
  }

  // Set the response code and content-type appropriately.
  // http://www.mirthproject.org/community/forums/showthread.php?t=12678

  channelMap.put('responseStatusCode', 200);

  if(clientWantsJSON) {
    json.status = 'success';
    var content = JSON.stringify(json);
    channelMap.put('responseContent', content);
    channelMap.put('responseContentType', responseContentType);
    return content;
  } else {
    channelMap.put('responseContentType', responseContentType);
    var content = xml.toString();
    channelMap.put('responseContent', content);
    return content;
  }
}
catch (err)
{
  channelMap.put('responseStatusCode', '500');
  if(clientWantsJSON) {
    json.status = 'error';
    if(err.javaException) {
      // If you want to unpack a Java exception, this is how you do it:
      json.errorType = String(err.javaException.getClass().getName());
      json.errorMessage = String(err.javaException.getMessage());
    }

    channelMap.put('responseContentType', responseContentType);

    // Return an error with our "error" JSON
    return Packages.com.mirth.connect.server.userutil.ResponseFactory.getErrorResponse(JSON.stringify(json));
  } else {
    if(err.javaException) {
      xml['response']['error']['@type'] = String(err.javaException.getClass().getName());
      xml['response']['error']['@message'] = String(err.javaException.getMessage());
    }

    channelMap.put('responseContentType', responseContentType);

    // Return an error with our "error" XML
    return Packages.com.mirth.connect.server.userutil.ResponseFactory.getErrorResponse(xml.toString());
  }
}

 

 

 

Document generated by Confluence on Nov 11, 2019 08:40

Atlassian

⚠️ **GitHub.com Fallback** ⚠️