Generic Top

I just announced the new Learn Spring course, focused on the fundamentals of Spring 5 and Spring Boot 2:

>> CHECK OUT THE COURSE

1. Overview

Nowadays, we see a range of ways to expose data by an application over the web.

Often, the application uses a SOAP or REST web service to expose their APIs. However, there are streaming protocols like RSS and Atom to consider as well.

In this quick tutorial, we'll explore a few handy ways to work with web services in Groovy for each of these protocols.

2. Execute HTTP requests

To begin with, let's execute a simple HTTP GET request using the URL class. We'll consume the Postman Echo APIs during our exploration.

First, we'll call the openConnection method of the URL class and then set the requestMethod to GET:

def postmanGet = new URL('https://postman-echo.com/get')
def getConnection = postmanGet.openConnection()
getConnection.requestMethod = 'GET'
assert getConnection.responseCode == 200

Similarly, we can make a POST request by setting the requestMethod to POST:

def postmanPost = new URL('https://postman-echo.com/post')
def postConnection = postmanPost.openConnection()
postConnection.requestMethod = 'POST'
assert postConnection.responseCode == 200

Also, we can pass the parameters to the POST request using the outputStream.withWriter:

def form = "param1=This is request parameter."
postConnection.doOutput = true
def text
postConnection.with {
    outputStream.withWriter { outputStreamWriter ->
        outputStreamWriter << form
    }
    text = content.text
}
assert postConnection.responseCode == 200

Here, Groovy's with closure looks quite handy and makes the code cleaner.

Let's use the JsonSlurper to parse the String response into JSON:

JsonSlurper jsonSlurper = new JsonSlurper()
assert jsonSlurper.parseText(text)?.json.param1 == "This is request parameter."

3. RSS and Atom Feeds

RSS and Atom feed are common ways to expose the contents like news, blogs, and tech forums over the web.

Also, both of the feeds are XML-formatted. Therefore, we can use Groovy's XMLParser class to parse the content.

Let's read a few top stories from the Google News utilizing their RSS feed:

def rssFeed = new XmlParser()
    .parse("https://news.google.com/rss?hl=en-US&gl=US&ceid=US:en")
def stories = []
(0..4).each {
    def item = rssFeed.channel.item.get(it)
    stories << item.title.text()
}
assert stories.size() == 5

Similarly, we can read the Atom feeds. However, due to the variation in specifications of both protocols, we'll access the content differently in Atom feeds:

def atomFeed = new XmlParser()
    .parse("https://news.google.com/atom?hl=en-US&gl=US&ceid=US:en")
def stories = []
(0..4).each {
    def entry = atomFeed.entry.get(it)
    stories << entry.title.text()
}
assert stories.size() == 5

Also, we understand Groovy supports all Java libraries are encouraged in Groovy. Therefore, we can surely use the Rome API to read the RSS feeds.

4. SOAP Request and Response

SOAP is one of the most popular web service protocols used by applications to expose their services over the web.

We'll use the groovy-wslite library to consume the SOAP APIs. Let's add its latest dependency to our pom.xml:

<dependency>
    <groupId>com.github.groovy-wslite</groupId>
    <artifactId>groovy-wslite</artifactId>
    <version>1.1.3</version>
</dependency>

Alternatively, we can add the latest dependency using Gradle:

compile group: 'com.github.groovy-wslite', name: 'groovy-wslite', version: '1.1.3'

Or if we want to write a Groovy script. We can add it directly using @Grab:

@Grab(group='com.github.groovy-wslite', module='groovy-wslite', version='1.1.3')

The groovy-wslite library provides the SOAPClient class to communicate with SOAP APIs. At the same time, it has the SOAPMessageBuilder class to create the request message.

Let's consume a Number conversion SOAP Service using the SOAPClient:

def url = "http://www.dataaccess.com/webservicesserver/numberconversion.wso"
def soapClient = new SOAPClient(url)
def message = new SOAPMessageBuilder().build({
    body {
        NumberToWords(xmlns: "http://www.dataaccess.com/webservicesserver/") {
            ubiNum(123)
        }
    }
})
def response = soapClient.send(message.toString());
def words = response.NumberToWordsResponse
assert words == "one hundred and twenty three "

5. REST Request and Response

REST is another popular architectural style used for creating web services. Also, the APIs are exposed based on HTTP methods like GET, POST,  PUT, and DELETE.

5.1. GET

We'll use the already discussed groovy-wslite library to consume the REST APIs. It provides the RESTClient class for hassle-free communication.

Let's make a GET request to the already discussed Postman API:

RESTClient client = new RESTClient("https://postman-echo.com")
def path = "/get"
def response
try {
    response = client.get(path: path)
    assert response.statusCode = 200
    assert response.json?.headers?.host == "postman-echo.com"
} catch (RESTClientException e) {
    assert e?.response?.statusCode != 200
}

5.2. POST

Now, let's make a POST request to the Postman API. At the same time, we'll pass the form parameters as JSON:

client.defaultAcceptHeader = ContentType.JSON
def path = "/post"
def params = ["foo":1,"bar":2]
def response = client.post(path: path) {
    type ContentType.JSON
    json params
}
assert response.json?.data == params

Here, we've set the JSON as the default accept header.

6. Authentication for Web Service

With the growing amount of web services and applications communicating one with another, it's recommended to have a secure web service.

As a result, a combination of HTTPS and an authentication mechanism like Basic Auth and OAuth is important.

Therefore, an application must authenticate itself while consuming a web service API.

6.1. Basic Auth

We can use the already discussed RESTClient class. Let's use the HTTPBasicAuthorization class with credentials to perform a basic authentication:

def path = "/basic-auth"
client.authorization = new HTTPBasicAuthorization("postman", "password")
response = client.get(path: path)
assert response.statusCode == 200
assert response.json?.authenticated == true

Alternatively, we can directly pass the credentials (Base64 encoded) in the headers parameter:

def response = client
.get(path: path, headers: ["Authorization": "Basic cG9zdG1hbjpwYXNzd29yZA=="])

6.2. OAuth 1.0

Similarly, we can make an OAuth 1.0 request passing the auth parameters like consumer key and consumer secret.

However, since we don't have inbuilt support for OAuth 1.0 as we do for the other mechanisms, we'll have to do the work ourselves:

def path = "/oauth1"
def params = [oauth_consumer_key: "RKCGzna7bv9YD57c", 
    oauth_signature_method: "HMAC-SHA1", 
    oauth_timestamp:1567089944, oauth_nonce: "URT7v4", oauth_version: 1.0, 
    oauth_signature: 'RGgR/ktDmclkM0ISWaFzebtlO0A=']
def response = new RESTClient("https://postman-echo.com")
    .get(path: path, query: params)
assert response.statusCode == 200
assert response.statusMessage == "OK"
assert response.json.status == "pass"

7. Conclusion

In this tutorial, we've explored a few handy ways to work with web services in Groovy.

At the same time, we've seen an easy way to read an RSS or Atom feed.

As usual, the code implementations are available over on GitHub.

Generic bottom

I just announced the new Learn Spring course, focused on the fundamentals of Spring 5 and Spring Boot 2:

>> CHECK OUT THE COURSE
Comments are closed on this article!