Create a Simple REST API in Groovy with Micronaut

by Didin J. on Oct 27, 2025 Create a Simple REST API in Groovy with Micronaut

Learn how to build a simple REST API in Groovy using Micronaut, featuring CRUD endpoints, lightweight performance, and Spock testing examples.

In modern web development, REST APIs have become the backbone of most applications — from web and mobile apps to IoT systems and microservices. Developers often look for frameworks that make building APIs both simple and efficient while maintaining excellent performance and scalability.

Micronaut is one such framework — a modern, JVM-based, full-stack microservice framework designed for building modular and lightweight applications. It’s developed by the same team behind Grails but takes a fresh approach by emphasizing ahead-of-time (AOT) compilation, fast startup times, and low memory usage.

Unlike traditional frameworks that rely heavily on runtime reflection and classpath scanning, Micronaut performs dependency injection, AOP, and configuration processing at compile time, resulting in impressive performance even in resource-constrained environments.

Pairing Micronaut with Groovy makes development even smoother. Groovy’s expressive syntax, dynamic capabilities, and concise code structure allow developers to focus more on the business logic rather than boilerplate code.

In this tutorial, you’ll learn how to create a simple REST API in Groovy using Micronaut, step by step. We’ll build a small CRUD-style service to manage data (for example, a list of books) and explore how Micronaut simplifies creating endpoints, handling requests, and returning JSON responses.

By the end of this tutorial, you will know how to:

  • Set up a Micronaut project with Groovy.

  • Create RESTful endpoints for CRUD operations.

  • Run and test your API locally.

  • Understand the basics of Micronaut’s lightweight architecture.


Prerequisites

Before starting this tutorial, make sure your development environment is ready for Groovy and Micronaut. You’ll need to install a few tools and dependencies to follow along smoothly.

What You’ll Need

  1. JDK 17 or later
    Micronaut requires Java 17 or newer. You can check if it’s installed by running:

     
    java -version

     

    If not installed, download it from the Adoptium website or use SDKMAN!.

  2. SDKMAN! (optional but recommended)
    SDKMAN! is a handy tool for managing multiple versions of Java, Groovy, and Micronaut.
    To install it (on macOS, Linux, or WSL), run:

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

     

  3. Micronaut CLI
    You can easily install Micronaut using SDKMAN!:

     
    sdk install micronaut

     

    Check the installation by running:

     
    mn --version

     

  4. Gradle or Maven
    The Micronaut CLI automatically sets up your build tool, but you can also install Gradle manually using SDKMAN!:

     
    sdk install gradle

     

  5. Groovy
    Most Micronaut installations come with Groovy support, but you can install it separately:

     
    sdk install groovy

     

  6. IDE or Text Editor
    You can use any IDE that supports Groovy and Gradle — popular choices include:

    • IntelliJ IDEA (with Micronaut and Groovy plugins)

    • VS Code (with Java and Groovy extensions)

    • Eclipse IDE

  7. cURL or Postman
    To test the API endpoints later, install Postman (GUI-based) or use cURL (command-line).

What You’ll Learn

In this tutorial, you’ll learn how to:

  • Create a Micronaut project using the CLI.

  • Define a Groovy model class.

  • Build RESTful endpoints (GET, POST, PUT, DELETE).

  • Run and test your API locally.

Now that everything is ready, let’s create the Micronaut project and set up the initial structure.


Project Setup

In this section, we’ll create a new Micronaut project using the CLI and configure it to use Groovy as the main programming language. Micronaut’s command-line tool simplifies project creation by generating the entire folder structure and essential configuration files for you.

Step 1: Create a New Micronaut Project

Open your terminal, navigate to your preferred projects folder, and run the following command:

mn create-app com.example.groovymnapi --lang groovy

Here’s what each part means:

  • create-app – tells the Micronaut CLI to generate a new application.

  • com.example.groovymnapi – is the base package name (you can change this to your own).

  • --lang groovy – specifies that the source code should be written in Groovy.

Once complete, change into the newly created directory:

cd groovymnapi

Step 2: Project Structure Overview

Your project folder should now look something like this:

