What is REST API in Java? Guide with Examples

Explore the basics, learn the specifics, and get hands-on with examples of using REST API in Java.
By
What is REST API in Java? Guide with Examples
  • Blog
  • >
  • What is REST API in Java? Guide with Examples
TOPICS

30 Day Free Trial

Bring together legacy systems, RPA bots, microservices and more with Camunda

Sign Up for Camunda Content

Get the latest on Camunda features, events, top trends, and more.

TRENDING CONTENT

Whether it’s social media platforms, e-commerce websites, or mobile applications, they all rely on efficient communication between different systems to deliver dynamic and interactive experiences. One of the key technologies that powers this communication is the REST API.

REST, which stands for Representational State Transfer, is an architectural style that provides a set of principles for designing networked applications. It has gained immense popularity due to its simplicity, scalability, and ease of integration. Java, being a robust and versatile programming language, offers excellent support for building RESTful APIs.

In this article, we’ll explore the fundamental concepts of REST, dive into the specifics of building RESTful APIs in Java, and provide some examples to solidify our understanding.

So, let’s embark on this journey to unravel the world of REST API in Java and discover its significance in modern web development.

Understanding REST API

When it comes to building web applications, REST plays a crucial role in facilitating communication between different systems over the internet. RESTis a guiding set of principles for designing networked applications. It emphasizes simplicity, scalability, and the use of standard protocols.
At its core, REST treats everything as a resource. A resource can be any piece of information or functionality that can be accessed and manipulated.

These resources are identified by unique URLs (which do not change over time), often referred to as endpoints, and are represented using various media types, such as JSON (JavaScript Object Notation) or XML (eXtensible Markup Language). Notice how we’re talking about “representation” here, which is already part of the name of this architectural style.

RESTful architectures follow a client-server model, where the client initiates requests to the server, and the server responds with the requested data or performs the requested actions. This decoupling of the client and server enables a more flexible and scalable system.

The above diagram shows how the flow works. Some highlights from it:

  1. The “Client app” can be any system, it doesn’t have to be a user-facing UI.
  2. The “Client app” is requesting information about a single user, and the REST API knows where that data is, hence it reads it, but the response doesn’t have the same “shape”
  3. The “shape” of the returned data is just a representation of the original user data, and can take any form (JSON and XML being the most common ones).

But what else is in REST?

While the core principles of REST are focused on simplicity and scalability, several requirements need to be met to make an API truly RESTful. Let’s take a closer look at these requirements:

  • Stateless Communication: One of the fundamental principles of REST is statelessness. In a RESTful API, each request from the client to the server must contain all the information necessary to understand and process that request. The server does not store any client-specific state, ensuring that each request can be processed independently. This simplifies server implementation and improves scalability.
  • Client-Server Separation: REST emphasizes the separation of concerns between the client and the server. The client is responsible for using the data returned by the server, however it needs to, but is the server the only one responsible for any processing that needs to be done with the resource data. This separation allows for independent evolution and scalability of the client and server components.
  • Uniform Interface: RESTful APIs should have a uniform interface, meaning that they follow a consistent set of conventions for interacting with resources. This includes using standard HTTP methods (GET, POST, PUT, DELETE) to perform CRUD (Create, Read, Update, Delete) operations on resources. Additionally, the APIs should use standard HTTP status codes and headers to convey the outcome and metadata of requests and responses.
  • Resource-Based Interaction: Resources are the key building blocks of RESTful APIs. Each resource should have a unique identifier (URL) and should be accessed and manipulated through standard and consistent representations. The API should provide a clear and consistent structure for organizing and navigating resources.
  • Hypermedia as the Engine of Application State (HATEOAS): HATEOAS is an important concept in REST. It means that the API should provide links to related resources within its responses. These links provide discoverability and enable the client to navigate the API’s capabilities dynamically. The client can explore the API by following these hypermedia links, rather than having prior knowledge of all possible endpoints.

By adhering to these requirements, a RESTful API can achieve a high level of flexibility, scalability, and interoperability. It promotes loose coupling between client and server, making it easier to evolve and maintain the system over time.

Should we implement REST APIs in Java?

Spoiler alert: absolutely yes!

While there are many useful types of APIs out there, Java, with its versatility and robustness, provides a solid foundation for building RESTful APIs. It offers a wide range of libraries, frameworks, and tools that simplify the development process and promote best practices.

Java’s extensive ecosystem provides developers with a wealth of resources, such as documentation, community support, and third-party libraries. These resources contribute to the overall productivity and efficiency of building RESTful APIs in Java.

Honestly, no matter what you’re trying to do and what database you’re trying to integrate with, the Java ecosystem will provide you with the drivers you need.

