eBook – Guide Spring Cloud – NPI EA (cat=Spring Cloud)
announcement - icon

Let's get started with a Microservice Architecture with Spring Cloud:

>> Join Pro and download the eBook

eBook – Mockito – NPI EA (tag = Mockito)
announcement - icon

Mocking is an essential part of unit testing, and the Mockito library makes it easy to write clean and intuitive unit tests for your Java code.

Get started with mocking and improve your application tests using our Mockito guide:

Download the eBook

eBook – Java Concurrency – NPI EA (cat=Java Concurrency)
announcement - icon

Handling concurrency in an application can be a tricky process with many potential pitfalls. A solid grasp of the fundamentals will go a long way to help minimize these issues.

Get started with understanding multi-threaded applications with our Java Concurrency guide:

>> Download the eBook

eBook – Reactive – NPI EA (cat=Reactive)
announcement - icon

Spring 5 added support for reactive programming with the Spring WebFlux module, which has been improved upon ever since. Get started with the Reactor project basics and reactive programming in Spring Boot:

>> Join Pro and download the eBook

eBook – Java Streams – NPI EA (cat=Java Streams)
announcement - icon

Since its introduction in Java 8, the Stream API has become a staple of Java development. The basic operations like iterating, filtering, mapping sequences of elements are deceptively simple to use.

But these can also be overused and fall into some common pitfalls.

To get a better understanding on how Streams work and how to combine them with other language features, check out our guide to Java Streams:

>> Join Pro and download the eBook

eBook – Jackson – NPI EA (cat=Jackson)
announcement - icon

Do JSON right with Jackson

Download the E-book

eBook – HTTP Client – NPI EA (cat=Http Client-Side)
announcement - icon

Get the most out of the Apache HTTP Client

Download the E-book

eBook – Maven – NPI EA (cat = Maven)
announcement - icon

Get Started with Apache Maven:

Download the E-book

eBook – Persistence – NPI EA (cat=Persistence)
announcement - icon

Working on getting your persistence layer right with Spring?

Explore the eBook

eBook – RwS – NPI EA (cat=Spring MVC)
announcement - icon

Building a REST API with Spring?

Download the E-book

Course – LS – NPI EA (cat=Jackson)
announcement - icon

Get started with Spring and Spring Boot, through the Learn Spring course:

>> LEARN SPRING
Course – RWSB – NPI EA (cat=REST)
announcement - icon

Explore Spring Boot 3 and Spring 6 in-depth through building a full REST API with the framework:

>> The New “REST With Spring Boot”

Course – LSS – NPI EA (cat=Spring Security)
announcement - icon

Yes, Spring Security can be complex, from the more advanced functionality within the Core to the deep OAuth support in the framework.

I built the security material as two full courses - Core and OAuth, to get practical with these more complex scenarios. We explore when and how to use each feature and code through it on the backing project.

You can explore the course here:

>> Learn Spring Security

Course – LSD – NPI EA (tag=Spring Data JPA)
announcement - icon

Spring Data JPA is a great way to handle the complexity of JPA with the powerful simplicity of Spring Boot.

Get started with Spring Data JPA through the guided reference course:

>> CHECK OUT THE COURSE

Partner – Moderne – NPI EA (cat=Spring Boot)
announcement - icon

Refactor Java code safely — and automatically — with OpenRewrite.

Refactoring big codebases by hand is slow, risky, and easy to put off. That’s where OpenRewrite comes in. The open-source framework for large-scale, automated code transformations helps teams modernize safely and consistently.

Each month, the creators and maintainers of OpenRewrite at Moderne run live, hands-on training sessions — one for newcomers and one for experienced users. You’ll see how recipes work, how to apply them across projects, and how to modernize code with confidence.

Join the next session, bring your questions, and learn how to automate the kind of work that usually eats your sprint time.

Course – LJB – NPI EA (cat = Core Java)
announcement - icon

Code your way through and build up a solid, practical foundation of Java:

>> Learn Java Basics

Partner – LambdaTest – NPI EA (cat= Testing)
announcement - icon

Distributed systems often come with complex challenges such as service-to-service communication, state management, asynchronous messaging, security, and more.

Dapr (Distributed Application Runtime) provides a set of APIs and building blocks to address these challenges, abstracting away infrastructure so we can focus on business logic.

In this tutorial, we'll focus on Dapr's pub/sub API for message brokering. Using its Spring Boot integration, we'll simplify the creation of a loosely coupled, portable, and easily testable pub/sub messaging system:

>> Flexible Pub/Sub Messaging With Spring Boot and Dapr