groovymnapi/
├── gradle/
├── src/
│   ├── main/
│   │   ├── groovy/
│   │   │   └── com/example/groovymnapi/
│   │   │       └── Application.groovy
│   │   └── resources/
│   │       ├── application.yml
│   │       └── logback.xml
│   └── test/
│       └── groovy/
├── build.gradle
├── gradlew
├── gradlew.bat
└── settings.gradle

Let’s take a quick look at what each part does:

  • Application.groovy — The main entry point of your Micronaut app.

  • application.yml — Configuration file for server port, database settings, etc.

  • build.gradle — Gradle build script that defines dependencies and plugins.

  • logback.xml — Default logging configuration.

  • src/test/groovy — Folder for your Spock or JUnit test files.

Step 3: Open the Project in Your IDE

Now open the project in IntelliJ IDEA, VS Code, or your preferred IDE.
If prompted, let the IDE import the Gradle configuration to automatically download all required dependencies.

Step 4: Verify the Application Runs

To ensure everything works, run the default application using Gradle:

./gradlew run

If you’re using Windows:

gradlew.bat run

Once it starts successfully, you should see something like this in the terminal:

Startup completed in 2004ms. Server Running: http://localhost:8080

This means your Micronaut Groovy application is up and running on port 8080.

You can test the default route by opening your browser and navigating to:

👉 http://localhost:8080

You’ll likely see an empty response or a simple message like:

{"message":"Page Not Found"}

That’s fine — we haven’t added any routes yet.

Now that the project is running successfully, we can start adding our model and controller to handle REST API requests.


Define a Model

Before creating REST endpoints, we need a data model to represent the resources our API will manage. In this tutorial, we’ll build a simple API that handles a collection of books, each with an id, title, and author.

Micronaut uses Java or Groovy classes to define models, and it provides annotations for serialization (converting between objects and JSON).

Step 1: Create the Book Model

Inside the folder src/main/groovy/com/example/, create a new Groovy file named Book.groovy and add the following code:

package com.example

import io.micronaut.serde.annotation.Serdeable

@Serdeable
class Book {
    Long id
    String title
    String author
}

Step 2: Understanding the Code

Let’s break down what’s happening here:

  • @Serdeable
    This annotation tells Micronaut that the class can be serialized and deserialized automatically to and from JSON.
    When the controller returns a Book or a list of Book objects, Micronaut converts them to JSON responses without any additional configuration.

  • Long id, String title, String author
    These are the fields that represent our book data.
    For simplicity, we’re not using a database yet — the data will be stored in memory using a list (which we’ll set up in the controller).

Step 3: Add Sample Data Later

In the next section, we’ll define a controller that:

  • Stores a few sample books in memory,

  • Exposes endpoints for CRUD operations (GET, POST, PUT, DELETE), and

  • Uses this Book model as the data structure for all responses.

With the model in place, we’re ready to move on and start creating RESTful endpoints.


Create a Controller

Now that we have our Book model ready, it’s time to create a controller — the component that will handle HTTP requests and responses. In Micronaut, controllers are annotated classes that map HTTP routes (like /books) to methods that process incoming requests.

In this section, we’ll build a simple CRUD (Create, Read, Update, Delete) REST API for our book data.

Step 1: Create the Controller Class

Inside src/main/groovy/com/example/groovymnapi/, create a new file named BookController.groovy, then add the following code:

package com.example

import io.micronaut.http.annotation.*

@Controller("/books")
class BookController {

    private List<Book> books = [
        new Book(id: 1, title: "Groovy in Action", author: "Dierk König"),
        new Book(id: 2, title: "Learning Micronaut", author: "John Doe")
    ]

    @Get("/")
    List<Book> list() {
        books
    }

    @Get("/{id}")
    Book show(Long id) {
        books.find { it.id == id }
    }

    @Post("/")
    Book add(@Body Book book) {
        book.id = (books*.id.max() ?: 0) + 1
        books << book
        book
    }

    @Put("/{id}")
    Book update(Long id, @Body Book updatedBook) {
        def index = books.findIndexOf { it.id == id }
        if (index != -1) {
            books[index].title = updatedBook.title
            books[index].author = updatedBook.author
            return books[index]
        }
        null
    }

