Calling REST APIs with Groovy

by Didin J. on Oct 03, 2025 Calling REST APIs with Groovy

Learn how to make HTTP requests in Groovy with JsonSlurper, POST, headers, authentication, and HTTPBuilder for cleaner API integration.

Groovy is a powerful, dynamic language for the Java platform that blends seamlessly with existing Java code while offering concise syntax and scripting flexibility. One of its most practical use cases is interacting with RESTful APIs—whether for automation, testing, or lightweight backend tasks.

In this tutorial, you’ll learn step by step how to call REST APIs using Groovy. We’ll start with simple GET requests, move on to parsing JSON, sending POST requests with payloads, adding authentication headers, and finally, exploring more advanced libraries to simplify HTTP operations. By the end, you’ll be equipped to build scripts that can communicate with any REST API quickly and efficiently.


1. Prerequisites

Before we dive in, make sure you have the following set up on your machine:

  • Java Development Kit (JDK 17 or higher)
    Since Groovy runs on the JVM, you’ll need Java installed. You can check your version with:

     
    java -version

     

  • Groovy (latest version, preferably 4.x)
    The easiest way to install Groovy is using SDKMAN!:

     
    curl -s "https://get.sdkman.io" | bash
    source "$HOME/.sdkman/bin/sdkman-init.sh"
    sdk install groovy

     

    Verify the installation:

     
    groovy -v

     

  • Basic understanding of REST APIs
    You should be familiar with common HTTP methods like GET, POST, PUT, and DELETE.

  • A REST API to test against
    In this tutorial, we’ll use the JSONPlaceholder fake API, which is perfect for practicing GET and POST requests.

👉 Once you have these ready, you’re set to start making API calls with Groovy.


2. Setting Up Groovy

Before we can start calling REST APIs, we need to make sure Groovy is properly installed and ready to use.

Step 1: Install Groovy

There are two common ways to install Groovy:

Option A: Using SDKMAN! (Recommended)
SDKMAN! is a handy tool for managing parallel versions of multiple SDKs. If you don’t already have it installed:

curl -s "https://get.sdkman.io" | bash
source "$HOME/.sdkman/bin/sdkman-init.sh"

Then install Groovy with:

sdk install groovy

Option B: Manual Installation

  • Download the latest Groovy binary from the official Groovy website.

  • Extract the archive to a directory of your choice (e.g., /opt/groovy).

  • Add Groovy’s bin directory to your system’s PATH. For example, in Linux/macOS, edit ~/.bashrc or ~/.zshrc:

export PATH=$PATH:/opt/groovy/bin

Step 2: Verify Installation

Once installed, check the Groovy version:

groovy -v

You should see something like:

Groovy Version: 4.0.15 JVM: 17.0.9 Vendor: Oracle OS: Mac OS X

Step 3: Test a Simple Script

Let’s confirm that Groovy is working by running a small script:

Create a file hello.groovy with the following content:

println "Hello, Groovy!"

Run it with:

groovy hello.groovy

Output:

Hello, Groovy!

✅ Congratulations! Groovy is installed and running. You’re now ready to use it for making HTTP requests.


3. Making a Simple GET Request

The most common operation when working with REST APIs is fetching data using an HTTP GET request. Groovy makes this really simple because it extends Java classes like URL with helper methods.

Example: Fetching a Post from JSONPlaceholder

def url = new URL("https://jsonplaceholder.typicode.com/posts/1")
def response = url.text
println(response)

Explanation

  • new URL(...) → Creates a URL object pointing to the API endpoint.

  • .text → Groovy adds this shortcut to the Java URL class, allowing you to fetch the content directly as a string.

  • println(response) → Prints the raw JSON response from the API.

Expected Output

When you run the script above (groovy getRequest.groovy), you’ll see:

{
  "userId": 1,
  "id": 1,
  "title": "sunt aut facere repellat provident occaecati excepturi optio reprehenderit",
  "body": "quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto"
}

Why This Works Well

  • No need for extra libraries.

  • Perfect for quick one-liners or automation scripts.

  • You can fetch any public API with just two lines of Groovy.

👉 In the next section, we’ll learn how to parse this JSON response so we can extract specific fields like title or body.