1. Introduction

API (Application Programming Interface) plays a crucial role in communication between different software systems. Whether we’re integrating third-party services or RESTful web services, an understanding of API development is essential to building modern-day web applications.

In this article, we’ll briefly explore what an API is in the context of Java, understand its significance, and even take a look at an example of it to get started with API development.

2. What Is an API?

Let us understand API with a real-world example. When we go to a restaurant, we just look at the menu and order the food. We don’t need to know how the food is prepared in the kitchen.

In a similar sense, an API in Java is a set of methods and classes that we developers use without worrying about how they work internally.

For example, imagine we want to build a weather forecast application. Instead of manually collecting the data and calculating, we can just use the weather API provided by a third party. The weather API may expose various endpoints (think of them like methods that we can call over the web) to get a variety of data we may require.

APIs are extensively used in modern-day application building. Modern-day applications follow component-based architecture, where the application is split up into multiple small pieces with separate functions, and all these components talk to each other by exposing their API.

3. Types of APIs

In Java, we have different types of APIs based on their purpose, as follows.

3.1. Web API’s

Web APIs help us interact with other web applications over the web. This could mean making an HTTP request to another web application that’s exposing its API or communication between various components within the same application.

For example, the PayPal API allows an e-commerce app to process payments. The YouTube API allows developers to add videos to their apps, etc.

We have different types of web APIs, and RESTful APIs are among the most commonly used. They rely on URLs to identify resources and use standard HTTP methods (GET, POST, PUT, DELETE) to send and receive data.

SOAP API, though older, is more secure and is used in banking and financial systems. GraphQL is yet another type of API that is more flexible and allows clients to request only the specific data they need.

3.2. Operating System APIs

Java offers operating system APIs that help us interact with OS-specific features, such as file handling, network access, etc.

Java NIO (New I/O API), Java Process API, and Java Preferences API are some of the examples that would allow us to perform OS tasks.

3.3. Database API’s

Database APIs allow us to perform CRUD operations by connecting to a database. Some of the examples include JDBC (Java Database Connectivity), JPA (Java Persistence API), and Spring Data JPA.

3.4. Hardware APIs

Java also offers APIs to interact with hardware components like printers, cameras, sensors, etc. Java Sound API and Java Print API are some of the examples.

For this article, we’ll focus on RESTful APIs built using Java.

4. Creating a CRUD API

Let’s now create a REST API that performs CRUD operations. One of the simplest ways to accomplish this is by using HttpServer. HttpServer is lightweight and is great for small projects and learning how REST APIs work.

We’d first create a Maven project, and then we’ll create a class file named RestApiServer in src/main/java where we’ll have the main() method along with code that handles incoming requests and performs CRUD operations.

4.1. Creating HTTP Server

Inside the main() method, we’d create an HTTP server that listens to port 8080 and allows incoming HTTP requests at the /users endpoint. Below is the code that demonstrates that:

public static void main(String[] args) throws IOException {
    HttpServer server = HttpServer.create(new InetSocketAddress(8080), 0);
    server.createContext("/users", new RestApiServer());
    server.setExecutor(null);
    System.out.println("Server started at http://localhost:8080/users");
    server.start();
}

The server.createContext(“/users”, new RestApiServer()) registers a handler for the /users endpoint. I.e., any HTTP request sent to http://localhost:8080/users will be processed by an instance of RestApiServer.

We’re also configuring the server with server.setExecutor(null), which means it’ll use the default thread pool to process the incoming requests. Finally, server.start() starts the server when we run the program.

4.2. Implementing handle() Method

To process incoming requests, the RestApiServer class implements the HttpHandler interface, which comes with the handle() method. We’d need to override the handle() method and provide logic to check the incoming request and call the corresponding handler function.

Below is the implementation of the handle() method:

@Override
public void handle(HttpExchange exchange) throws IOException {
    String method = exchange.getRequestMethod();
    switch (method) {
        case "GET" -> handleGet(exchange);
        case "POST" -> handlePost(exchange);
        case "PUT" -> handlePut(exchange);
        case "DELETE" -> handleDelete(exchange);
        default -> sendResponse(exchange, 405, "Method Not Allowed");
    }
}

4.3. Processing Requests

Next, let’s explore these individual methods and how they handle requests to perform CRUD operations. In order to keep this as simple as possible, we’re not going to use entities and repositories. We’ll just use a List inside the class that maintains a list of users.

If the incoming request is a GET request, we’d call the handleGet() method which would simply return the list of uses. Below is the code for the same:

private void handleGet(HttpExchange exchange) throws IOException {
    sendResponse(exchange, 200, users.toString());
}

Next, let’s take a look at the handlePost() method, which would handle the POST request. This method would create/add a user after checking if the user is not blank.

Below is the code for the same:

private void handlePost(HttpExchange exchange) throws IOException {
    String newUser = readRequestBody(exchange);
    if (!newUser.isBlank()) {
        users.add(newUser);
        sendResponse(exchange, 201, "User added: " + newUser);
    } else {
        sendResponse(exchange, 400, "Invalid user data");
    }
}

Now let’s take a look at the handlePut() method, which would update an existing user at the specified index.

Below is the code for the same:

private void handlePut(HttpExchange exchange) throws IOException {
    String body = readRequestBody(exchange);
    String[] parts = body.split(":", 2);
    if (parts.length == 2) {
        int index = Integer.parseInt(parts[0]);
        String newName = parts[1];
        if (index >= 0 && index < users.size()) {
            users.set(index, newName);
            sendResponse(exchange, 200, "User updated: " + newName);
        } else {
            sendResponse(exchange, 404, "User not found");
        }
    } else {
        sendResponse(exchange, 400, "Invalid input format");
    }
}

It starts by reading the request body using readRequestBody(exchange), which is expected to return a string containing user data in “index:newName” format. If the input format is in two parts, it’ll check whether the provided index exists in the user’s list. It’d add the user and return a 200 OK status with a success message only If it’s valid.

If the index is out of range, it assumes that there is no user in the specified index and returns a 400 Bad Request error.

Next, we’ll also have a similar method to perform the deletion of the user. Below is the code for the same:

private void handleDelete(HttpExchange exchange) throws IOException {
    String body = readRequestBody(exchange);
    int index;
    try {
        index = Integer.parseInt(body);
        if (index >= 0 && index < users.size()) {
            String removedUser = users.remove(index);
            sendResponse(exchange, 200, "User deleted: " + removedUser);
        } else {
            sendResponse(exchange, 404, "User not found");
        }
    } catch (NumberFormatException e) {
        sendResponse(exchange, 400, "Invalid index");
    }
}

First we’re reading the request body to see if it contains a single integer representing the index of the user to be deleted. If the index is valid, it attempts to delete the user from that index and responds with a 200 OK status along with a confirmation message. If the index is out of range or is invalid, it will return a 404 not found error.

We also have a couple of methods to read the request body and send a response in a meaningful way. Below is the code for reading requests:

private String readRequestBody(HttpExchange exchange) throws IOException {
    InputStream is = exchange.getRequestBody();
    return new String(is.readAllBytes(), StandardCharsets.UTF_8);
}

Below is the code that writes to the response:

private void sendResponse(HttpExchange exchange, int statusCode, String response) throws IOException {
    exchange.sendResponseHeaders(statusCode, response.length());
    OutputStream os = exchange.getResponseBody();
    os.write(response.getBytes(StandardCharsets.UTF_8));
    os.close();
}

5. Testing the Application

To run the application and test our API, we don’t need an external server, we can use the embedded HTTP server. Below are the steps to test our API.

We must first package our project using Maven and create a jar file. Open PowerShell in Windows and run the below command in the project directory:

mvn clean package

After that, we need to go to the project directory and run our class file using the below command (assuming our class is in com.example.rest package) and this should launch our server in port 8080:

java -cp .\target\my-crud-app-0.0.1-SNAPSHOT.jar com.example.rest.RestApiServer

Now, inside the PowerShell, we use curl to make API calls.

To get all the users, we need to run the below command:

curl.exe -X GET http://localhost:8080/users

The below command is used to add a new user (Sending POST request):

curl.exe -X POST -d "Alice" http://localhost:8080/users

We use the below command to update an existing user:

curl.exe -X PUT -d "0:Bob" http://localhost:8080/users

Finally, we use the below command to delete an existing user:

curl.exe -X DELETE -d "0" http://localhost:8080/users

6. External Libraries/Frameworks

To build modern applications, we use more advanced frameworks with enhanced features, ease of use, and scalability. These frameworks simplify managing dependencies, support dependency injection, improve security, and facilitate database interactions.

In this section, we’ll explore some of the most popular libraries and frameworks used for API development.

6.1. Spring Boot

Spring Boot revolutionized the way we build Java applications by simplifying the process of building production-ready applications. With features like auto-configuration, Spring Boot eliminates the need for extensive manual configuration.

It also supports dependency injection and comes with an embedded Tomcat server supporting the building of modern-day distributed applications.