    @Delete("/{id}")
    void delete(Long id) {
        books.removeIf { it.id == id }
    }
}

Step 2: Understanding the Code

Let’s break it down step by step:

  • @Controller("/books")
    This annotation tells Micronaut that this class handles all routes starting with /books.

  • private List<Book> books
    For simplicity, we’re storing the data in memory using a list of Book objects. In a real-world project, this would come from a database.

  • @Get("/")list()
    Returns all books. This corresponds to the HTTP GET /books request.

  • @Get("/{id}")show(id)
    Returns a single book by its id, mapped to GET /books/{id}.

  • @Post("/")add(book)
    Adds a new book to the list. Micronaut automatically converts incoming JSON to a Book object.

  • @Put("/{id}")update(id, updatedBook)
    Updates an existing book’s title and author.

  • @Delete("/{id}")delete(id)
    Deletes a book from the list by its id.

Step 3: Test Your Controller

Run your application again:

./gradlew run

When the server starts, open a new terminal and try the following test requests.

List all books

curl http://localhost:8080/books

Expected output:

[
  {"id":1,"title":"Groovy in Action","author":"Dierk König"},
  {"id":2,"title":"Learning Micronaut","author":"John Doe"}
]

Get a single book

curl http://localhost:8080/books/1

Add a new book

curl -X POST http://localhost:8080/books \
-H "Content-Type: application/json" \
-d '{"title": "Mastering Groovy", "author": "Jane Smith"}'

Update a book

curl -X PUT http://localhost:8080/books/2 \
-H "Content-Type: application/json" \
-d '{"title": "Micronaut for Beginners", "author": "John Doe"}'

Delete a book

curl -X DELETE http://localhost:8080/books/1

Each operation should return a JSON response or an empty result for DELETE.

Step 4: Verify API Output in a Browser or Postman

You can also open http://localhost:8080/books in your browser, or use Postman to make the same requests visually.

At this point, your simple REST API is fully functional!


Test the REST API with Spock

Testing is a crucial part of any backend application. It helps ensure your API behaves as expected, even after you make changes. Since we’re using Groovy, the natural choice for testing is Spock — a powerful and expressive testing framework built specifically for Groovy.

Micronaut integrates nicely with Spock, allowing you to write readable, BDD-style (Behavior-Driven Development) tests for your REST endpoints.

Step 1: Verify Spock is Included in the Dependencies

When you created the Micronaut project with the --lang groovy option, Spock should have been added automatically in your build.gradle file.

Open build.gradle and look for a line like this:

testImplementation("io.micronaut.test:micronaut-test-spock")
testImplementation("org.spockframework:spock-core")

If they’re missing, add them under the dependencies block:

dependencies {
    testImplementation("io.micronaut.test:micronaut-test-spock")
    testImplementation("org.spockframework:spock-core")
}

Then reload your Gradle project (your IDE should do this automatically).

Step 2: Create a Test File

Inside the folder src/test/groovy/com/example/, create a new file named BookControllerSpec.groovy and add the following code:

package com.example

import io.micronaut.http.HttpRequest
import io.micronaut.http.HttpStatus
import io.micronaut.http.client.HttpClient
import io.micronaut.runtime.server.EmbeddedServer
import io.micronaut.test.extensions.spock.annotation.MicronautTest
import jakarta.inject.Inject
import spock.lang.Specification

@MicronautTest
class BookControllerSpec extends Specification {

    @Inject
    EmbeddedServer embeddedServer

    @Inject
    HttpClient httpClient

    def "should list all books"() {
        when:
        def response = httpClient.toBlocking().exchange(HttpRequest.GET("/books"), List)

        then:
        response.status == HttpStatus.OK
        response.body().size() >= 2
    }

    def "should retrieve a book by id"() {
        when:
        def response = httpClient.toBlocking().exchange(HttpRequest.GET("/books/1"), Book)

        then:
        response.status == HttpStatus.OK
        response.body().title == "Groovy in Action"
    }