4. Parsing JSON Responses

Most REST APIs return data in JSON format. Groovy comes with a built-in class called JsonSlurper that makes it easy to parse JSON into maps and lists, which you can use just like regular Groovy objects.

Example: Parse a JSON Response

import groovy.json.JsonSlurper

def url = new URL("https://jsonplaceholder.typicode.com/posts/1")
def jsonText = url.text

def json = new JsonSlurper().parseText(jsonText)

println("ID: ${json.id}")
println("User ID: ${json.userId}")
println("Title: ${json.title}")
println("Body: ${json.body}")

Explanation

  • JsonSlurper → Groovy’s JSON parser.

  • .parseText(jsonText) → Converts the JSON string into a Groovy object (usually a Map).

  • ${json.title} → You can access fields directly like properties.

Expected Output

ID: 1
User ID: 1
Title: sunt aut facere repellat provident occaecati excepturi optio reprehenderit
Body: quia et suscipit
suscipit recusandae consequuntur expedita et cum
reprehenderit molestiae ut ut quas totam
nostrum rerum est autem sunt rem eveniet architecto

Parsing Arrays

Some endpoints return an array of objects instead of a single one. For example:

import groovy.json.JsonSlurper

def url = new URL("https://jsonplaceholder.typicode.com/posts")
def posts = new JsonSlurper().parseText(url.text)

println "Total posts: ${posts.size()}"
println "First post title: ${posts[0].title}"

This will output:

Total posts: 100
First post title: sunt aut facere repellat provident occaecati excepturi optio reprehenderit

✅ Now you can work with API data just like Groovy maps and lists, making it very convenient for automation, reporting, or testing tasks.


5. Sending a POST Request

While GET is useful for retrieving data, you’ll often need to send data to an API using a POST request. This is common for creating resources (e.g., creating a new user, posting a comment).

In Groovy, you can use HttpURLConnection to send POST requests and include JSON payloads.

Example: Sending JSON Data

import groovy.json.JsonOutput

def url = new URL("https://jsonplaceholder.typicode.com/posts")
def conn = url.openConnection()
conn.setRequestMethod("POST")
conn.doOutput = true
conn.setRequestProperty("Content-Type", "application/json; charset=UTF-8")

// JSON payload
def payload = [
    title : "Groovy Post",
    body  : "Hello from Groovy!",
    userId: 1
]

// Write the JSON to the request body
conn.outputStream.withWriter("UTF-8") { writer ->
    writer << JsonOutput.toJson(payload)
}

// Read the response
println "Response Code: ${conn.responseCode}"
println "Response: ${conn.inputStream.text}"

Explanation

  • setRequestMethod("POST") → Tells the connection we’re sending a POST request.

  • setRequestProperty("Content-Type", "application/json") → Specifies that we’re sending JSON data.

  • JsonOutput.toJson(payload) → Converts the Groovy map into a JSON string.

  • conn.outputStream.withWriter { ... } → Writes the JSON payload to the request body.

  • conn.responseCode and conn.inputStream.text → Retrieve the HTTP status code and server response.

Expected Output (from JSONPlaceholder)

Response Code: 201
Response: {
  "title": "Groovy Post",
  "body": "Hello from Groovy!",
  "userId": 1,
  "id": 101
}

💡 Note: JSONPlaceholder is a fake API, so it doesn’t actually create new posts—it just returns a mock response with an id.

✅ Now you know how to send JSON payloads using POST requests in Groovy.


6. Adding Headers & Authentication

Most real-world APIs require additional headers—for example, specifying the content type, passing an API key, or including a Bearer token for authentication. With Groovy, adding headers is simple.

Example: Adding Custom Headers

def url = new URL("https://jsonplaceholder.typicode.com/posts/1")
def conn = url.openConnection()

// Add custom headers
conn.setRequestProperty("Accept", "application/json")
conn.setRequestProperty("User-Agent", "GroovyClient/1.0")

println "Response Code: ${conn.responseCode}"
println "Response: ${conn.inputStream.text}"

Example: Bearer Token Authentication

When working with secure APIs, you’ll often need to include an Authorization header.

def url = new URL("https://api.example.com/data")
def conn = url.openConnection()
conn.setRequestMethod("GET")

