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
-
JDK 17 or later
Micronaut requires Java 17 or newer. You can check if it’s installed by running:java -versionIf not installed, download it from the Adoptium website or use SDKMAN!.
-
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" -
Micronaut CLI
You can easily install Micronaut using SDKMAN!:sdk install micronautCheck the installation by running:
mn --version -
Gradle or Maven
The Micronaut CLI automatically sets up your build tool, but you can also install Gradle manually using SDKMAN!:sdk install gradle -
Groovy
Most Micronaut installations come with Groovy support, but you can install it separately:sdk install groovy -
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
-
-
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:
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 aBookor a list ofBookobjects, 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
Bookmodel 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 ofBookobjects. In a real-world project, this would come from a database. -
@Get("/")→list()
Returns all books. This corresponds to the HTTPGET /booksrequest. -
@Get("/{id}")→show(id)
Returns a single book by itsid, mapped toGET /books/{id}. -
@Post("/")→add(book)
Adds a new book to the list. Micronaut automatically converts incoming JSON to aBookobject. -
@Put("/{id}")→update(id, updatedBook)
Updates an existing book’s title and author. -
@Delete("/{id}")→delete(id)
Deletes a book from the list by itsid.
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. -
EmbeddedServerandHttpClient
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 likegiven,when,then. -
Each test case verifies a specific API behavior:
-
should list all books→ tests theGET /booksendpoint. -
should retrieve a book by id→ testsGET /books/{id}. -
should add a new book→ testsPOST /books. -
should update a book→ testsPUT /books/{id}. -
should delete a book→ testsDELETE /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:
-
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. -
Add Validation
Micronaut supports Jakarta Bean Validation annotations like@NotBlankand@Minfor validating incoming request data. -
Implement Error Handling
Create custom exception handlers using@Errorto return meaningful JSON error responses. -
Add Authentication and Authorization
Secure your API with Micronaut Security and JWT-based authentication for real-world use. -
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:
- The Complete Apache Groovy Developer Course
- Groovy Fundamentals For Testers - Step By Step
- Groovy Programming Fundamentals for Java Developers
- The Complete Jenkins DevOps CI/CD Pipeline Bootcamp
- WebServices/API Testing by SoapUI & ReadyAPI - Groovy |30+hr
- Mastering Grails. A Comprehensive Grails Course.
- Intro to web programming with Groovy on Grails
Thanks!
