«1. Обзор

В настоящее время мы видим множество способов предоставления данных приложением через Интернет.

Часто приложение использует веб-службу SOAP или REST для предоставления своих API. Тем не менее, есть потоковые протоколы, такие как RSS и Atom, которые также следует учитывать.

В этом кратком руководстве мы рассмотрим несколько удобных способов работы с веб-сервисами в Groovy для каждого из этих протоколов.

2. Выполнение HTTP-запросов

Для начала давайте выполним простой HTTP-запрос GET, используя класс URL. Мы будем использовать API-интерфейсы Postman Echo во время нашего исследования.

Сначала мы вызовем метод openConnection класса URL, а затем установим для requestMethod значение GET:

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

Точно так же мы можем сделать запрос POST, установив для requestMethod значение POST:

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

~~ ~ Кроме того, мы можем передать параметры POST-запросу с помощью 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

Здесь Groovy с замыканием выглядит очень удобно и делает код чище.

Давайте воспользуемся JsonSlurper для преобразования ответа String в JSON:

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

3. Ленты RSS и Atom

Ленты RSS и Atom — распространенные способы предоставления контента, такого как новости, блоги и технические форумы, через паутина.

Кроме того, оба канала имеют формат XML. Поэтому мы можем использовать класс Groovy XMLParser для разбора содержимого.

Давайте прочитаем несколько главных новостей из новостей Google, используя их RSS-канал:

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

Точно так же мы можем читать каналы Atom. Однако из-за различий в спецификациях обоих протоколов мы будем по-разному обращаться к содержимому каналов Atom:

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

Кроме того, мы понимаем, что Groovy поддерживает все библиотеки Java, рекомендованные в Groovy. Поэтому мы, безусловно, можем использовать Rome API для чтения RSS-каналов.

4. Запрос и ответ SOAP

SOAP — это один из самых популярных протоколов веб-сервисов, используемых приложениями для предоставления своих сервисов через Интернет.

Мы будем использовать библиотеку groovy-wslite для использования API-интерфейсов SOAP. Давайте добавим его последнюю зависимость в наш pom.xml:

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

Кроме того, мы можем добавить последнюю зависимость с помощью Gradle:

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

Или, если мы хотим написать сценарий Groovy. Мы можем добавить его напрямую с помощью @Grab:

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

Библиотека groovy-wslite предоставляет класс SOAPClient для взаимодействия с API-интерфейсами SOAP. В то же время у него есть класс SOAPMessageBuilder для создания сообщения запроса.

Давайте воспользуемся SOAP-сервисом преобразования чисел с помощью 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-запрос и ответ

REST — еще один популярный архитектурный стиль, используемый для создания веб-сервисов. Кроме того, API-интерфейсы предоставляются на основе методов HTTP, таких как GET, POST, PUT и DELETE.

5.1. GET

Мы будем использовать уже обсуждавшуюся библиотеку groovy-wslite для использования REST API. Он предоставляет класс RESTClient для беспроблемного общения.

Сделаем GET-запрос к уже рассмотренному API Postman:

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

Теперь давайте отправим POST-запрос к Postman API. В то же время мы будем передавать параметры формы как 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

Здесь мы установили JSON в качестве заголовка принятия по умолчанию.

6. Аутентификация для веб-службы

С ростом количества веб-служб и приложений, взаимодействующих друг с другом, рекомендуется иметь защищенную веб-службу.

В результате важно сочетание HTTPS и механизма аутентификации, такого как Basic Auth и OAuth.

Поэтому приложение должно аутентифицировать себя при использовании API веб-службы.

6.1. Basic Auth

Мы можем использовать уже обсуждавшийся класс RESTClient. Давайте воспользуемся классом HTTPBasicAuthorization с учетными данными для выполнения базовой аутентификации:

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

В качестве альтернативы мы можем напрямую передать учетные данные (в кодировке Base64) в параметре заголовков:

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

6.2. OAuth 1.0

Точно так же мы можем сделать запрос OAuth 1.0, передав параметры аутентификации, такие как ключ потребителя и секрет потребителя.

Однако, поскольку у нас нет встроенной поддержки OAuth 1.0, как у других механизмов, нам придется сделать всю работу самостоятельно:

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. Заключение

«В этом руководстве мы рассмотрели несколько удобных способов работы с веб-службами в Groovy.

В то же время мы увидели простой способ чтения RSS- или Atom-потока.

Как обычно, реализации кода доступны на GitHub.