How to create a REST service in webMethods Integration Server

A while ago I created my first REST service in webMethods Integration Server. It’s quite easy to do and works correctly out of the box. Software AG managed to implement the standards quite well and I didn’t have to go through hours of configuring (like I had to with SOAP webservices).

How to create a REST service in webMethods Integration Server

First of all, you don’t actually create a REST service, but a REST resource. A resource represents a business entity for wich you can call the basic CRUD operations through (multiple) services, that respond to the common HTTP methods (GET, POST, PUT, DELETE). So, a REST resource uses multiple Flow services that implement the logic. These services get called automatically by IS, when the corresponding HTTP call is made by the client.

My example implements a common scenario: Authenticating a user based on its username and password.

The first – and most important – question was, how to name the REST resource. I couldn’t name it User, as one might think at first, because this name doesn’t fit the notion of REST: I don’t create or read a user. The user already has to be there and simply gets authenticated. In a SOAP context I would create a Flow service like AuthenticateUser with Username and Password as parameters. But in REST we can only use the basic CRUD operations. And there is no HTTP method called AUTHENTICATE. So I had to find another name for the resource.

What I ended up with was the concept of a Session. When a user gets authenticated, a Session is created for him. When he logs off, the Session gets destroyed. I can also read the Session to find out, whether the user is already logged in. So it all seemed to make sense now.

After the nomenclature problem is solved, here’s a quick step-by-step guide on how I implemented the REST resource in IS.

