Groovy built-in REST/HTTP client?
Asked Answered
D

7

117

I heard that Groovy has a built-in REST/HTTP client. The only library I can find is HttpBuilder, is this it?

Basically I'm looking for a way to do HTTP GETs from inside Groovy code without having to import any libraries (if at all possible). But since this module doesn't appear to be a part of core Groovy I'm not sure if I have the right lib here.

Duquette answered 5/9, 2014 at 19:14 Comment(3)
To summarize the below answers j = new groovy.json.JsonSlurper().parseText(new URL("https://httpbin.org/get").getText()) then println j.headers["User-Agent"]Rikki
You might also checkout an updated (re)version of the HttpBuilder library - http-builder-ng.github.io/http-builder-ngCanescent
If you use @Grab it makes http-builder fairly painless to use: @Grab(group='org.codehaus.groovy.modules.http-builder', module='http-builder', version='0.7')Aloha
F
181

Native Groovy GET and POST

// GET
def get = new URL("https://httpbin.org/get").openConnection();
def getRC = get.getResponseCode();
println(getRC);
if (getRC.equals(200)) {
    println(get.getInputStream().getText());
}

// POST
def post = new URL("https://httpbin.org/post").openConnection();
def message = '{"message":"this is a message"}'
post.setRequestMethod("POST")
post.setDoOutput(true)
post.setRequestProperty("Content-Type", "application/json")
post.getOutputStream().write(message.getBytes("UTF-8"));
def postRC = post.getResponseCode();
println(postRC);
if (postRC.equals(200)) {
    println(post.getInputStream().getText());
}
Fakery answered 8/3, 2017 at 7:1 Comment(12)
How do you set headers on GET or POST calls with this?Gourmand
@Gourmand The setRequestProperty method does that. I used it in the example to set the Content-Type header. See docs.oracle.com/javase/8/docs/api/java/net/…Fakery
In pipeline as code, you must do it in shared library otherwise jenkins will forbid it for security reasons, Overriding them is possible but then you may really add vulnerabilities.Anuska
How to get the response headers? I can't find it out .Denysedenzil
@Denysedenzil figure it out: post.getHeaderFields(), see more methods in docjar.com/docs/api/sun/net/www/protocol/https/…Denysedenzil
At what exact point is the HTTP Request actually sent? Sometime during post.getResponseCode(); ?Plagiarize
@PhilippDoerner The request is implicitly sent by getResponseCode() or any similar method that depends on the connection being connected. I believe you can also call connect() to explicitly send the request. docs.oracle.com/javase/8/docs/api/java/net/URLConnection.htmlFakery
@JimPerris Could it be that post.getOutputStream().write(message.getBytes("UTF-8")); also counts among those that implicitly send a request? I just encountered a bug where I set a request header after writing the body with that statement and it threw an error of "already connected", which was fixed by moving the writing of the body after the writing of the headersPlagiarize
@PhilippDoerner sure, that could be the case. I haven't messed with Groovy or Java in a couple years, so kinda rusty on this stuff.Fakery
URL.getOpenConnection returns an URLConnection. But URLConnection does not know the method setRequestMethod, because only HttpURLConnection (a child of URLConnection) knows the method. If I try this in ScriptRunner, I get a type error: Cannot find matching method java.net.URLConnection#setRequestMethod(java.lang.String).Inclement
When the URL starts with "http" then an HttpUrlConnection object is returned, but you must cast the object to HttpUrlConnection because indeed the return type of openConnection is not HttpUrlConnection. So use something like def post = (HttpUrlConnection) new URL("https://httpbin.org/post").openConnection();Hypethral
Per my last comment... beware when typecasting like this. If your code needs to be robust, then it's better to explicitly check the type, catch the possibly resulting exception, or have a good catch all exception handler in place.Hypethral
M
69

If your needs are simple and you want to avoid adding additional dependencies you may be able to use the getText() methods that Groovy adds to the java.net.URL class:

new URL("http://stackoverflow.com").getText()

// or

new URL("http://stackoverflow.com")
        .getText(connectTimeout: 5000, 
                readTimeout: 10000, 
                useCaches: true, 
                allowUserInteraction: false, 
                requestProperties: ['Connection': 'close'])