That said, let’s create a simple example of a RESTful API using Spring Boot, which is one of the popular frameworks of choice when it comes to building such systems.

For this article, we’ll create a simple CRUD (Create, Read, Update and Delete) API around a single resource: Users.

So let’s get going.

Implementing a RESTful API using Spring Boot

As I mentioned before, REST suggests the use of HTTP methods for CRUD operations, and while there is no hard-coded mapping, the industry standard is:

HTTP Method CRUD operation
GETRead
POSTCreate
PUTUpdate
DELETEDelete

And for this example, we’re going to end up having a web server that responds to the following URL + HTTP Method combination (A.K.A endpoint):

EndpointAction
GET /usersTo get the list of users
POST /usersTo create a new user
PUT /users/[id]To update the details of a single user
DELETE /users/[id]To delete a single user

Now, to get started, we’ll use the online helper for SpringBoot which will create the skeleton for our project with just a couple of clicks.

For the purposes of this example, here is the configuration I’m going with:

Feel free to change values around, or even versions if you have different preferences. The output of this configuration will be a Zip file with the entire project.

After unzipping it, we’ll import it into Eclipse as an existing Maven project:

And then, to ensure that you have all the required dependencies, edit your `pom.xml` file to look like this:

<?xml version="1.0" encoding="UTF-8"?>
<project
        xmlns="http://maven.apache.org/POM/4.0.0"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <parent>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-parent</artifactId>
                <version>3.1.1</version>
                <relativePath/>
                <!-- lookup parent from repository -->
        </parent>
        <groupId>com.example</groupId>
        <artifactId>fdoglio</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <name>fdoglio</name>
        <description>Demo rest api project</description>
        <properties>
                <java.version>17</java.version>
        </properties>
        <dependencies>
                <dependency>
                        <groupId>org.springframework.boot</groupId>
                        <artifactId>spring-boot-starter</artifactId>
                </dependency>
                <dependency>
                        <groupId>org.springframework</groupId>
                        <artifactId>spring-web</artifactId>
                        <version>6.0.10</version>
                </dependency>
                <dependency>
                        <groupId>org.springframework.boot</groupId>
                        <artifactId>spring-boot-starter-test</artifactId>
                        <scope>test</scope>
                </dependency>
                <dependency>
                        <groupId>org.springframework.boot</groupId>
                        <artifactId>spring-boot-starter-web</artifactId>
                </dependency>
        </dependencies>
        <build>
                <plugins>
                        <plugin>
                                <groupId>org.springframework.boot</groupId>
                                <artifactId>spring-boot-maven-plugin</artifactId>
                        </plugin>
                </plugins>
        </build>
</project>

For our API, we’ll need to create three classes:

  • User.java which will contain the actual resource our API will be dealing with. This class will be very simple containing only three properties: ID, name and email.
  • UserRepository.java which will act as a fake data-storage layer for our example. And I mean “fake” because here we’ll normally add the code to access our database and actually store our users. Instead, we’ll keep all data in memory.
  • UserController.java which will act as the main entry point for our API. Here we’ll use annotations to map class methods to endpoints (more of this in a minute).

For the sake of simplicity, let’s skip the User class, you’ll have more than enough information to build it once you see how we use it.

Building our data layer

Now, our “data layer” will be built around an `ArrayList`, which is where we’ll be storing our users. To simplify our tests, we’ll also create three users as part of the initialization process. So in the end, our code will look like this:

package com.example.fdoglio;
import java.util.ArrayList;
import java.util.List;
import org.springframework.stereotype.Repository;
@Repository
public class UserRepository {
        private final List<User> users;
        UserRepository() {
                this.users = new ArrayList<>();
                users.add(new User(1, "John Doe", "[email protected]"));
            users.add(new User(2, "Jane Smith", "[email protected]"));
users.add(new User(3, "Bob Johnson", "[email protected]"));
        }
public List<User> findAll() {
return users;
}
public boolean add(User user) {
        users.add(user);
        return true;
}
public boolean deleteUser(Long id) {
         for (int i = 0; i < users.size(); i++) {
User user = users.get(i);
if (user.getID() == id) {
users.remove(i);
return true;
}
}        
         return false;
}
public User updateUser(Long id, User updatedUser) {
         for (int i = 0; i < users.size(); i++) {
User user = users.get(i);
if (user.getID() == id) {
users.set(i, updatedUser);
return updatedUser;
}
}        
                 return null;
        }
}

In the end, this class is pretty standard, the only relevant highlight is the `@Repository` annotation which tells SpringBoot that this is the class in charge of data storage. That said, this annotation would be more useful if we were fully integrating JPA and a real database.

Let’s now create our API.