Step-by-step guide

  • Create a Flow service that implements the logic you need.
    In my case, I created AuthenticateUser as described above (see Best practices for structuring packages in webMethods Integration Server for details on the package’s folder structure).
    Flow service AuthenticateUser
    As the REST resource is merely an additional access layer on top of existing logic (like a Web Service Descriptor), it’s good practice to keep the two concerns – business logic and access logic – separated. Another advantage of this approach is the fact, that you can simply re-use your existing Flow services and only have to add the REST part on top of it.
  • Make sure the Flow service works as expected.
    This step might seem obvious, but if you introduce another layer of complexity in your system, you better make sure the underlying parts already work correctly. Otherwise, the search for potential errors might take very long and you can’t be sure, if it’s really the REST part that goes wrong.
    Successful result of a call to AuthenticateUser
  • Create a REST Resource.
    This is a easy as selecting New -> REST Resource from Designer’s context menu, giving the resource a name and selecting the needed HTTP methods.
    Creating a REST Resource in webMethods Integration Server - Step 1
    Creating a REST Resource in webMethods Integration Server - Step 2
    Here, I used POST, because I want to create a new user session. If you are not exactly sure, which HTTP methods to use, here’s a quick mapping: GET -> read, POST -> create, PUT -> update, DELETE -> delete. Also see Using HTTP Methods for RESTful Services and When should we use PUT and when should we use POST?.
    Creating a REST Resource in webMethods Integration Server - Step 3
    Voilá, we created our first “REST Service”! 🙂
    Creating a REST Resource in webMethods Integration Server - Step 4
  • Define the parameters for the REST services.
    The newly created service _post has no parameters yet (aside from two technical parameters $resourceID and $path, see REST Developer’s Guide for an explanation of those). So you need to add them.
    Adding paramters to the REST service
    In my case, I simply used the same parameters from AuthenticateUser. But they also can be different.
  • Implement the REST service.
    Implementing the _post service is quite simple, because the main logic is already implemented in AuthenticateUser. Therefore, _post can simply call AuthenticateUser and only needs to take care of REST specialties, like setting a meaningful response code. Otherwise, IS returns 200 (see List of HTTP status codes for additional information) even if the authentication was not successful. Fortunately, there is an HTTP code that describes almost exactly what I need: 401 Unauthorized. You can set the response code with the IS service pub.flow:setResponseCode.
    Implementation of the _post service
  • Test the REST service.
    You can now call the _post service directly from Designer and make sure it works.
    Call _post
    Successful response from _post
    Unsuccessful response from _post
  • Test the REST service from outside IS.
    After you made sure, that the _post service works as expected, you can try and call it from outside IS. My tool of choice for this task is curl (which comes with the installation of Git for Windows, by the way). All REST resources are available in IS under the following URL without any further configuration:

    http://server:port/rest/FullyQualifiedResource
    

    Or translated to my example:

    http://localhost:5555/rest/ExamplePackage/Resources/Session
    

    You can call the REST service with this curl command on Windows (on Linux you need to replace ^ with \, see Windows: How to specify multiline command on command prompt?):

    curl^
      -u Administrator:manage^
      -X POST^
      -H "Accept: application/json"^
      -H "Content-Type: application/json"^
      -d "{\"Username\":\"Stefan\",\"Password\":\"secret\"}"^
      http://localhost:5555/rest/ExamplePackage/Resources/Session
    

    IS automatically unwraps the JSON payload and converts it to IS documents. You only need to provide the same document structure and field names as defined in your _post parameters.
    Result of curl call to _post service
    By the way: I had to use double quotes for the JSON payload and needed to escape the quotes inside the JSON data to make it work on Windows. When I used single quotes (e.g. -d '{"Username":"Stefan","Password":"secret"}'), I got this nice error:

    org.codehaus.jackson.JsonParseException:Unexpected character (''' (code 39)): expected a valid value (number, String, array, object, 'true', 'false' or 'null')\n at [Source: com.wm.net.HttpInputStream@74356f93; line: 1, column: 2]
    

And this leaves you with a fully functional REST service in webMethods Integration Server! 🙂

Official Documentation

These documents helped me along the way:

Recommended reading

For a very good introduction to REST I recommend the Pluralsight course REST Fundamentals:


REST Fundamentals – $29.00

REST is an overloaded, and thus misunderstood term in architectural circles these days. This course attempts to clear up some of the misunderstandings about REST as well as provide a more practical approach for designing RESTful solutions – both clients and services. Additionally, the course looks at REST from the perspective of the cloud and describes how REST is well-suited to meet the demands that the cloud brings to bear on a modern architecture.

43 thoughts on “How to create a REST service in webMethods Integration Server”

  1. Its really very good post..you have explained step by step. Please post some more, if you have any, its really helpful us to upgrade knowledge on new topics.

  2. Its really good post explaining step-by-step.
    If you explain about different methods usage of Rest,it would be helpful to learn about Restful webservices.

  3. Hi Stefen,

    Thanks for your clear explanation, I have followed the same steps which you have given but am getting below error after run the _post service. Please look into this error and let me know where I was wrong.

    Launch started: 2016-09-09 11:49:42.21
    Configuration name: _post
    Configuration location: E:/SoftwareAG/workspace95/.metadata/.plugins/org.eclipse.debug.core/.launches/_post.launch

    Could not run ‘_post’
    com.wm.lang.flow.FlowException: [ISC.0049.9009] Missing required property switch at ‘unlabeled BRANCH’

    com.wm.lang.flow.FlowException:[ISC.0049.9009] Missing required property switch at ‘unlabeled BRANCH’
    Launch completed: 2016-09-09 11:49:52.835

  4. Hi Sainath,

    it looks as if you miss a label in a branch. Could you perhaps step through the service with the debugger to find out at which position in your Flow service the error occurs?

    Best regards,
    Stefan

  5. Hi Alfred,

    you can call your REST service with any path without configuring anything. The information behind order will be available in the variables $resourceID (75909) and $path (customer/0122) inside your service.

    Best regards,
    Stefan

  6. Hi Stefan,

    Do you have any idea on how do we implement REST over _post method with XML as the request? I am unable to trace in pipeline as it gives log as below.

    0 node {com.wm.lang.xml.Document} = ‘DOCUMENT System ID: null Public ID: null’

  7. Hi Stefan

    Can you please provide the same examples for get and put and btw for post restful service how will the authentication happen if we are invoking it from outside.

    I have tried running with the ACL as anonymous and it went through but in real scenario how will this work

  8. Hi Vijay,

    are you running the service directly from within your browser via a GET request? If you only provide a POST method, a GET will produce a 405 error. You might want to take a look at Postman for testing purposes.

    Best regards,
    Stefan

  9. Hi abhihith,

    authentication will work exactly as with a SOAP webservice. You can provice Basic Authentication with your request to the REST service, e.g. via the Authorization header (e.g. Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==). I’ve used the same configuration with ACLs in Integration Server as with SOAP services.

    Best regards, Stefan

  10. Hello,

    Thanks for the guide but one thing I am having trouble understanding is this line: “IS automatically unwraps the JSON payload and converts it to IS documents”.

    In your example it looks like the input to your flow service is 4 strings. Did you also add a document to your input and mirrors the structure in or message body? Did you use a jsonStream and then utilize a public json service to convert that to a document? Or did you handle this some other way?

    Thank you!

  11. Hi Stefan,

    you are an oasis in the dessert of mediocre documentation from the software ag. Thanks for the well written article.

    Best regards
    Martin

  12. Hi Chris, no I didn’t add anything. The input parameters are exactly like they are shown in the example. You just need to create a JSON document in your caller and pass it to the service. If the names of these fields match the input fields, you’re done. See the example above: if the input parameter is “MyString”, you need to provide a JSON document { "MyString": "My value" }.

  13. Hi Stefan,

    Can you please post similar post with step by step guide to create HTTPS Rest services?

  14. Hi Stefan,

    Very good tutorial. Thank you.

    I was wondering if there is a way to access the REST request before the REST method takes over.

    The equivalent of SOAP Request Handler for the Web Services world.

    The idea is that the REST client can send a user creation call for example like:
    {userId:”1″, username:”john”}
    OR
    {user: {userId:”1″, username:”john”}}

    In the first case IS will map this to 2 input strings
    In the second case IS will map the input to a document.

    Second case is better because you can create doc types and easily manage the interface, especially if you have cases where you have just one REST method (_post) and multiple resources and you need to parse the $path variable.

    Thanks.
    Vlad.

  15. Hi Vlad,

    I think I would create two endpoints for the use case you described. Why should one endpoint be able to work with two different sets of input values?

    Best regards,
    Stefan

  16. Hi, for your forced 401 – Unauthorized error, did you encounter a “temporary disconnection” from your server? Every time I set 5xx HTTP status codes and some 4xx ones, I get the same message (com.wm.net.netexception) and a prompt that I got disconnected from the server (I didn’t).

    More details here.

    It’s a bit misleading and annoying especially when debugging.

  17. Hi Stefan,

    Can you please tell how can we access an HTTPS REST service?

    Thanks & Regards,
    Swati

  18. Hi Stefan,

    For HTTPS request, certificate and key will be provided by the client. How can it be used to send across an HTTPS request?

    Thanks & Regards.
    Swati

  19. Hi Stefan,
    I have a scenario here. Could you tell me how to achieve this.
    Need to publish JSON data to Google Cloud pub/sub through cloudStream adapter.
    Could you tell me the steps and components involved to complete this.

    Thanks,
    Karthika

  20. Hi Stefan,

    Thank you for your elegant example.

    Would it be possible to add to it an example of how to invoke it from a consumer web service running in another (or same) webMethods IS?

    Kind regards,
    Nigel

  21. Hi Stefan,

    One way would be to use pub.client.http can call a REST service, was wondering if there is an elegant way to analyze the response code, message, body.

    Thank you,
    Nigel

  22. Hi Nigel, yes, that’s exactly how I do it. Unfortunately, that’s not very elegant :-/ You need a few Flow steps and redundant service definitions. Another way would be to use the Application Platform in IS which makes developing Java services much easier, but I haven’t tried that, yet.

Leave a Comment

To create code blocks or other preformatted text, indent by four spaces:

    This will be displayed in a monospaced font. The first four 
    spaces will be stripped off, but all other whitespace
    will be preserved.
    
    Markdown is turned off in code blocks:
     [This is not a link](http://example.com)

To create not a block, but an inline code span, use backticks:

Here is some inline `code`.

For more help see http://daringfireball.net/projects/markdown/syntax