
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.
And, as always, the source code for the examples can be found over on GitHub.
The post What Is an API in Java? first appeared on Baeldung.