Building our REST controller

As I already mentioned, our controller class will be the entry point for our application. This means our server will be started and our methods will be automatically mapped to the endpoints we defined above.

Let’s see what that looks like in code:

package com.example.fdoglio;
import java.awt.PageAttributes.MediaType;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.; import org.springframework.web.bind.annotation.;
@RestController
@RequestMapping(produces = "application/json")
public class UserController {
        private final UserRepository userRepository;
        UserController(UserRepository userRepo) {
                this.userRepository = userRepo;
        }
        @GetMapping(value = "/users")
        public List getUsers() {
                List users = userRepository.findAll();
                return users;
        }
        @PostMapping(value = "/users")
        public ResponseEntity newUser(@RequestBody User user) {
                this.userRepository.add(user);
                return new ResponseEntity(user, HttpStatus.CREATED);
        }
        @PutMapping(value = "/users/{id}")
        public ResponseEntity updateUser(@PathVariable Long id, @RequestBody User user) {
                User retUser = this.userRepository.updateUser(id, user);
                if(retUser != null) {
                        return new ResponseEntity(user, HttpStatus.ACCEPTED);                        
                }
                return new ResponseEntity<>(null, HttpStatus.NOT_FOUND);
        }
        @DeleteMapping(value = "/users/{id}")
        public ResponseEntity deleteUser(@PathVariable Long id) {
                boolean result = this.userRepository.deleteUser(id);
                if(result) {
                        return ResponseEntity.noContent().build();
                } else {
                        return new ResponseEntity<>(null, HttpStatus.NOT_FOUND);
                }
        }
}

Our controller class, without the annotations, is quite simple, every method uses the userRepository to perform their respective action, and they return a ResponseEntity as a result. As part of the return values, you can also appreciate the use of the HttpStatus enum, which shows how we’re using the standard HTTP Status codes mentioned as part of the REST explanation at the start of this guide.

Finally, once we add the annotations, things start to take shape:

  • The @RestController annotation speaks for itself, but it tells the framework that this controller will be used by the server.
  • The @RequestMapping annotation here is used to specify the content type of the responses from all methods. We could, if we wanted, also specify this information on each method, but since we’re going to be replying with JSONs on every method, it makes more sense to define it at class level.
  • The @GetMapping, @PostMapping, @PutMapping and @DeleteMapping annotations clearly map the method they annotate to the HTTP Method they reference. As part of the annotation, you also specify the URI, so you have control over what the endpoints look like. Keep in mind that as part of REST, your URIs should reference resources, so in this example, they all take the shape of “/users” or “/users/123”, which either references the list of users, or a single one. Other URLs, such as “/users/edit”, or “/users/delete” would not be correct, because they would reference actions instead of resources.
  • Another interesting detail about route mapping with SpringBoot, is that URL parameters, such as the ID of the user are easily mapped to method parameters. So if we send a DELETE request to /users/123 we’ll be receiving the value 123 on the id parameter of the deleteUser method

Configuring and running our server

The last step before we can hit the “run” button on our IDE, is to configure the server. In our case, given how SpringBoot does pretty much everything for us, all we need to take care of is configuring the port for our web server.

So open up the application.properties file and add the following line:

<span style="font-size: 10pt;font-family: 'Courier New'">`server.port=</span><span style="font-size: 10pt;font-family: 'Courier New';color: #2a00ff">8082`</span>

That’s it, really, that’s all you need.

Now click on the “run” button and you should see something like this:

That means everything is working fine and you can start testing it. For that you can use CLI tools such as cURL, or you can also download Postman and send requests using it.

So, should we be using Java to build RESTful APIs?

In the end, that’s the question, isn’t it? Should we use Java for this? And the answer by now should be obvious: YES!

While the language itself could be labeled as verbose or slow to write by some, frameworks like SpringBoot make it trivially simple to build RESTful APIs in Java.

It’s all a matter of properly annotating your code and adding the few lines of code required to connect each one of your components together.

So go on, download Eclipse and Postman (if you haven’t already), and start toying around with SpringBoot, you’ll have your server running in no time.

Using REST with Camunda

Wondering how you can use Camunda, the leading process orchestration solution, to make REST calls and start a process? Check out this blog post to learn more about how you can use REST in your process automation, and if you’re new to Camunda, feel free to dive right in with a free trial.

Start the discussion at forum.camunda.io

Try All Features of Camunda

Related Content

Learn how to get started with automated underwriting, what the benefits are and why automation in underwriting is important.
An integral part of process orchestration is process automation—get those repeatable, well-understood tasks that don't require complex decision-making on autopilot!
Enhance your business's operational efficiency with business process management, and streamline your workflows to reduce cost and minimize risk.