    def "should add a new book"() {
        given:
        def newBook = new Book(title: "Testing with Spock", author: "Jane Doe")

        when:
        def response = httpClient.toBlocking().exchange(
            HttpRequest.POST("/books", newBook),
            Book
        )

        then:
        response.status == HttpStatus.OK
        response.body().title == "Testing with Spock"
    }

    def "should update a book"() {
        given:
        def updatedBook = new Book(title: "Micronaut Updated", author: "John Doe")

        when:
        def response = httpClient.toBlocking().exchange(
            HttpRequest.PUT("/books/2", updatedBook),
            Book
        )

        then:
        response.status == HttpStatus.OK
        response.body().title == "Micronaut Updated"
    }

    def "should delete a book"() {
        when:
        def response = httpClient.toBlocking().exchange(HttpRequest.DELETE("/books/1"))

        then:
        response.status == HttpStatus.NO_CONTENT || response.status == HttpStatus.OK
    }
}

Step 3: Understanding the Test Code

Let’s go over what’s happening here:

  • @MicronautTest
    This annotation starts an embedded Micronaut server during the test so you can send real HTTP requests to your controllers.

  • EmbeddedServer and HttpClient
    These are injected to help us send requests directly to the running app.

  • Specification
    The base class for all Spock tests. It allows the use of expressive syntax like given, when, then.

  • Each test case verifies a specific API behavior:

    • should list all books → tests the GET /books endpoint.

    • should retrieve a book by id → tests GET /books/{id}.

    • should add a new book → tests POST /books.

    • should update a book → tests PUT /books/{id}.

    • should delete a book → tests DELETE /books/{id}.

Step 4: Run the Tests

Run all tests with Gradle:

./gradlew test

If everything is configured correctly, you should see output like this:

BUILD SUCCESSFUL in 4s
4 actionable tasks: 4 executed

Or in IntelliJ IDEA, you can open the BookControllerSpec.groovy file and click the green run icon beside each test.

Step 5: View Test Reports (Optional)

Gradle automatically generates HTML test reports under:

build/reports/tests/test/index.html

Open this file in your browser to view a summary of all test results.

At This Stage

You’ve now:

  • Created a functional REST API in Groovy with Micronaut.

  • Verified it using Spock tests.

  • Confirmed all endpoints are working correctly.


Conclusion and Next Steps

In this tutorial, you learned how to build a simple REST API in Groovy using Micronaut, one of the fastest and most lightweight JVM frameworks available today.

You started from scratch — setting up a Micronaut project using the CLI, defining a Groovy model, creating a REST controller for CRUD operations, and testing everything with the Spock framework. Along the way, you also saw how Micronaut’s compile-time dependency injection, fast startup time, and low memory usage make it an ideal choice for modern microservices and cloud-based applications.

Let’s summarize what we accomplished:

✅ Created a new Micronaut project with Groovy
✅ Defined a Book model and added serialization support
✅ Built RESTful endpoints for GET, POST, PUT, and DELETE requests
✅ Tested the API with Spock, ensuring all routes work as expected

Next Steps

Now that you have a solid understanding of how Micronaut and Groovy work together, you can take this project further by adding more advanced features:

  1. Connect to a Real Database
    Use Micronaut Data or Hibernate/JPA with PostgreSQL, MySQL, or MongoDB to persist data instead of using an in-memory list.

  2. Add Validation
    Micronaut supports Jakarta Bean Validation annotations like @NotBlank and @Min for validating incoming request data.

  3. Implement Error Handling
    Create custom exception handlers using @Error to return meaningful JSON error responses.

  4. Add Authentication and Authorization
    Secure your API with Micronaut Security and JWT-based authentication for real-world use.

  5. Dockerize the Application
    Package your Micronaut app into a lightweight Docker image and deploy it to the cloud (e.g., AWS, Azure, or GCP).

Final Thoughts

Micronaut with Groovy provides a clean, expressive, and high-performance way to build APIs on the JVM. Its fast startup and low overhead make it a great choice for developers who want to move beyond traditional frameworks while keeping the power and flexibility of Groovy.

You now have all the fundamentals to start building scalable, production-ready REST APIs using Micronaut!

You can get the full source code 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!