Micronaut is a powerful framework for building microservices and REST APIs in Java. In this tutorial, we will be Building REST API in Micronaut for a banking application using Micronaut and Java 21. We will cover everything step-by-step so even beginners can follow along.
Project Overview
We will build a small banking API that allows us to:
- Create a bank account
- View account details
- Deposit money
- Withdraw money
Package structure: com.kscodes.banking
Prerequisites
- Java 21 installed
- Micronaut CLI installed (optional but recommended)
- VS Code (or any IDE)
- Maven
Step 1: Create a Micronaut Project
Using Micronaut CLI:
1 2 3 4 |
mn create-app com.kscodes.banking --java-version 21 --build maven |
Or use Micronaut Launch and download the generated project with Maven as the build tool.
Open the project in VS Code.
Step 2: Define the Domain Model
Create a new file Account.java
in:
src/main/java/com/kscodes/banking/model/
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
package com.kscodes.banking.model; import java.math.BigDecimal; import java.util.UUID; public class Account { private UUID accountId; private String accountHolder; private BigDecimal balance; public Account(String accountHolder) { this.accountId = UUID.randomUUID(); this.accountHolder = accountHolder; this.balance = BigDecimal.ZERO; } public UUID getAccountId() { return accountId; } public String getAccountHolder() { return accountHolder; } public BigDecimal getBalance() { return balance; } public void deposit(BigDecimal amount) { balance = balance.add(amount); } public void withdraw(BigDecimal amount) { balance = balance.subtract(amount); } } |
Step 3: Create a Simple Service
Create AccountService.java
in:
src/main/java/com/kscodes/banking/service/
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
package com.kscodes.banking.service; import com.kscodes.banking.model.Account; import jakarta.inject.Singleton; import java.math.BigDecimal; import java.util.*; @Singleton public class AccountService { private final Map<UUID, Account> accounts = new HashMap<>(); public Account createAccount(String accountHolder) { Account account = new Account(accountHolder); accounts.put(account.getAccountId(), account); return account; } public Optional<Account> getAccount(UUID accountId) { return Optional.ofNullable(accounts.get(accountId)); } public Optional<Account> deposit(UUID accountId, BigDecimal amount) { Account account = accounts.get(accountId); if (account != null) { account.deposit(amount); return Optional.of(account); } return Optional.empty(); } public Optional<Account> withdraw(UUID accountId, BigDecimal amount) { Account account = accounts.get(accountId); if (account != null) { account.withdraw(amount); return Optional.of(account); } return Optional.empty(); } } |
Step 4: Create REST Controller
Create AccountController.java
in:
src/main/java/com/kscodes/banking/controller/
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
package com.kscodes.banking.controller; import com.kscodes.banking.model.Account; import com.kscodes.banking.service.AccountService; import io.micronaut.http.HttpResponse; import io.micronaut.http.annotation.*; import jakarta.inject.Inject; import java.math.BigDecimal; import java.util.Optional; import java.util.UUID; @Controller("/accounts") public class AccountController { @Inject AccountService accountService; @Post("/") public Account createAccount(@Body String accountHolder) { return accountService.createAccount(accountHolder); } @Get("/{accountId}") public HttpResponse<Account> getAccount(UUID accountId) { return accountService.getAccount(accountId) .map(HttpResponse::ok) .orElse(HttpResponse.notFound()); } @Post("/{accountId}/deposit") public HttpResponse<Account> deposit(UUID accountId, @Body BigDecimal amount) { return accountService.deposit(accountId, amount) .map(HttpResponse::ok) .orElse(HttpResponse.notFound()); } @Post("/{accountId}/withdraw") public HttpResponse<Account> withdraw(UUID accountId, @Body BigDecimal amount) { return accountService.withdraw(accountId, amount) .map(HttpResponse::ok) .orElse(HttpResponse.notFound()); } } |
Step 5: Run and Test
Build and run the application:
1 2 3 |
mvnw mn:run |

Example API calls:
- Create Account:
1 2 3 |
curl -X POST http://localhost:8080/accounts -d "John Doe" |
- Deposit Money:
1 2 3 |
curl -X POST http://localhost:8080/accounts/{accountId}/deposit -d 500.00 |
- Withdraw Money:
1 2 3 |
curl -X POST http://localhost:8080/accounts/{accountId}/withdraw -d 200.00 |
- Get Account Info:
1 2 3 |
curl http://localhost:8080/accounts/{accountId} |
Step 6: Using Virtual Threads (Java 21 Feature)
In application.yml
, enable virtual threads:
1 2 3 4 5 6 7 |
micronaut: executors: io: type: virtual |
This allows your Micronaut app to scale better with Java 21.
Summary
- We created a simple banking REST API using Micronaut.
- Implemented account creation, deposit, withdrawal, and fetching account info.
- Used Java 21 virtual threads.
- Simple in-memory storage (can be extended with a database).
Stay tuned for future posts where we will add database support, validations, exception handling, and more enterprise-ready features!