Developers can easily create RESTful services using Spring Boot’s annotations like @RestController and @RequestMapping, reducing the need for XML-based configurations.

With Spring Data JPA, we seamlessly integrate with the database, making CRUD operations efficient with minimal effort.

Moreover, Spring Boot’s compatibility with microservices architecture, in combination with tools like Spring Cloud, makes it a preferred choice for building enterprise-grade applications.

6.2. Jakarta EE

Jakarta EE (formerly known as Java EE) is a popular and powerful enterprise framework used to build large-scale, distributed applications. It provides a comprehensive set of APIs such as JAX-RS for RESTful web services, JPA for database operations, and CDI (Contexts and Dependency Injection) for managing dependencies.

Unlike Spring Boot, which comes with an embedded server and other features, Jakarta EE runs on application servers like WildFly, Payara, or Open Liberty.

Jakarta EE allows developers to build scalable and robust applications with built-in support for transaction management, messaging (JMS), and security. It takes a more traditional approach, handling configuration through web.xml or annotations, making it suitable for enterprises that require strict compliance with Java EE standards.

6.3. JAX-RS

JAX-RS (Java API for RESTful Web Services) is a Java standard for building RESTful web services. This was commonly used before Spring Boot gained popularity. It is one of the widely adopted frameworks that uses a set of annotations to make API development simpler and more declarative.

Unlike Spring Boot, which comes with features like dependency injection and security, JAX-RS focuses solely on RESTful API development, which makes it lightweight and efficient.

JAX-RS supports annotations like @GET, @POST, @PUT, @DELETE, and @Path, allowing developers to define endpoints without manual XML-based configurations. It also has features like request filtering, exception handling, and content negotiation, making it an ideal choice for API development. Jersey (by Oracle) and RESTEasy (by JBoss) are some of the popular implementations of JAX-RS.

7. Conclusion

In this article we’ve understood what an API is in the context of Java, understood various types of APIs, and we’ve even implemented an API that takes requests and processes them. While we’ve created the simplest form of REST API using core Java, there are many advanced frameworks that help us build modern-day applications with ease and robust security.

The code backing this article is available on GitHub. Once you're logged in as a Baeldung Pro Member, start learning and coding on the project.

Baeldung Pro – NPI EA (cat = Baeldung)
announcement - icon

Baeldung Pro comes with both absolutely No-Ads as well as finally with Dark Mode, for a clean learning experience:

>> Explore a clean Baeldung

Once the early-adopter seats are all used, the price will go up and stay at $33/year.

eBook – HTTP Client – NPI EA (cat=HTTP Client-Side)
announcement - icon

The Apache HTTP Client is a very robust library, suitable for both simple and advanced use cases when testing HTTP endpoints. Check out our guide covering basic request and response handling, as well as security, cookies, timeouts, and more:

>> Download the eBook

eBook – Java Concurrency – NPI EA (cat=Java Concurrency)
announcement - icon

Handling concurrency in an application can be a tricky process with many potential pitfalls. A solid grasp of the fundamentals will go a long way to help minimize these issues.

Get started with understanding multi-threaded applications with our Java Concurrency guide:

>> Download the eBook

eBook – Java Streams – NPI EA (cat=Java Streams)
announcement - icon

Since its introduction in Java 8, the Stream API has become a staple of Java development. The basic operations like iterating, filtering, mapping sequences of elements are deceptively simple to use.

But these can also be overused and fall into some common pitfalls.

To get a better understanding on how Streams work and how to combine them with other language features, check out our guide to Java Streams:

>> Join Pro and download the eBook

eBook – Persistence – NPI EA (cat=Persistence)
announcement - icon

Working on getting your persistence layer right with Spring?

Explore the eBook

Course – LS – NPI EA (cat=REST)

announcement - icon

Get started with Spring Boot and with core Spring, through the Learn Spring course:

>> CHECK OUT THE COURSE

Partner – Moderne – NPI EA (tag=Refactoring)
announcement - icon

Modern Java teams move fast — but codebases don’t always keep up. Frameworks change, dependencies drift, and tech debt builds until it starts to drag on delivery. OpenRewrite was built to fix that: an open-source refactoring engine that automates repetitive code changes while keeping developer intent intact.

The monthly training series, led by the creators and maintainers of OpenRewrite at Moderne, walks through real-world migrations and modernization patterns. Whether you’re new to recipes or ready to write your own, you’ll learn practical ways to refactor safely and at scale.

If you’ve ever wished refactoring felt as natural — and as fast — as writing code, this is a good place to start.

eBook Jackson – NPI EA – 3 (cat = Jackson)