If you are expecting binary data back there is also similar functionality provided by the newInputStream() methods.

Mychael answered 5/9, 2014 at 20:16 Comment(1)
How about a post request?Efren
P
40

The simplest one got to be:

def html = "http://google.com".toURL().text
Philadelphia answered 13/8, 2016 at 20:4 Comment(2)
Brillient idea. what can I do if we need add proxy server name and port?Yoheaveho
proxy settings are controlled by the containing JVM as described in the oracle documentation.Protoxylem
P
33

You can take advantage of Groovy features like with(), improvements to URLConnection, and simplified getters/setters:

GET:

String getResult = new URL('http://mytestsite/bloop').text

POST:

String postResult
((HttpURLConnection)new URL('http://mytestsite/bloop').openConnection()).with({
    requestMethod = 'POST'
    doOutput = true
    setRequestProperty('Content-Type', '...') // Set your content type.
    outputStream.withPrintWriter({printWriter ->
        printWriter.write('...') // Your post data. Could also use withWriter() if you don't want to write a String.
    })
    // Can check 'responseCode' here if you like.
    postResult = inputStream.text // Using 'inputStream.text' because 'content' will throw an exception when empty.
})

Note, the POST will start when you try to read a value from the HttpURLConnection, such as responseCode, inputStream.text, or getHeaderField('...').

Pelargonium answered 25/11, 2017 at 19:35 Comment(2)
Voted up for the 'note' that was the key. ThanksMoonshot
This looks very simple. What's with exception handling and ressource handling? Is there no close() and disconnect() necessary for the open connection? Is there a simple way to pass the content of a file through the http post outputstream?Daubigny
W
14

HTTPBuilder is it. Very easy to use.

import groovyx.net.http.HTTPBuilder

def http = new HTTPBuilder('https://google.com')
def html = http.get(path : '/search', query : [q:'waffles'])

It is especially useful if you need error handling and generally more functionality than just fetching content with GET.

Wreckful answered 5/9, 2014 at 19:53 Comment(5)
Thanks @Dakota Brown - and can you confirm I don't need to import anything?Duquette
That's the downside, you'll need the jar: groovy.codehaus.org/modules/http-builder/download.html. Nothing in groovy core for it.Wreckful
Thanks @Dakota Brown - please see my comment underneath Will P's answer - I have the same question for youDuquette
grails.org/plugin/rest will allow you to use HTTP Builder in GRAILS projectWreckful
I downvoted because in 2020 this isn't working well. http-builder hasn't been updated since 2014, and it uses a JSON library that hasn't been updated since 2010 and isn't actually on Maven central anymore (try downloading the JAR: you'll get a 404).Freewheeling
P
1

I don't think http-builder is a Groovy module, but rather an external API on top of apache http-client so you do need to import classes and download a bunch of APIs. You are better using Gradle or @Grab to download the jar and dependencies:

@Grab(group='org.codehaus.groovy.modules.http-builder', module='http-builder', version='0.7.1' )
import groovyx.net.http.*
import static groovyx.net.http.ContentType.*
import static groovyx.net.http.Method.*

Note: since the CodeHaus site went down, you can find the JAR at (https://mvnrepository.com/artifact/org.codehaus.groovy.modules.http-builder/http-builder)

Procurance answered 5/9, 2014 at 20:0 Comment(2)
I don't know grails enough to answer and i don't think it belongs to the view, neither. You'd probably better downloading the dependencies or using URL as per @John's answerProcurance
@Duquette the @Grab would be added in the grails-app/conf/BuildConfig.groovy. Then it would be working within controllers, services, ... -- but please don't add such code to the view.Orthogenetic
S
-2
import groovyx.net.http.HTTPBuilder;

public class HttpclassgetrRoles {
     static void main(String[] args){
         def baseUrl = new URL('http://test.city.com/api/Cirtxyz/GetUser')

         HttpURLConnection connection = (HttpURLConnection) baseUrl.openConnection();
         connection.addRequestProperty("Accept", "application/json")
         connection.with {
           doOutput = true
           requestMethod = 'GET'
           println content.text
         }

     }
}
Sennacherib answered 13/9, 2017 at 11:31 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.