// Add authorization header
conn.setRequestProperty("Authorization", "Bearer YOUR_ACCESS_TOKEN")
conn.setRequestProperty("Accept", "application/json")

println "Response Code: ${conn.responseCode}"
println "Response: ${conn.inputStream.text}"

Example: API Key in Header

Some APIs use an API key instead of a token:

def url = new URL("https://api.example.com/weather")
def conn = url.openConnection()
conn.setRequestMethod("GET")

conn.setRequestProperty("x-api-key", "YOUR_API_KEY")

println "Response Code: ${conn.responseCode}"
println "Response: ${conn.inputStream.text}"

Why Headers Matter

  • Authorization → Secure access to APIs.

  • Content-Type / Accept → Tell the API the format you’re sending or expecting (JSON, XML, etc.).

  • User-Agent → Identifies your client (sometimes required).

✅ With headers and authentication, you can now access protected APIs just as easily as public ones.


7. Handling Errors & Response Codes

When working with REST APIs, not every request will succeed. You might encounter:

  • 404 Not Found (wrong endpoint or resource missing)

  • 401 Unauthorized / 403 Forbidden (missing or invalid credentials)

  • 500 Internal Server Error (server-side issue)

  • Timeouts or connectivity problems

Groovy lets you inspect response codes and catch exceptions to handle these cases gracefully.

Example: Basic Error Handling

def url = new URL("https://jsonplaceholder.typicode.com/invalid-endpoint")
def conn = url.openConnection()
conn.setRequestMethod("GET")

try {
    def responseCode = conn.responseCode
    if (responseCode == 200) {
        println "Success: ${conn.inputStream.text}"
    } else {
        println "Error: Response code ${responseCode}"
        println "Error details: ${conn.errorStream?.text}"
    }
} catch (IOException e) {
    println "Exception occurred: ${e.message}"
}

Explanation

  • conn.responseCode → Retrieves the HTTP status code.

  • conn.inputStream.text → Reads the response body (if successful).

  • conn.errorStream?.text → Reads error details if available (e.g., from a 404 or 500 response).

  • try-catch → Ensures the script doesn’t crash on network errors.

Example: Handling Authentication Failures

def url = new URL("https://api.example.com/protected")
def conn = url.openConnection()
conn.setRequestMethod("GET")

// Intentionally missing token
conn.setRequestProperty("Accept", "application/json")

try {
    if (conn.responseCode == 200) {
        println "Response: ${conn.inputStream.text}"
    } else if (conn.responseCode == 401 || conn.responseCode == 403) {
        println "Authentication failed: ${conn.responseCode}"
    } else {
        println "Unexpected error: ${conn.responseCode}"
    }
} catch (Exception e) {
    println "Request failed: ${e.message}"
}

Best Practices for Error Handling

  • Always check responseCode before reading the response.

  • Use errorStream for error details.

  • Wrap requests in try-catch to handle connectivity issues.

  • For production scripts, consider logging instead of just printing.

✅ With proper error handling, your Groovy scripts will be more reliable and easier to debug.


8. Using Groovy’s @Grab and HTTPBuilder for Cleaner API Calls

While HttpURLConnection works fine, it can get verbose, especially when handling headers, POST bodies, and responses. Groovy supports Grape (@Grab), which allows you to fetch external libraries directly from Maven Central, making scripts more powerful without needing a full project setup.

One popular library for REST calls in Groovy is HTTPBuilder.

Example: Using @Grab to Import HTTPBuilder

Create a script called httpbuilder-example.groovy:

@Grab('com.squareup.okhttp3:okhttp:4.12.0')
@Grab('com.fasterxml.jackson.core:jackson-databind:2.18.2')
import okhttp3.*
import com.fasterxml.jackson.databind.ObjectMapper

def client = new OkHttpClient()
def mapper = new ObjectMapper()

// GET request
def request = new Request.Builder()
        .url("https://jsonplaceholder.typicode.com/posts/1")
        .build()

def response = client.newCall(request).execute()
def json = mapper.readTree(response.body().string())

println "Title: ${json.get('title').asText()}"
println "Body: ${json.get('body').asText()}"

Explanation

  • @Grab → Automatically downloads and adds the dependency (http-builder) at runtime.

  • RESTClient → Simplifies HTTP operations like GET, POST, PUT, DELETE.

  • response.data → Parsed JSON response (already converted to Groovy objects).

Example: Sending a POST Request with HTTPBuilder

@Grab('com.squareup.okhttp3:okhttp:4.12.0')
@Grab('com.fasterxml.jackson.core:jackson-databind:2.18.2')
import okhttp3.*
import com.fasterxml.jackson.databind.ObjectMapper

def client = new OkHttpClient()
def mapper = new ObjectMapper()

// GET request
def request = new Request.Builder()
        .url("https://jsonplaceholder.typicode.com/posts/1")
        .build()

def response = client.newCall(request).execute()
def json = mapper.readTree(response.body().string())

println "Title: ${json.get('title').asText()}"
println "Body: ${json.get('body').asText()}"

// POST request
def postBody = RequestBody.create(
        mapper.writeValueAsString([title: "OkHttp Post", body: "Hello Groovy 4", userId: 1]),
        MediaType.get("application/json; charset=utf-8")
)

def postRequest = new Request.Builder()
        .url("https://jsonplaceholder.typicode.com/posts")
        .post(postBody)
        .build()

def postResponse = client.newCall(postRequest).execute()
println "New Post Response: ${postResponse.body().string()}"

Expected Output (from JSONPlaceholder):

Title: sunt aut facere repellat provident occaecati excepturi optio reprehenderit
Body: quia et suscipit
suscipit recusandae consequuntur expedita et cum
reprehenderit molestiae ut ut quas totam
nostrum rerum est autem sunt rem eveniet architecto
New Post Response: {
  "title": "OkHttp Post",
  "body": "Hello Groovy 4",
  "userId": 1,
  "id": 101
}

Why Use HTTPBuilder?

✅ Cleaner syntax for REST calls
✅ Automatic JSON parsing
✅ Easier handling of headers and request bodies
✅ Reduces boilerplate compared to HttpURLConnection

👉 With @Grab and HTTPBuilder, your Groovy scripts are shorter, cleaner, and easier to maintain.


9. Conclusion + Best Practices

In this tutorial, we explored multiple ways to perform HTTP requests in Groovy, starting from the standard HttpURLConnection to more advanced and expressive approaches using Groovy’s built-in JsonSlurper, JsonOutput, and libraries such as HTTPBuilder. Along the way, we demonstrated how to handle common tasks like parsing JSON responses, sending POST requests, adding headers and authentication, and dealing with response codes and errors.

Key Takeaways

  • Groovy + Java Interop: You can always fall back on Java’s HttpURLConnection if you need low-level control or wish to avoid extra dependencies.

  • JsonSlurper & JsonOutput: These provide a straightforward way to parse incoming JSON and create JSON payloads when working with REST APIs.

  • HTTPBuilder/RESTClient: These libraries simplify boilerplate code, letting you focus on the API interaction rather than raw request/response handling.

Best Practices

  1. Always Handle Errors Gracefully
    Check response codes before processing the body. Implement retries or fallback logic if the API is not reliable.

  2. Use Timeouts
    Set appropriate connection and read timeouts to prevent hanging requests.

  3. Secure Authentication
    Store API keys, tokens, and credentials securely (e.g., environment variables or secrets manager). Avoid hardcoding them in source code.

  4. Prefer External Libraries for Complex APIs
    While HttpURLConnection works, libraries like HTTPBuilder or modern alternatives (OkHttp, Apache HttpClient) offer more readable and maintainable code.

  5. Log Requests and Responses
    For debugging, logging API calls helps troubleshoot issues with payloads, headers, or authentication.

  6. Keep Dependencies in Check
    If using @Grab for dependencies, ensure compatibility with your Groovy version to avoid runtime errors like NoClassDefFoundError.

✅ With these tools and practices, you should be able to integrate Groovy seamlessly with any RESTful API, whether for quick scripts, backend services, or data pipelines.

You can find the source code used in this tutorial on our GitHub.

That's just the basics. If you need more deep learning about Groovy and Grails, you can take the following cheap course:

Thanks!