Web Service Tutorial: Streaming Data with Spring Boot RESTful

Web Service Tutorial: Streaming Data with Spring Boot RESTful

In this article, we are going to look at an example to download files using StreamingResponseBody. In this approach, data is processed and written in chunks to the OutputStream.

In this article, we are going to look at an example to download files using StreamingResponseBody. In this approach, data is processed and written in chunks to the OutputStream.

Streaming data is a radical new approach to sending data to web browsers which provides for dramatically faster page load times. Quite often, we need to allow users to download files in web applications. When the data is too large, it becomes quite a challenge to provide a good user experience.

Spring offers support for asynchronous request processing via StreamingResponseBody. In this approach, an application can write data directly to the response OutputStream without holding up the Servlet container thread. There are a few other methods in Spring to handle asynchronous request processing.

Setting Up Spring Boot Project

Create a sample Spring Boot application. Here is my sample project structure. I have created the project manually, but you could also create using Spring Intializer.

Project structure

Let us add some basic dependencies to Maven POM.

<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.techshard.streamingresponse</groupId>
    <artifactId>springboot-download</artifactId>
    <version>1.0-SNAPSHOT</version>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.4.RELEASE</version>
        <relativePath />
    </parent>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-io</artifactId>
            <version>1.3.2</version>
        </dependency>
    </dependencies>
</project>

We will now create a controller and add an API endpoint for download. Here is my complete controller.

package com.techshard.download.controller;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
@RestController
@RequestMapping ("/api")
public class DownloadController {
    private final Logger logger = LoggerFactory.getLogger(DownloadController.class);
    @GetMapping (value = "/download", produces = MediaType.APPLICATION_JSON_VALUE)
    public ResponseEntity<StreamingResponseBody> download(final HttpServletResponse response) {
        response.setContentType("application/zip");
        response.setHeader(
                "Content-Disposition",
                "attachment;filename=sample.zip");
        StreamingResponseBody stream = out -> {
            final String home = System.getProperty("user.home");
            final File directory = new File(home + File.separator + "Documents" + File.separator + "sample");
            final ZipOutputStream zipOut = new ZipOutputStream(response.getOutputStream());
            if(directory.exists() && directory.isDirectory()) {
                try {
                    for (final File file : directory.listFiles()) {
                        final InputStream inputStream=new FileInputStream(file);
                        final ZipEntry zipEntry=new ZipEntry(file.getName());
                        zipOut.putNextEntry(zipEntry);
                        byte[] bytes=new byte[1024];
                        int length;
                        while ((length=inputStream.read(bytes)) >= 0) {
                            zipOut.write(bytes, 0, length);
                        }
                        inputStream.close();
                    }
                    zipOut.close();
                } catch (final IOException e) {
                    logger.error("Exception while reading and streaming data {} ", e);
                }
            }
        };
        logger.info("steaming response {} ", stream);
        return new ResponseEntity(stream, HttpStatus.OK);
    }
}

In this API endpoint, we are reading multiple files from a directory and creating a zip file. We are executing this process within StreamingResponseBody*. It writes data directly to an OutputStream before passing that written information back to the client using aResponseEntity. *This means that the download process will start immediately on the client, while the server is processing and writing data in chunks.

Start the server and test this endpoint using http://localhost:8080/api/download.

When using StreamingResponseBody, it is highly recommended to configure TaskExecutor used in Spring MVC for executing asynchronous requests. TaskExecutor is an interface that abstracts the execution of a Runnable.

Let us configure the TaskExecutor. Here is the AsyncConfiguration class which configures timeout using WebMvcCofigurer and also registers an interceptor that is called when there's a timeout in case you need some special handling.

package com.techshard.download;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.aop.interceptor.SimpleAsyncUncaughtExceptionHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.task.AsyncTaskExecutor;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.context.request.async.CallableProcessingInterceptor;
import org.springframework.web.context.request.async.TimeoutCallableProcessingInterceptor;
import org.springframework.web.servlet.config.annotation.AsyncSupportConfigurer;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import java.util.concurrent.Callable;
@Configuration
@EnableAsync
@EnableScheduling
public class AsyncConfiguration implements AsyncConfigurer {
    private final Logger log = LoggerFactory.getLogger(AsyncConfiguration.class);
    @Override
    @Bean (name = "taskExecutor")
    public AsyncTaskExecutor getAsyncExecutor() {
        log.debug("Creating Async Task Executor");
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(5);
        executor.setMaxPoolSize(10);
        executor.setQueueCapacity(25);
        return executor;
    }
    @Override
    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
        return new SimpleAsyncUncaughtExceptionHandler();
    }
    /** Configure async support for Spring MVC. */
    @Bean
    public WebMvcConfigurer webMvcConfigurerConfigurer(AsyncTaskExecutor taskExecutor, CallableProcessingInterceptor callableProcessingInterceptor) {
        return new WebMvcConfigurer() {
            @Override
            public void configureAsyncSupport(AsyncSupportConfigurer configurer) {
                configurer.setDefaultTimeout(360000).setTaskExecutor(taskExecutor);
                configurer.registerCallableInterceptors(callableProcessingInterceptor);
                WebMvcConfigurer.super.configureAsyncSupport(configurer);
            }
        };
    }
    @Bean
    public CallableProcessingInterceptor callableProcessingInterceptor() {
        return new TimeoutCallableProcessingInterceptor() {
            @Override
            public <T> Object handleTimeout(NativeWebRequest request, Callable<T> task) throws Exception {
                log.error("timeout!");
                return super.handleTimeout(request, task);
            }
        };
    }
}

Conclusion

Using StreamingResponseBody, we can now stream data easily for highly-concurrent applications. I hope you enjoyed this article. Let me know if you have any comments or suggestion in the comments section below.

The example for this article can be found on GitHub repository.

Creating a REST Web Service With Java and Spring

Creating a REST Web Service With Java and Spring

In this article, you'll learn how to create a REST Web Service With Java and Spring

Originally published by Justin Albano at https://dzone.com

In the modern world of interconnected software, web applications have become an indispensable asset. Foremost among these web applications is the Representational State Transfer (REST) web service, with Java becoming one of the most popular implementation languages. Within the Java REST ecosystem, there are two popular contenders: Java Enterprise Edition (JavaEE) and Spring. While both have their strengths and weaknesses, this article will focus on Spring and create a simple order management RESTful web application using Spring 4. Although this management system will be simple compared to the large-scale RESTful services found today, it will nonetheless demonstrate the basic thought process, design decisions, and implementation tests required to create a Level 3 (hypermedia-driven) Spring REST web service.

By the end of this article, we will have created a fully functional Spring REST order management system. While the source code illustrated in this article covers the essential aspects of the order management system, there are other components and code (such as test cases) that support the main service that are not shown. All of the source code, including these supporting aspects, can be found in the following GitHub repository:

The source code snippets in this article are not in-and-of-themselves sufficient for creating a fully functioning REST web service. Instead, they serve as a snapshot or reflection of the source code contained in the above repository. Therefore, as we walk through each step in creating our REST service, the source code in the above repository should be visited consistently and used as the authoritative reference for all design and implementation choices. For the remainder of this article, when we refer to our order management system, we are actually referring to the Spring REST service contained in the above repository.

Prerequisite Knowledge

It is expected that the reader has at least a novice understanding of dependency injection (DI), particularly DI using the Spring framework. Although we will explore the DI framework configurations used and the DI components utilized in our order management system, it is assumed that the reader has at least a conceptual understanding of the need for and premise of DI. For more information on DI in Spring, see the Spring Framework Guide

This article also assumes that the reader has a foundational understanding of REST and RESTful web services. While we will deep dive into the design and implementation intricacies of creating a REST web service in Spring, we will not focus on the conceptual aspects of REST (such as the use of an HTTP GET or POST call).

Development Cycle and Tools

Our order management system was created using Test Driven Development (TDD), where tests were created first and each design decision and implemented component was focused on passing the created test cases. This not only resulted in a simple set of classes, but a more easily distinguishable set of components. For example, persistence logic and domain logic are not intertwined. Apart from the process used to create the service, there are also numerous tools used to build, test, and deploy the system, including:

  • Spring Model-View-Controller (MVC): the core framework of our web service; this framework provides the necessary annotations and structure required to create our REST endpoints and serve these endpoints over HTTP.
  • Spring Boot: a convention-over-configuration framework that removes a majority of the boilerplate Spring code and configuration; this framework allows us to develop and launch of web service with a fraction of the hassle of a standard Spring web service.
  • Apache Maven: a build and dependency management tool that is used to build, execute tests, and package our web service into a Java Archive (JAR) file that will be executed to run our RESTful web service.
  • JUnit: an automated unit testing framework that will be used for unit and integration tests, as well as to automate the execution of our acceptance tests.
  • Cucumber: an automated acceptance testing framework that allows us to create text-based acceptance criteria and exercise our web service to ensure that all top-level functionality is correct during the development of the service.
  • Java 8: at the time of writing, the latest version of Java; we will utilize the streams API to reduce the code needed to filter through the domain objects in our system.
  • GitHub: a free hosting service for Git-based projects; our web service will be hosted here and the commit history for the web service can be viewed here.
  • Travis Continuous Integration (CI): a free continuous integration platform that executes the automated tests in order of web service each time a commit is pushed to our GitHub repository; the build and test history of our web service can be viewed here.

Although we are using a wide array of frameworks and tools, each has a very important task when building our web service. Before we jump into the implementation, though, we first need to devise a design for our order management system.

Designing the Web Service

The first step to designing our web service is deciding on what we want the service to accomplish. Since we are required to process orders, the definition of an order (i.e. creating a domain model) is a good place to start. Each order that we process should have an identifier (ID) so that we can uniquely point to it, a description that describes the order in a human-readable form, a cost, and a completion status.

Note that the cost is not a trivial issue to deal with in software: It is very easy to lose track of cents and make simple rounding errors. In order to avoid these subliminal issues, we will simply store the cost for our order in cents. This allows us to remove the decimal place and perform simple arithmetic without worrying that we will lose a penny in the mix.

Using this simple definition of an order, we devise the following domain model:

With our order designed, we can move onto designing how we will expose our orders through our RESTful web service. Using the standard HTTP verbs, we can quickly come up with a set of REST endpoints that cover the usual Create, Read, Update, and Delete (CRUD) operations:

It is important to note that we should not simply enumerate the REST endpoints we intended to create, but also include the expected behavior if the endpoint successfully completes the request or if it fails to do so. For example, if a client requests to update a non-existent order, we should return a 404 error to inform the client that this resource does not exist. If we successfully update the resource, we should return a 200 status to inform the client that its request was successfully completed.

At this point, it is also useful to think about what the response bodies for the various REST endpoints will look like. Due to its simplicity, we will consume Javascript Object Notation (JSON) objects in the request bodies we receive and produce JSON objects in the response bodies we send, respectively. For example, if we follow our domain model, the response body for getting an order with a specified ID would resemble:

{
    "id": 1,
    "description": "Some sample order",
    "costInCents": 250,
    "complete": false
}

We will see later in this article that other attributes, such as hypermedia links, will also be included. Irrespective of hypermedia link, thinking about the expected request and response bodies for our REST endpoints allows us to devise test cases in advance that ensure we are handling and producing the expected results when we implement our REST endpoints.

With our domain model and REST endpoints defined, we can move to the last piece of the puzzle: How to store our orders. For example, when we create a new order, we need some means of storing that order so that a client, at some future time, can retrieve the created order.

In a true REST web service, we would decide on the best database or persistence framework that supports our domain model and design a persistence layer interface to use to interact with this database. For example, we could select a Neo4j database if our data was well-suited for a graph domain model, or MongoDB if our domain model fits nicely into collections. In the case of our system, for simplicity, we will use an in-memory persistence layer. Although there are various useful in-memory databases, our model is simple enough to create the in-memory database ourselves. In doing so, we will see the basic functionality of a database attached to a REST service, as well as understand the simple interfaces that are common among repositories in RESTful services.

Abstracting Our Design

At this point in our design, we have three discrete sections of our system: (1) a domain model, (2) a series of REST endpoints, and (3) a means of storing our domain objects, or a persistence layer. This set of three sections is so common, it has its own name: A 3-Tier application. Whatsmore, Martin Fowler has written an entire book, Patterns of Enterprise Architecture, on the patterns that surround this application architecture. The three tiers in this architecture are (1) presentation, (2) domain, and (3) data source (used interchangeably with persistence layer). In our case, our REST endpoints map to the presentation layer, our order domain model maps to the domain layer, and our in-memory database maps to the data source layer.

Although these three layers are usually depicted with one stacked on top of the other, with the presentation layer at the top, closest to the user, the domain layer in the middle, and the data source layer on the bottom, it can be more helpful to look at this architecture in terms of its interactions, as illustrated in the following diagram.

There is an important addition that is made to our architecture: Domain objects are not sent directly to the user. Instead, they are wrapped in resources and the resources are provided to the user. This provides a level of indirection between the domain object and how we present the domain object to the user. For example, if we wish to present the user with a different name for a field in our domain model (say orderName instead of simply name), we can do so using a resource. Although this level of indirection is very useful in decoupling our presentation from the domain model, it does allow duplication to sneak in. In most cases, the resource will resemble the interface of the domain object, with a few minor additions. This issue is addressed later when we implement our presentation layer.

The resource object also provides an apt place for us to introduce our hypermedia links. According to the Richardson model for REST web services, hypermedia-driven services are the highest capability level of a REST application and provide important information associated with the resource data. For example, we can provide links for deleting or updating the resource, which removes the need for the client consuming our REST web service to know the REST endpoints for these actions. In practice, the returned resource (deserialized to JSON) may resemble the following:

{
    "id": 1,
    "description": "Some sample order",
    "costInCents": 250,
    "complete": false
    "_links": {
        "self": {
            "href": "http://localhost:8080/order/1"
        },
        "update": {
            "href": "http://localhost:8080/order/1"
        },
        "delete": {
            "href": "http://localhost:8080/order/1"
        }
    }
}

Given these links, the consumer is no longer required to build the URLs for the update, delete, or self-reference REST endpoints. Instead, it can simply use the links provided in our hypermedia-driven response. Not only does this reduces the logic necessary for interacting with our REST web service (no longer do the URLs need to be built), but it also encapsulates the logic for the construction of the URLs. For example, suppose we change our REST service to require a query parameter, such as sorting: if we provide the links to the consumer, we can adjust for that change, without making any changes to the consumer:

{
    "id": 1,
    "description": "Some sample order",
    "costInCents": 250,
    "complete": false
    "_links": {
        "self": {
            "href": "http://localhost:8080/order/1?sorting=default"
        },
        "update": {
            "href": "http://localhost:8080/order/1?sorting=default"
        },
        "delete": {
            "href": "http://localhost:8080/order/1?sorting=default"
        }
    }
}

Although generating these links could be tedious and subject to a large number of bugs (i.e. what if the IP address of the machine hosting the web service changes?), the Spring Hypermedia as the Engine of Application State (HATEOAS, commonly pronounced hay-tee-os) framework provides numerous classes and builders that allow us to create these links with ease. This topic will be explored further when we delve into the implementation of our presentation layer.

Before moving to the implementation of our web service, we must pull our design together and devise a plan of action to create it. At the moment, we have a single domain object, Order, instances of whom will be persisted in an in-memory database and served up (within a resource) to clients using our REST endpoints. This design leaves us with four main steps:

  • Implement the domain model
  • Create the Order domain class
  • Implement the data source layer
  • Create an in-memory database
  • Implement the CRUD operations for the Order domain class
  • Implement the presentation layer
  • Create the REST endpoints
  • Create the Order resource
  • Create assembler to construct an Order resource with proper HATEOAS links
  • Pull the application together
  • Create the main method that will run the application
Implementing the Web Service

Finding where to start can be difficult, but we will take a systematic approach to creating our web service. Start with the layer that depends on the fewest other layers and is depended on by the greatest number of layers. Thus, we will first implement the domain layer, which does not depend on the other two layers but is depended on by both. Then we will implement the data source layer, which depends on the domain layer and is likewise depended on by the presentation layer. Lastly, we will implement the presentation layer, which is not depended on by any other layer but depends on both the data source and domain layers.

Implementing the Domain Layer

The first step in creating our RESTful web service is creating the domain layer. While our domain layer is very simple, we will soon see that it requires some very specific details to be accounted for in order to be properly used by the rest of our system. The first of these details is identity.

All domain objects that will be persisted must have some unique means of identity; the simplest among these is a unique ID. While there are many data structures that can be used as IDs, such as Universally Unique IDs (UUIDs), we will keep it as simple from the start and use a numeric value. Each class in our domain layer must, therefore, have a means of obtaining the ID associated with the object. In addition, to allow our persistence layer to set the ID of a newly created domain object, we must have a means of setting the ID for an object as well. Since we do not want the persistence layer to depend on any concrete class in our domain layer for this functionality, we will create an interface to accomplish this task:

public interface Identifiable extends org.springframework.hateoas.Identifiable<Long> {
    public void setId(Long id);
}

While we could have simply created an interface with a getter and a setter for ID, we instead extend the Identifiable interface provided by the Spring HATEOAS framework. This interface provides a getId() method and extending this interface allows us to use our domain class within the Spring HATEOAS framework, which will come in handy when we implement the presentation layer. With our identity interface complete, we can now create our Orderclass:

public class Order implements Identifiable {
    private Long id;
    private String description;
    private long costInCents;
    private boolean isComplete;
    @Override
    public Long getId() {
        return id;
    }
    @Override
    public void setId(Long id) {
        this.id = id;
    }
    public String getDescription() {
        return description;
    }
    public void setDescription(String description) {
        this.description = description;
    }
    public void setCostInCents(long cost) {
        costInCents = cost;
    }
    public long getCostInCents() {
        return costInCents;
    }
    public void setComplete(boolean isComplete) {
        this.isComplete = isComplete;
    }
    public void markComplete() {
        setComplete(true);
    }
    public void markIncomplete() {
        setComplete(false);
    }
    public boolean isComplete() {
        return isComplete;
    }
}

Our Order class is strikingly simple, but that is the beauty of separating domain classes from the remainder of the system: we can create Plain Old Java Objects (POJOs) that are independent of the rest of the intricacies and idiosyncrasies of our web service (such as how the POJO is persisted and how it is presented through a RESTful interface). Due to the simplicity of this class (it is only composed of getters and setters), we have forgone unit tests.

Although automated unit tests are important, they should be used with discretion. If our Order class contained complicated business logic, such as "an order can only be created between 8am and 5pm EST," we would be wise to implement this logic by first creating a test that exercises this functionality and implement our Orderclass to pass this test. As more functionality is added, we can create more tests and implement this functionality to pass these tests as well (the core of TDD). This leaves us with a general rule about unit testing, especially for domain objects:

Unit tests can be forgone for simple methods, such as getters and setters, but should be used in conjunction with TDD for more complex methods, such as those containing business logic.  

It is also important to note that we have created three methods for setting the completion status of our order: (1) setComplete, (2) markComplete, and (3) markIncomplete. Although it is usually not good practice to set the value of a boolean flag using a setter that takes a boolean argument, we have added this method to our Order class because it allows for simplified updated logic. For example, if we did not have this method, we would have to update the completion status of an order in a manner akin to:

public void updateOrder(Order original, Order updated) {
    // Update the other fields of the order
    if (updated.isComplete()) {
        original.markComplete();
    }
    else {
        original.makeIncomplete();
    }
}

By providing a setter with a boolean argument, we can reduce this update logic to:

public void updateOrder(Order original, Order updated) {
    // Update the other fields of the order
    original.setComplete(updated.isComplete());
}

We have also provided the remaining two setter methods for the completion state to allow for clients to set the completion status in the recommended manner (without passing a boolean flag to a setter method).

In general, we want to externalize the update logic of our domain objects. Instead of creating anupdate(Order updated) method within our Orderclass, we leave it up to external clients to perform the update. The reasoning behind this is that our Order class does not have enough knowledge of the update process needed by external clients to internalize this logic. For example, when we update an Order in the persistence layer, do we update the ID of our order or leave the original ID? That is a decision that should be made in the persistence layer, and therefore, we leave it up to the persistence layer to implement the update logic for our Order class.

Implementing the Data Source Layer

The first step to developing our data source layer is to define the requirements that this layer must fulfill. At its most basic level, our data source must be able to perform the following fundamental operations:

  • Retrieve a list of all orders.
  • Retrieve a specific order based on its ID.
  • Create a new order.
  • Delete an existing order.
  • Update an existing order.

These five operations are common among a vast majority of data sources, and unsurprisingly, follows the basic set of CRUD operations. In this particular case, we create a specialization of the read operation (the R in CRUD) by allowing a caller to supply an ID and retrieve only the order that corresponds to that ID (if such an order exists).

This specialization is particularly useful when dealing with databases, where reads and writes are relatively expensive operations. If we were only capable of retrieving all order and then filtering by ID to find the order of interest, we would wastefully perform a read on each and every order in the database. In a large system with possibly thousands or even millions of entries, this strategy is completely untenable. Instead, we provide methods to target our searches for orders, which in turn allows our data source to optimize the logic used to retrieve entries from its database.

Although we will use an in-memory database in our system, we will include this specialized retrieval method in order to maintain a consistent interface with clients. Although we internally know that the data source is an in-memory database, any clients should not have to change depending on our internal data source implementation.

Since we will be using an in-memory persistence scheme, we cannot rely on a database to provide a new ID for each domain class that we persist. Instead, we will need to create an ID generator that will provide us with unique IDs for each of the Orders we will persist. Our implementation of this generator is as follows:

@Component
@Scope(BeanDefinition.SCOPE_PROTOTYPE)
public class IdGenerator {
    private AtomicLong nextId = new AtomicLong(1);
    public long getNextId() {
        return nextId.getAndIncrement();
    }
}

Although our ID generator is very simple, there are some important aspects that require special attention. First, we have marked our generator as a Spring component using the @Component annotation. This annotation allows our Spring boot application to recognize (through component scanning) our generator class as an injectable component. This will allow us to use the@Autowired annotation in other classes and have our component injected without having to create the generator using the new operator. For more information on Spring DI and autowiring, see the Spring Reference Document for Inversion of Control (IoC) Container.

We have also denoted that the scope of the generator (using the @Scope annotation) is PROTOTYPE, which ensures that a new object is created each time is it autowired. By default, when Spring injects an autowired dependency, it treats each component as a singleton, injecting the same object into each autowired location (within the same context). Using this default logic would result in each caller receiving the same generator, which would result in inconsistent ID generation.

For example, suppose we inject an ID generator into two data sources. If the same generator is used, if source one gets an ID, the resulting ID will be 1. If source two then requests an ID, the resulting ID will then be 2. This is contrary to our desired scheme, where each data source starts with an ID of 1 and increments only when a new object is created within that data source (the IDs can be differentiated based on the type of the object, i.e. "this is order 1" and "this is user 1"). Thus, the first object created in data source one should have an ID of 1, while the first object created in data source two should have an ID of 1 as well. This can only be accomplished if we have different ID generator objects, hence the prototype scoping of our ID generator class.

A second point is the use of AtomicLong to store our next ID. It may be tempting to use a simple long to store the next ID, but this could lead to a very nuanced situation: What if two different calls are made to generate an ID? Since we are working within the realm of a concurrent web application, if we forgo any type of synchronization logic, we would run into a classic race condition, where two identical IDs may be produced. In order to eliminate these difficult-to-debug issues, we use the built-in concurrency mechanisms provided by Java. This ensures that even if two callers request IDs at the same time, each will be unique and the consistency of the next ID will be maintained.

With our ID generator in place, we are now ready to implement our data source. Since much of the in-memory logic is common for all types of objects, we will create an Abstract Base Class (ABC) that contains the core logic for managing our persisted objects (note that Spring uses the nomenclature Repository to mean a data source, and hence we follow the same convention):

public abstract class InMemoryRepository<T extends Identifiable> {
    @Autowired
    private IdGenerator idGenerator;
    private List<T> elements = Collections.synchronizedList(new ArrayList<>());
    public T create(T element) {
        elements.add(element);
        element.setId(idGenerator.getNextId());
        return element;
    }
    public boolean delete(Long id) {
        return elements.removeIf(element -> element.getId().equals(id));
    }
    public List<T> findAll() {
        return elements;
    }
    public Optional<T> findById(Long id) {
        return elements.stream().filter(e -> e.getId().equals(id)).findFirst();
    }
    public int getCount() {
        return elements.size();
    }
    public void clear() {
        elements.clear();
    }
    public boolean update(Long id, T updated) {
        if (updated == null) {
            return false;
        }
        else {
            Optional<T> element = findById(id);
            element.ifPresent(original -> updateIfExists(original, updated));
            return element.isPresent();
        }
    }
    protected abstract void updateIfExists(T original, T desired);
}

The basic premise of this InMemoryRepository is simple: Provide a mechanism for all five of the previously enumerated persistence methods for any object that implements the Identifiable interface. This is where the importance of our Identifiable interface is made apparent: Our in-memory repository knows nothing about the objects it is storing, except that it can get and set the ID of those objects. Although we have created a dependency between the data source and domain layers, we have made that dependency very weak, where the data source layer only depends on an interface (rather than an abstract or concrete class that contains executable code) with only two methods. The fact that this interface is very unlikely to change also ensures that any changes to the domain layer will be unlikely to affect the data source layer.

As previously stated, our ID generator is capable of being injected into other classes, and we have done so using the @Autowired annotation. In addition, we have used a synchronized list to store our managed objects. For the same reason as the AtomicLong in our ID generator, we must ensure that we do not allow for a race condition if multiple callers try to perform concurrent operations on our data source.

While each of the operations is simple in their implementation (due to the simple in-memory design), there is one piece of information that requires knowledge of the stored object to perform: an update if the object exists. As previously expressed, our domain objects do not have enough knowledge on how to perform an update on themselves, therefore, it is the responsibility of our data source to perform this update.

Since this operation requires information we do not have, we mark it as abstract and require that concrete subclasses provide an implementation of this template method. In our case, we have only one subclass:

@Repository
public class OrderRepository extends InMemoryRepository<Order> {
    protected void updateIfExists(Order original, Order updated) {
        original.setDescription(updated.getDescription());
        original.setCostInCents(updated.getCostInCents());
        original.setComplete(updated.isComplete());
    }
}

This concrete class simply provides an implementation for updating all non-ID fields of an Order. We have also decorated our class with the @Repository annotation, which is the same as the@Component annotation (allows our class to be injected into other classes by the Spring DI framework) but also includes additional database-related capabilities. For more information, see the Javadocs for the @Repository annotation.

Although we were required to account for synchronization and DI capabilities, our entire data source layer consists of three classes and less than 70 lines of code (not counting package and import declarations). This is where the power of using a framework such as Spring comes to the forefront: many of the common tasks and conventions in web application development have been codified and made as simple as decorating classes and fields with the correct annotations. With the completion of our data source layer, we are ready to implement the final layer of our RESTful web service: the presentation layer.

Implementing the Presentation Layer

Without the aid of a web application framework, creating a presentation layer would be a daunting task, but after many years, the patterns and conventional designs of RESTful web services have been captured in the Spring Model-View-Controller (MVC) framework. This framework allows us to create RESTful endpoints with much the same ease as we saw during the development of our data source layer, using annotations and helper classes to do most of the heavy lifting for us.

Starting with the class that is the most depended on and requires the least dependencies, we will create the OrderResource first:

public class OrderResource extends ResourceSupport {
    private final long id;
    private final String description;
    private final long costInCents;
    private final boolean isComplete;
    public OrderResource(Order order) {
        id = order.getId();
        description = order.getDescription();
        costInCents = order.getCostInCents();
        isComplete = order.isComplete();
    }
    @JsonProperty("id")
    public Long getResourceId() {
        return id;
    }
    public String getDescription() {
        return description;
    }
    public long getCostInCents() {
        return costInCents;
    }
    public boolean isComplete() {
        return isComplete;
    }
}

The OrderResource class is strikingly similar to our Order class, but with a few main differences. First, we inherit from the ResourceSupport class provided by the Spring HATEOAS packages, which allows us to attach links to our resource (we will revisit this topic shortly). Second, we have made all of the fields final. Although this is not a requirement, it is a good practice because we wish to restrict the values of the fields in the resource from changing after they have been set, ensuring that they reflect the values of the Order class for which it is acting as a resource.

In this simple case, the OrderResource class has a one-to-one field relationship with the Order class, which begs the question: Why not just use the Order class? The primary reason to create a separate resource class is that the resource class allows us to implement a level of indirection between the Order class itself and how that class is presented. In this case, although the fields are the same, we are also attaching links to the fields in the Order class. Without a dedicated resource class, we would have to intermix the domain logic with the presentation logic, which would cause serious dependency issues in a large-scale system.

A happy medium between the duplication between the OrderResource and Order classes is the use of Jackson annotations in order to use the fields of the Order class to act as the fields of theOrderResource class when the OrderResource class is serialized to JSON. In the Spring MVC framework, our resource class will be converted to JSON before being sent over HTTP to the consumers of our web service. The default serialization process takes each of the fields of our class and uses the field names as the keys and the field values as the values. For example, a serialized Order class may resemble the following:

{
    "id": 1,
    "description": "Some test description",
    "costInCents": 200,
    "complete": true
}

If we tried to directly embed the Order object inside our OrderResource object (implemented our OrderResourceclass to have a single field that holds an Order object in order to reuse the fields of the Orderobject), we would end up with the following:

{
    "order": {
        "id": 1,
        "description": "Some test description",
        "costInCents": 200,
        "complete": true
    }
}

Instead, we can annotate the nested Orderobject with the Jackson @JsonUnwrapped annotation, which removes the nesting when the OrderResource object is serialized. Such an implementation would result in the following definition for the OrderResource class:

public class OrderResource extends ResourceSupport {
    @JsonUnwrapped
    private final Order order;
    public OrderResource(Order order) {
        this.order = order;
    }
}

Serializing this class would result in our desired JSON:

{
    "id": 1,
    "description": "Some test description",
    "costInCents": 200,
    "complete": true
}

While unwrapping the nested Orderobject significantly reduces the size of the OrderResource class, it has one drawback: When the internal fields of the Order changes, so do the resulting serialized JSON produced from the OrderResource object. In essence, we have coupled theOrderResource class and the internal structure of the Orderclass, breaking encapsulation. We walk a fine line between the duplication seen in the first approach (replicating the Order fields within OrderResource) and the coupling seen in the JSON unwrapping approach. Both have advantages and drawbacks, and judgment and experience will dictate the best times to use each.

One final note on our OrderResource class: We cannot use the getId()method as our getter for our ID since the ResourceSupport class has a default getId() method that returns a link. Therefore, we use the getResourceId() method as our getter for our id field; thus, we have to annotate our getResourceId() method since, by default, our resource would serialize the ID field to resourceId due to the name of the getter method. To force this property to be serialized to id, we use the @JsonProperty("id") annotation.

With our resource class in place, we need to implement an assembler that will create anOrderResource from an Order domain object. To do this, we will focus on two methods: (1)toResource, which consumes a single Order object and produces an OrderResource object, and (2) toResourceCollection, which consumes a collection of Order objects and produces a collection of OrderResource objects. Since we can implement the latter in terms of the former, we will abstract this relationship into an ABC:

public abstract class ResourceAssembler<DomainType, ResourceType> {
    public abstract ResourceType toResource(DomainType domainObject);
    public Collection<ResourceType> toResourceCollection(Collection<DomainType> domainObjects) {
        return domainObjects.stream().map(o -> toResource(o)).collect(Collectors.toList());
    }
}

In our implementation of toResourceCollection, we simply map the consumed list of Order objects to OrderResource objects by calling the toResource method on each of the Order objects in the consumed list. We then create an OrderResourceAssembler class that provides an implementation for the toResource method:

@Component
public class OrderResourceAssembler extends ResourceAssembler<Order, OrderResource> {
    @Autowired
    protected EntityLinks entityLinks;
    private static final String UPDATE_REL = "update";
    private static final String DELETE_REL = "delete";
    @Override
    public OrderResource toResource(Order order) {
        OrderResource resource = new OrderResource(order);
        final Link selfLink = entityLinks.linkToSingleResource(order);
        resource.add(selfLink.withSelfRel());
        resource.add(selfLink.withRel(UPDATE_REL));
        resource.add(selfLink.withRel(DELETE_REL));
        return resource;
    }
}

In this concrete class, we simply extend the ResourceAssembler ABC, declaring the domain object type and the resource object type, respectively, as the generic arguments. We are already familiar with the @Component annotation, which will allow us to inject this assembler into other classes as needed. The autowiring of the EntityLinks class requires some further explanation.

As we have already seen, creating links for a resource can be a difficult task. In order to remedy this difficulty, the Spring HATEOAS framework includes an EntityLinks class that provides helper methods that provide for the construction of links using just the domain object type. This is accomplished by having a REST endpoint class (which we will define shortly) use the@ExposesResourceFor(Class domainClass) annotation, which tells the HATEOAS framework that links built for the supplied domain class should point to that REST endpoint.

For example, suppose we create a REST endpoint that allows a client to create, retrieve, update, and delete Order objects. In order to allow for Spring HATEOAS to help in the creation of links to delete and update Order objects, we must decorate the REST endpoint class with@ExposesResourceFor(Order.class). We will see shortly how this ties into the path used by the REST endpoint. For the time being, it suffices to say that the EntityLinks class allows us to create links to objects that have a corresponding @ExposesResourceFor somewhere in our system. For more information on how this exposure occurs, see the Spring HATEOAS reference documentation.

The remainder of our OrderResourceAssembler class is devoted to the creation of OrderResource objects from Order objects. The creation of the resource object itself is straightforward, but the creation of the links requires some explanation. Using the EntityLinks class, we can create a link to our own resource by specifying (using the linkToSingleResource method) that we wish to create a link to an Order , which uses the Spring HATEOAS Identifiable interface to obtain the ID of the object. We then reuse this link to create three separate links: (1) a self link, (2) an update link, and (3) a delete link. We set the relative value (rel) of the link using the withRel method. We then return the fully constructed resource object. Given the three links we have created, our resulting OrderResource, when serialized to JSON, looks as follows:

{
    "id": 1,
    "description": "Some sample order",
    "costInCents": 250,
    "complete": false
    "_links": {
        "self": {
            "href": "http://localhost:8080/order/1"
        },
        "udpate": {
            "href": "http://localhost:8080/order/1"
        },
        "delete": {
            "href": "http://localhost:8080/order/1"
        }
    }
}

The self link tells the consumer that if a link to this resource is needed, the provided HREF can be used. The update and delete links tell the consumer that if this resource should be updated or deleted, respectively, the provided HREF should be used.

With the OrderResource class and its assembler completed, we can move onto the last, and arguably most essential step: creating the REST endpoints. In the Spring MVC framework, a REST endpoint is created by implementing a controller class (a class annotated with @Controller or @RestController) and adding methods that correspond to the desired REST endpoints. We will list our controller class first and then explain the meaning of each section of code:

@CrossOrigin(origins = "*")
@RestController
@ExposesResourceFor(Order.class)
@RequestMapping(value = "/order", produces = "application/json")
public class OrderController {
    @Autowired
    private OrderRepository repository;
    @Autowired
    private OrderResourceAssembler assembler;
    @RequestMapping(method = RequestMethod.GET)
    public ResponseEntity<Collection<OrderResource>> findAllOrders() {
        List<Order> orders = repository.findAll();
        return new ResponseEntity<>(assembler.toResourceCollection(orders), HttpStatus.OK);
    }
    @RequestMapping(method = RequestMethod.POST, consumes = "application/json")
    public ResponseEntity<OrderResource> createOrder(@RequestBody Order order) {
        Order createdOrder = repository.create(order);
        return new ResponseEntity<>(assembler.toResource(createdOrder), HttpStatus.CREATED);
    }
    @RequestMapping(value = "/{id}", method = RequestMethod.GET)
    public ResponseEntity<OrderResource> findOrderById(@PathVariable Long id) {
        Optional<Order> order = repository.findById(id);
        if (order.isPresent()) {
            return new ResponseEntity<>(assembler.toResource(order.get()), HttpStatus.OK);
        }
        else {
            return new ResponseEntity<>(HttpStatus.NOT_FOUND);
        }
    }
    @RequestMapping(value = "/{id}", method = RequestMethod.DELETE)
    public ResponseEntity<Void> deleteOrder(@PathVariable Long id) {
        boolean wasDeleted = repository.delete(id);
        HttpStatus responseStatus = wasDeleted ? HttpStatus.NO_CONTENT : HttpStatus.NOT_FOUND;
        return new ResponseEntity<>(responseStatus);
    }
    @RequestMapping(value = "/{id}", method = RequestMethod.PUT, consumes = "application/json")
    public ResponseEntity<OrderResource> updateOrder(@PathVariable Long id, @RequestBody Order updatedOrder) {
        boolean wasUpdated = repository.update(id, updatedOrder);
        if (wasUpdated) {
            return findOrderById(id);
        }
        else {
            return new ResponseEntity<>(HttpStatus.NOT_FOUND);
        }
    }
}

Note that the @CrossOrigin annotation provides for support of Cross Origin Resource Sharing (CORS) for our controller; for more information, see the Spring Enabling Cross Origin Requests for a RESTful Web Service tutorial. The @RestControllera annotation, as stated above, tells Spring that this class is a controller and will include REST endpoints. This annotation is coupled with the @ExposesResourceFor(Order.class) annotation, which denotes that if a link is needed to anOrder object, this controller should be used to provide the path for that link. The path information for the controller (i.e. the /order in http://localhost:8080/order) is supplied using the @RequestMapping, which maps the supplied string as the path for the controller.

For example, if the URL of the machine that the controller is executed on is http://localhost:8080, the path to reach this controller will be http://localhost:8080/order. We also include the type of the data produced by the controller, or application/json, in the request mapping to instruct Spring that this controller class produces JSON output (Spring will, in turn, include Content-Type: application/json in the header of any HTTP responses sent).

Within the controller class, we inject the OrderRepository and OrderResourceAssembler components which will allow us to access the stored Order objects and create OrderResource objects from these domain objects, respectively. Although we have a dependency to the data store layer within our controller class, we lean on Spring to provide us with an instance of the OrderRepository, ensuring that we are only dependent on the external interface of the repository, rather than on the creation process.

The last portion of the controller class is the most crucial: the methods that will perform the REST operations. In order to declare a new REST endpoint, we use the @RequestMapping to annotate a method and supply the HTTP verb that we wish to use. For example, if we look at the findAllOrders method,

@RequestMapping(method = RequestMethod.GET)
public ResponseEntity<Collection<OrderResource>> findAllOrders() {
    List<Order> orders = repository.findAll();
    return new ResponseEntity<>(assembler.toResourceCollection(orders), HttpStatus.OK);
}

we use the @RequsetMapping annotation to inform the Spring MVC framework thatfindAllOrders is intended to be called when an HTTP GET is received. This process is called mapping, and as we will see later, Spring will establish this mapping during deployment. It is important to note that the path of the mapping is relative to the path declared at the controller level. For example, since our OrderController is annotated with @RequestMapping(“/order”) and no path is explicitly declared for our findAllOrders method, the path used for this method is /orders.

The return type of ourfindAllOrders method is particularly important. The ResponseEntity class is provided by the Spring MVC framework and represents an HTTP response to an HTTP request. The generic parameter of this class represents the class of the object that will be contained in the response body of the call; this response body object will be serialized to JSON and then returned to the requesting client as a JSON string.

In this case, we will return a collection of OrderResource objects (the list of all existing orders) after obtaining them from the OrderRepository. This list is then assembled into a list of OrderResource objects and packed into a ResponseEntity object in the following line:

return new ResponseEntity<>(assembler.toResourceCollection(orders), HttpStatus.OK);

The second argument to the new ResponseEntity class represents the HTTP status code that should be used if no exceptions or errors occur while sending the response to the requesting client. In this case, we will accompany our collection of OrderResource objects with an HTTP status code of 200 OK using the enum value HttpStatus.OK.

The remainder of the REST endpoints uses this same basic structure, with a few notable exceptions. In the case of our findOrderByIddeleteOrder, and updateOrder methods, we adjust the path of the REST endpoint to include /{id}. As previously stated, this path is relative to the controller path, and thus the resolved path for each of these methods is /order/{id}. The use of curly braces ({ and }) in a path denotes a variable whose value will be resolved to a parameter in the method it annotates. For example, if we look at the findOrderById method

@RequestMapping(value = "/{id}", method = RequestMethod.GET)
public ResponseEntity<OrderResource> findOrderById(@PathVariable Long id) {
    // …Body hidden for brevity…
}

we see that the name of the parameter (id) matches the variable in the path and is decorated with the @PathVariable annotation. The combination of these two adornments tells Spring that we wish to have the value of the id variable in the path passed as the runtime value of theid parameter in our findOrderById method. For example, if a GET request is made to /order/1, the call to our findOrderById method will be findOrderById(1).

Another difference that must be addressed is the return value of the deleteOrder method: The return value of ResponseEntity<Void> tells Spring MVC that we are returning a ResponseEntity with an associated HTTP status code but we are not including a response body (the response body is void). This results in an empty response body for the response sent to the requester.

The last difference deals with the parameters of updateOrder. In the case of updating an order, we must use the contents of the request body, but doing so as a string would be tedious. In that case, we would have to parse the string and extract the desired data, ensuring that we do not make an easy error during the parsing process. Instead, Spring MVC will deserialize the request body into an object of our choice. If we look at the updateOrder method

@RequestMapping(value = "/{id}", method = RequestMethod.PUT, consumes = "application/json")
public ResponseEntity<OrderResource> updateOrder(@PathVariable Long id, @RequestBody Order updatedOrder) {
    // …Body hidden for brevity…
}

we see that the updatedOrder parameter is decorated with the @RequestBody annotation. This instructs Spring MVC to deserialize the HTTP request body into the updateOrder parameter, which takes the JSON request body (denoted by the consumes = “application/json” field in the @RequestMapping annotation) and deserializes it into an Order object (the type of updateOrder). We are then able to use the updatedOrder parameter in the body of ourupdateOrder method.

With our REST endpoints defined, we are now ready to create the main method that will be executed to start our RESTful web service.

Pulling it Together

The main method used to start our web service is as follows:

@EnableEntityLinks
@EnableHypermediaSupport(type = HypermediaType.HAL)
@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

The @EnableEntityLinks annotation configures Spring to include support for the EntityLinks class in our system (allowing us to inject the EntityLinks object). Likewise, the@EnableHypermediaSupport annotation instructs Spring to include support for HATEOAS, using the Hypermedia Application Language (HAL) when producing links. The final annotation,@SpringBootApplication, marks our application a Spring Boot application, which configures the boilerplate code needed to start Spring and also instructs Spring to component scan our packages to find injectable classes (such as those annotated with @Component or @Repository).

The remainder of the main method simply runs the Spring Boot application, passing the current class and the command line arguments to the run method. Using Spring Boot, starting our web application is nearly trivial, which leaves us with only one thing left to do: Deploy and consume our RESTful web service. 

Running and Consuming the Web Service

Since we are using Maven to manage the dependencies and build the lifecycle of our application, and Spring Boot to configure our application, we can build our project and start the HTTP server using the following command (once Maven has been installed):

mvn spring-boot:run

This will host the REST web service on http://localhost:8080. If we look closely at the output, we can see the following statements:

INFO 15204 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/order/{id}],methods=[PUT],produces=[application/json]}" onto public org.springframework.http.ResponseEntity<com.dzone.albanoj2.example.rest.resource.OrderResource> com.dzone.albanoj2.example.rest.controller.OrderController.updateOrder(java.lang.Long,com.dzone.albanoj2.example.rest.domain.Order)
INFO 15204 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/order],methods=[POST],produces=[application/json]}" onto public org.springframework.http.ResponseEntity<com.dzone.albanoj2.example.rest.resource.OrderResource> com.dzone.albanoj2.example.rest.controller.OrderController.createOrder(com.dzone.albanoj2.example.rest.domain.Order)
INFO 15204 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/order/{id}],methods=[GET],produces=[application/json]}" onto public org.springframework.http.ResponseEntity<com.dzone.albanoj2.example.rest.resource.OrderResource> com.dzone.albanoj2.example.rest.controller.OrderController.findOrderById(java.lang.Long)
INFO 15204 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/order],methods=[GET],produces=[application/json]}" onto public org.springframework.http.ResponseEntity<java.util.Collection<com.dzone.albanoj2.example.rest.resource.OrderResource>> com.dzone.albanoj2.example.rest.controller.OrderController.findAllOrders()
INFO 15204 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/order/{id}],methods=[DELETE],produces=[application/json]}" onto public org.springframework.http.ResponseEntity<java.lang.Void> com.dzone.albanoj2.example.rest.controller.OrderController.deleteOrder(java.lang.Long)

This output explicitly tells us that Spring has successfully found our controller class and has mapped the enumerated URLs to the respective methods of our OrderController class. With our web application started, we can retrieve the list of all existing orders by navigating tohttp://localhost:8080/order in any browser. When we enter this URL into a browser, the browser sends an HTTP GET to our web service, which in turn calls the findAllOrders() method of our OrderController class and returns a list of all orders, wrapped asOrderResource objects and displayed as serialized JSON. By default, the following should be returned when we navigate to http://localhost:8080/order:

[]

Since we have not created any orders yet, we see an empty list. In order to create an order, we must use an HTTP client program, such as Postman (for more information on how to use Postman to send HTTP requests, see the official Postman documentation). Using this client, we can create an order by setting the request type to POST, the request URL to http://localhost:8080/order, and the request body to the following:

{
    "description": "Our first test order",
    "costInCents": 450,
    "complete": false
}

After clicking the Send button, we should see a response status code of 201 Created and response body of the following:

{
    "description": "Our first test order",
    "costInCents": 450,
    "complete": false,
    "_links": {
        "self": {
            "href": "http://localhost:8080/order/1"
        },
        "update": {
            "href": "http://localhost:8080/order/1"
        },
        "delete": {
            "href": "http://localhost:8080/order/1"
        }
    },
    "id": 1
}

We can now navigate back to http://localhost:8080/order in our browser (or perform a GET on that address in Postman) and see the following response:

[
    {
        "description": "Our first test order",
        "costInCents": 450,
        "complete": false,
        "_links": {
            "self": {
                "href": "http://localhost:8080/order/1"
            },
            "update": {
                "href": "http://localhost:8080/order/1"
            },
            "delete": {
                "href": "http://localhost:8080/order/1"
            }
        },
        "id": 1
    }
]

This is simply a list containing our only order. If we wish to make an update to our existing order, we can simply execute a PUT to http://localhost:8080/order/1 (note the /1 at the end of the URL, denoting that we are directing our request to the order with ID 1) with the following request body:

{
    "description": "Some updated description",
    "costInCents": 700,
    "complete": true
}

If we then perform a GET on http://localhost:8080/order/1, we will see the following response:

{
    "description": "Some updated description",
    "costInCents": 700,
    "complete": true,
    "_links": {
        "self": {
            "href": "http://localhost:8080/order/1"
        },
        "update": {
            "href": "http://localhost:8080/order/1"
        },
        "delete": {
            "href": "http://localhost:8080/order/1"
        }
    },
    "id": 1
}

The last remaining task we can complete is to delete the order. To do this, simply execute a DELETE with the URL http://localhost:8080/order/1, which should return a response status code of 204 No Content. To check that we have successfully deleted the order, we can execute a GET on http://localhost:8080/order/1 and we should receive a response status code of 404 Not Found.

With the completion of this delete call, we have successfully exercised all of the CRUD operations that we implemented for orders in our REST web service. An enumeration of the calls we have made is tabulated below:

Conclusion

RESTful web services are at the core of most systems today. From Google to Amazon to Netflix, there is hardly a major software system that does not include some form of a RESTful web service that interacts with clients. At the origin of the REST revolution, creating these applications was a tedious task, but with the advent of frameworks such as Spring, and supplemental frameworks such as Spring Boot, this task has been tremendously simplified. With such tools, we are left to focus on the simple creation of a domain layer, persistence (data source) layer, presentation layer, and minimal configuration code to spin up a web service.

Thanks for reading

If you liked this post, share it with all of your programming buddies!

Follow us on Facebook | Twitter

Further reading

Spring & Hibernate for Beginners (includes Spring Boot)

Spring Framework Master Class - Learn Spring the Modern Way!

Master Microservices with Spring Boot and Spring Cloud

Spring Boot and OAuth2: Getting the Authorization Code

An Introduction to Spring Boot

How to build GraphQL APIs with Kotlin, Spring Boot, and MongoDB?

Build a Rest API with Spring Boot using MySQL and JPA

Angular 8 + Spring Boot 2.2: Build a CRUD App Today!

Spring Boot vs. Spring MVC vs. Spring: How Do They Compare?

Top 4 Spring Annotations for Java Developer in 2019

Set up Web App with Spring Boot and Spring Security

Set up Web App with Spring Boot and Spring Security

Download the Spring Boot Web App Example Project. Run the Initial Web App. Add Project Dependencies for Your Spring Boot + Spring Security Web App. Understand Your Spring Boot App. Set Up Okta for OAuth 2.0 Single Sign-On. Configure Your Spring Boot App for Single SignOn (SSO) Refine Our Permissions

Developers know that securing web apps can be a pain. Doing it right is tough. The worst part is that “right” is a moving target. Security protocols change. Vulnerabilities are found in dependencies and patches are released. Tons of often complex boilerplate code has to be generated. The software-as-service paradigm has proliferated over the last decade, and while I love reinventing the wheel as much as the next developer (because, clearly, I’m gonna write it better than the yahoo they hired), security is an area where I’m happy to offload this work to specialists. Enter Okta.

In this tutorial, you’re going to use Spring Boot to build a simple web application with a user registration system and a login system. It will have the following features:

  • Login and registration pages
  • Password reset workflows
  • Restricting access according to group membership
Download the Spring Boot Web App Example Project

The first thing you’re going to need is a free Okta account. If you don’t already have one

The next thing will be to download the example project for this tutorial from GitHub.

git clone https://github.com/oktadeveloper/okta-spring-simple-app-example.git spring-app

This project uses Gradle, as the build tool, and the Thymeleaf templating system.

Run the Initial Web App

Once you have downloaded the example code from the GitHub repository, checkout out the Start tag using the following git command: git checkout tags/Start.

The app at this point it not protected at all. There is no authorization or authentication enabled (even though the necessary dependencies are included in the build.gradle file). Go ahead and run the example by opening a terminal and, from the project root directory, running the command ./gradlew bootRun (The bootRun command is a task provided by the Gradle Spring Boot plugin, added to the build.gradle file in the buildscript section at the top of the file).

Navigate to http://localhost:8080 in your favorite browser, and you should see this:

And if you click on the “Restricted” button:

Add Project Dependencies for Your Spring Boot + Spring Security Web App

The project dependencies are defined in the build.gradle file (see below). There’s a lot going on in this file, and this tutorial isn’t going to try and explain the Gradle build system to you. Feel free to check out their documentation. I just want to point out a few things.

First off, notice that we’re including the okta-spring-boot-starter. This project greatly simplifies integrating Okta with your Spring Boot application. It’s entirely possible to use Okta and Spring Boot without this starter. In fact, up to the point where Groups and Roles are introduced, the differences are minor (mostly involve application.yml changes). However, once you start to trying to integrate Groups and Roles, the Okta Spring Boot Starter saves a lot of coding. If you’d like to look a little deeper, take a look at the Okta Spring Boot Starter GitHub project.

The rest of the dependencies deal with Spring and Spring Boot. You’ll notice none of the org.springframework.bootdependencies have version numbers. This is because of some behind-the-scenes magic being done by the Spring io.spring.dependency-management Gradle plugin. The Spring Boot Version is set by the build script property springBootVersion near the top of the build.gradle file. Based on this version number, the Spring dependency management plugin decides what versions of dependencies to include.

We’re also bringing in the org.springframework.boot Gradle plugin, which adds the bootRun task that we’ll use to run the app.

  • spring-boot-starter-security and spring-boot-starter-web are core Spring Boot dependencies.
  • spring-security-oauth2-autoconfigure is required to use the @EnableOAuth2Sso annotation that we use to hook OAuth and Single Sign-On into our app.
  • spring-boot-starter-thymeleaf and thymeleaf-extras-springsecurity4 bring in the Thymeleaf templating system and integrate it with Spring Security.
buildscript {  
   ext {  
      springBootVersion = '2.0.5.RELEASE'  
  }  
   repositories {  
      mavenCentral()  
   }  
   dependencies {  
      classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")  
   }  
}  

apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'

group = 'com.okta.springboot'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = 1.8

repositories {
mavenCentral()
}

dependencies {
compile('com.okta.spring:okta-spring-boot-starter:0.6.0')
compile('org.springframework.boot:spring-boot-starter-security')
compile('org.springframework.boot:spring-boot-starter-web')
compile('org.springframework.boot:spring-boot-starter-thymeleaf')
compile('org.thymeleaf.extras:thymeleaf-extras-springsecurity4')
compile('org.springframework.security.oauth.boot:spring-security-oauth2-autoconfigure:2.0.5.RELEASE')
testCompile('org.springframework.boot:spring-boot-starter-test') "
testCompile('org.springframework.security:spring-security-test')
}

/*
This is required to resolve a logging dependency conflict between the
okta-spring-boot-starter and the various spring dependencies.
*/
configurations.all {
exclude group: 'org.springframework.boot', module: 'spring-boot-starter-logging'
exclude group: 'org.springframework.boot', module: 'logback-classic'
}

Understand Your Spring Boot App

The Java web application has only three class files and a few templates. Obviously Spring Boot is doing a lot of heavy hitting going on in the background, but what’s going on in our class files?

The application entry point is in the SpringSimpleApplication class:

@SpringBootApplication
public class SpringSimpleApplication {
public static void main(String[] args) {
SpringApplication.run(SpringSimpleApplication.class, args);
}
}

Two important things are happening here that get things rolling: 1) we use the @SpringBootApplication annotation, and 2) our main method calls the SpringApplication.run() method. This is the entry point to the entire Spring/Spring Boot system.

The SpringSecurityWebAppConfig class is a way to use Java code to configure how Spring Boot handles web app security. Here we use the HttpSecurity object to remove authorization from all endpoints. By default, the Spring Boot behavior is the opposite: all endpoints require authorization.

@Configuration
public class SpringSecurityWebAppConfig extends WebSecurityConfigurerAdapter {

@Override  
protected void configure(HttpSecurity http) throws Exception {
    http.authorizeRequests().anyRequest().permitAll();          
}

}

The @Configuration annotation tells Spring that we are using the class as a source of programmatic configuration, allowing us to override the configure() method.

The last Java class, SimpleAppController, is our only controller object. Controllers in a Spring Boot web application are where URL requests are mapped to Java code. The @Controller annotation tells Spring that this class is a controller.

@Controller
class SimpleAppController {

@RequestMapping("/")  
String home() {  
    return "home";  
}  

@RequestMapping("/restricted")  
String restricted() {  
    return "restricted";  
}  

}

Connections between class methods and URLs are made using the @RequestMapping annotation.

We have two mappings:

  1. “home” mapping
  2. “restricted” mapping

Remember that initially nothing is actually “restricted”, so don’t get confused by that. You’ll lock that mapping down in a bit.

Also notice that the classes return a simple text string, but this is getting auto-magically turned into a full html file. This is part of the Thymeleaf dependency that is included in the build.gradle file. These strings are assumed to be template file names, which are by default paths in the templates directory on the classpath.

Thus “home” is mapped to the src/main/resources/templates/home.html template file. When the web app is packaged in the the final jar, the entire resources folder is copied into the classpath, so that the templates directory is accessible at runtime.

Set Up Okta for OAuth 2.0 Single Sign-On

Now you’re going to set up authorization for our app. Okta makes this super easy. You should have already signed up for a free developer.okta.com account. Now you’re going to create an OpenID Connect (OIDC) application to use with OAuth 2.0 Single Sign-On (SSO).

That might be a lot of jargon and acronyms, if you’re not already familiar with them. Very simply, OAuth 2.0 is an industry standard for authorization - a standardized and tested method by which authorization servers and applications can communicate to facilitate user authorization. OpenID Connect is a layer on top of OAuth 2.0 that standardizes and simplifies the authorization procedure as well as providing user authentication. Together they provide a proven way for an application to interact with a remote server that provides authentication and authorization services (such as Okta).

To create an OIDC app, open your Okta developer dashboard. Click on the Applications top menu item, and then click on Add Application.

You should see the following screen. Click on the icon for the Web option. Click Next.

You need to update a few of the initial configuration options. First change the name to something more descriptive. I used “Okta Spring Boot Simple Web App.” Next update the Login redirect URIs to http://localhost:8080/login. Click Done.

This will take you to the new application’s general configuration tab. Scroll down and note the Client ID and Client secret. You’ll need these later.

That’s all you need to do to set up Okta for OAuth! Now let’s return to the Spring Boot app and hook our new OIDC application into the Spring Boot application.

Configure Your Spring Boot App for Single Sign-On (SSO)

Now you need to configure the Spring Boot app to interact with the Okta servers. This is super easy. We need to do two things:

  1. Add the @EnableOAuth2Sso annotation
  2. Update the application.yml configuration

First add the @EnableOAuth2Sso annotation to the SpringSecurityWebAppConfig class.

@EnableOAuth2Sso
@Configuration
public class WebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {

@Override  
protected void configure(HttpSecurity http) throws Exception {  
    http.authorizeRequests().anyRequest().permitAll();          
}  

}

The @EnableOAuth2Sso annotation does a TON of stuff. It’s worth digging into to understand what’s going on. You can check out Spring’s docs on the annotation itself, and their Spring Boot and OAuth2 tutorial.

One thing I want to point out (bc this has been bugging me a while and I just figured it out) is that you can put this annotation on other classes in the project. However, if you do, be aware that Spring is going to create a WebSecurityConfigurerAdapter and add it to the security chain. Since we’re also creating a WebSecurityConfigurerAdapter, there will be two of them, and you’ll get an error about conflicting chain orders. This is because both WebSecurityConfigurerAdapters will by default use the same chain order. You can resolve this error by adding an @Order(101) annotation to our customized class. However, even better is to add the @EnableOAuth2Sso annotation to our WebSecurityConfigurerAdapter class, WebSecurityConfigurerAdapter, and Spring will use that class instead of creating a duplicate one.

The second change you need to make is update the src/main/resources/application.yml file, filling in some Okta-specific configuration options for the OAuth SSO values take from our Okta OIDC application.

You’ll need to fill in your Client ID and Client secret from the application you created above. You’ll also need to change the issuer URL so that it reflects your Okta preview URL, something like dev-123456.oktapreview.com.

server:
port: 8080

spring:
resources: static-locations: "classpath:/static/"

okta:
oauth2:
issuer: https://{yourOktaDomain}/oauth2/default
clientId: {yourClientId}
clientSecret: {yourClientSecret}
rolesClaim: groups

Refine Our Permissions

Now you’re going to want to update the SpringSecurityWebAppConfig class so that you have a public home page and a restricted “restricted” page. We do this by using Spring’s fluent API for the HttpSecurity object.

import org.springframework.boot.autoconfigure.security.oauth2.client.EnableOAuth2Sso;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@EnableOAuth2Sso
@Configuration
public class SpringSecurityWebAppConfig extends WebSecurityConfigurerAdapter {

@Override  
protected void configure(HttpSecurity http) throws Exception {  
    http.authorizeRequests()  
            .antMatchers("/").permitAll() // allow all at home page
            .antMatchers("/img/**").permitAll()  // allow all to access static images
            .anyRequest().authenticated();  // authenticate everything else!
}  

}

Restart your app and now you should be able to:

  1. See the home page without authenticating
  2. NOT see the /restricted page without authenticating
  3. Be able to authenticate using Okta Single Sign-On

This point in the tutorial corresponds to the OktaOAuthSSO tag in the GitHub repository.

Take a Look at the Thymeleaf Templates

The Thymeleaf templates are pretty self explanatory, on the whole, but I did want to point out a couple things. Thymeleaf templates are fully valid HTML5, which is nice. If you want to dig deeper, you can head over to their website and their documentation.

What I wanted to point out is how the template brings in authentication information. To do this, we’re using the thymeleaf-extras-springsecurity plugin. This is included in the build.gradle file with the following line:

compile ("org.thymeleaf.extras:thymeleaf-extras-springsecurity4")

And is included in the template file as an XML namespace attribute on the main <html> tag.

xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity4"

This plugin is what allows us to check if a user is authenticated using the th:if attribute with a custom SPEL expression (Spring Expression Language). It also allows us to insert authentication properties. Below you see a span <span th:text="${#authentication.name}"></span> that is used to insert the name of the authenticated user.

<html xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity4">
<head>
<!--// <th:block th:include="fragments/head :: head"/> //-->
</head>
<body>
<div class="container-fluid">
<div class="row">
<div class="box col-md-6 col-md-offset-3">
<div class="okta-header">
<img src="img/logo.png"/>
</div>

        &lt;!--/* displayed if account IS NOT null, indicating that the user IS logged in */--&gt;  
        &lt;div th:if="${#authorization.expression('isAuthenticated()')}"&gt;  
            &lt;h1 th:inline="text"&gt;Hello, &lt;span th:text="${#authentication.name}"&gt;&lt;/span&gt;!&lt;/h1&gt;  
            &lt;a href="/restricted" class="btn btn-primary"&gt;Restricted&lt;/a&gt;  
        &lt;/div&gt;  

        &lt;!--/* displayed if account IS null, indicating that the user IS NOT logged in */--&gt;  
        &lt;div th:unless="${#authorization.expression('isAuthenticated()')}"&gt;  
            &lt;h1&gt;Who are you?&lt;/h1&gt;  
            &lt;a href="/restricted" class="btn btn-primary"&gt;Restricted&lt;/a&gt;  
        &lt;/div&gt;  
    &lt;/div&gt;  
&lt;/div&gt;  

</div>
</body>
</html>

The thymeleaf-extras-springsecurity plugin has some other nice features as well. If you want to dig a little deeper, check out the project repository on GitHub.

Secure Access By Group Membership

The next step in our tutorial is to add Group-based authentication using user groups that we’ll create and define on Okta. A very common example of this is to have an “admin” section of a website and a “user” section of a website, along with perhaps a public home page open to everybody. In this example, “admin” and “user” would correspond to two different groups of which an authenticated user could be a member. What we want to do is be able to restrict access to URL endpoints based on user group membership, and to be able to assign users to these groups.

A side note: groups vs roles. What’s the difference?

  • A “group” is a collection of users, and permissions are assigned to the group. Generally speaking group membership is relatively static, at least throughout the duration of a session.
  • A “role” is a set of permissions that a user can inherit when he/she acts under that role. Roles are generally more dynamic in nature. Users can have many roles. Roles frequently are activated or deactivated depending on complex criteria and often may change throughout a user session.

In practice, for simple authorization systems, they’re pretty similar. The main difference is that groups classify based on individual identity, whereas roles classify based on permissible activities. You’ll probably see apps and tutorials on the wild and woolly internet that ignore this difference, as it’s functionally somewhat subtle. (But now you know. And you can get on the comment thread for the tutorial in question and write a comment correcting the author.)

Configure Authorization Groups in Okta

Go to your developer.okta.com dashboard. From the top menu, go to Users and click on Groups.

Click on the Add Group button.

Name the group “Admin” and give it a description (I put “Administrators,” doesn’t matter what you put here really, just something descriptive).

Click on the group Name to open the group and click on the Add Members button. Add your user to the Admin group.

Next add a new user that’s not an admin.

  • Go to Users from the top menu and click on People.
  • Click Add Person.
  • Fill out the popup form:
  • First name: Not
  • Last name: Admin
  • Username: [email protected]
  • No groups or secondary email
  • Password: Set by admin
  • Assign a password
  • Uncheck “User must change password on first login”
  • Click Save

The next thing you’ll need to do is add a “groups” claim to the default authorization server.

  • From the top menu, go to API and click on Authorization Servers”
  • Click on the default authorization server.
  • Click on the Claims tab.
  • Click the Add Claim button.
  • Update the popup form to match the image below
  • Name: groups
  • Token type: Access
  • Value type: Groups
  • Filter: Regex .*
  • Don’t disable
  • Include in any scope

What you’re doing here is telling Okta to include a “groups” claim in the access token that is sent to your application. This is the OAuth method of Okta telling your application about the groups your authenticated user is a member of. Somewhat confusingly, these will be called “authorities” on the Spring application side, which is an abstract term for groups/roles/privileges communicated by the OAuth server to the app.

Now we have two users. Your primary user, which has been added to the Admin group, and a new user that is not in the admin group. We’ve also configured Okta to add the groups claim to the access token. Now all we have to do is make a few changes to the app code!

Update Your Spring Boot + Spring Security App to Use Group-based Authorization

This is where the Okta Spring Boot Starter really starts to shine. Normally if you wanted to map the security groups and groups claims that we are sending in the token to groups in the app, you’d have to write an extractor class or two to handle the extraction, as well as perhaps a group class. The Okta Spring Boot Starter handles all of this for you!

The first thing you’re going to want to do is add the following annotation to your SpringSecurityWebAppConfig class.

@EnableGlobalMethodSecurity(prePostEnabled = true)

Like so:

import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;

@EnableOAuth2Sso
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SpringSecurityWebAppConfig extends WebSecurityConfigurerAdapter {
/* class contents omitted for brevity */
}

This annotation enables the next annotation that we’re going to use, the @PreAuthorize annotation. This annotation allows us to use a Spring Expression Language (SpEL) predicate to determine if the controller method is authorized. The predicate expression is executed before the app even enters the controller method (hence the “pre”-authorize).

In the SimpleAppController class, add a new method called admin like so:

import org.springframework.security.access.prepost.PreAuthorize;

@Controller
class SimpleAppController {

/* other controllers omitted for clarity */ 

@RequestMapping("/admin")  
@PreAuthorize("hasAuthority('Admin')")  
String admin() {  
    return "admin";  
}  

}

Just to recap a little, this method does the following:

  • create a mapping for the /admin url endpoint;
  • assign the /admin endpoint an authorization scheme based on SpEL;
  • and simply return the name of a Thymeleaf template, assumed to be in the /templates directory (which we’ll create next).

Create the new admin template page. In the src/main/resources/templates directory, create a new file called admin.html with the following contents:

<html xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity4">
<head>
<!--// <th:block th:include="fragments/head :: head"/> //-->
</head>
<body>
<div class="container-fluid">
<div class="row">
<div class="box col-md-6 col-md-offset-3">
<div class="okta-header">
<img src="img/logo.png"/>
</div>

        &lt;h1&gt;Welcome to the admin page!&lt;/h1&gt;  

        &lt;a href="/" class="btn btn-primary"&gt;Go Home&lt;/a&gt;  

    &lt;/div&gt;  
&lt;/div&gt;  

</div>
</body>
</html>

You may be asking yourself what the SpEL expression used in the @PreAuthorize annotation means. Why is the SpEL expression hasAuthority and not hasGroup? A correct answer is somewhat complicated, having to do with the fact that Spring calls permissions privileges and authorities in different contexts, which can be mapped to groups and roles in the app. When using Spring Boot and OAuth, an ‘authority’ is often equated with a ‘role’, which is fine. But you said we’re using groups, not roles? Right. Practically speaking, in this instance, it doesn’t matter because Okta knows we’re talking about groups and the app knows we’re talking about groups, and in the middle we just use the groups claim and the authorities fields to communicate the text strings that represent the groups the user is a member of.

A helpful hint:

If you want to inspect the authentication information that the Spring Boot App is receiving, you can add the following line in one of the controller methods before the return statement.

Authentication authentication = SecurityContextHolder.getContext().getAuthentication();

Set a breakpoint on this line, or right after it, really, and run the app with a debugger that allows you to inspect the authentication object. It’s a great way to learn and debug problems.

Try Out Your New Spring Boot + Spring Security Web App!

That’s pretty much it. You should be able to restart the app and log in with two different users. Only the user that was added to the Admin group should be able to access the admin page. You’ll have to directly navigate to http://localhost:8080/admin (as we didn’t add a link or a button). If you try to navigate to the admin page with the other user, you’ll see the beautiful whitelabel error page showing a 403 / Unauthorized error.

Keep in mind that when switching between users you’ll have to stop the app, log out of your developer.okta.com account, and restart the app. You can also use an incognito window in your browser.

This part of the tutorial corresponds to the GroupsAuth tag, which you can checkout using the following command git checkout tags/GroupsAuth.

Thanks for reading. If you liked this post, share it with all of your programming buddies!

Further reading

☞ Spring & Hibernate for Beginners (includes Spring Boot)

☞ Spring Framework Master Class - Learn Spring the Modern Way!

☞ Master Microservices with Spring Boot and Spring Cloud

☞ Spring Boot and OAuth2: Getting the Authorization Code

☞ An Introduction to Spring Boot

☞ How to build GraphQL APIs with Kotlin, Spring Boot, and MongoDB?

☞ Build a Rest API with Spring Boot using MySQL and JPA

☞ Angular 8 + Spring Boot 2.2: Build a CRUD App Today!

☞ Spring Boot vs. Spring MVC vs. Spring: How Do They Compare?

☞ Top 4 Spring Annotations for Java Developer in 2019


Originally published on developer.okta.com

What is REST? What are RESTful Web Services?

What is REST? What are RESTful Web Services?

This tutorial provides an introduction to RESTful web services and goes over what REST is as well as HTTP.

REST stands for REpresentational State Transfer. It is a popular architectural approach to create your API's in today's world.

You Will Learn
  • What is REST?
  • What are the fundamentals of REST APIs?
  • How do you make use of HTTP when building REST API?
  • What is a Resource?
  • How do you identify REST API Resources?
  • What are some of the best practices in designing REST API?
What Is REST?

The acronym REST stands for REpresentational State Transfer. It was term originally coined by Roy Fielding, who was also the inventor of the HTTP protocol. The striking feature of REST services is that they want to make the best use of HTTP. Let's now have a quick overview of HTTP.

A Relook at HTTP

Let's open up the browser and visit a web page first:

And then click on one of the result pages:

Next, we can click on the link on the page we end up in:

And land upon another page:

This is how we typically browse the web.

When we browse the internet, there are a lot of things that happen behind the scenes. The following is a simplified view of what happens between the browser, and the servers running on the visited websites:

The HTTP Protocol

When you enter a URL such as https://www.google.com in the browser, a request is sent to the server on the website identified by the URL. That server then responds with a response. The important thing is the formats of these requests and responses. These formats are defined by a protocol called HTTPHyper Text Transfer Protocol.

When you type in a URL at the browser, it sends out a GET request to the identified server. The server then replies with an HTTP response that contains data in HTMLHyper Text Markup Language. The browser then takes this HTML and displays it on your screen.

Let's say you are filling in a form present on a web page with a list of details. In such a scenario when you click the Submit button, an HTTP POST request gets sent out to the server.

HTTP and RESTful Web Services

HTTP provides the base layer for building web services. Therefore, it is important to understand HTTP. Here are a few key abstractions.

Resource

A resource is a key abstraction that HTTP centers round. A resource is anything you want to expose to the outside world through your application. For instance, if we write a todo management application, instances of resources are:

  • A specific user
  • A specific todo
  • A list of todos

Resource URIs

When you develop RESTful services, you need to focus your thinking on the resources in the application. The way we identify a resource to expose, is to assign a URIUniform Resource Identifier — to it. For example:

  • The URI for the user Ranga is /user/ranga
  • The URI for all the todos belonging to Ranga is /user/Ranga/todos
  • The URI for the first todo that Ranga has is /user/Ranga/todos/1

Resource Representation

REST does not worry about how you represent your resource. It could be XML, HTML, JSON, or something entirely different! The only important thing is you clearly define your resource and perform whatever actions that are supported on it by making use of features already provided by HTTP. Examples are:

  • Create a user: POST /users
  • Delete a user: DELETE /users/1
  • Get all users: GET /users
  • Get a single user: GET /users/1
REST and Resources

A significant point to note is that with REST, you need to think about your application in terms of resources:

  • Identify what resources you want to expose to the outside world
  • Make use of the verbs already specified by HTTP to perform operations on these resources

Here is how a REST service is generally implemented:

  • Data Exchange Format: No restriction is imposed over here. JSON is a highly popular format, although other such as XML can be used as well
  • Transport: Always HTTP. REST is completely built on top of HTTP.
  • Service Definition: There is no standard to specify this, and REST is flexible. This could be a drawback in some scenarios, as it might be necessary for the consuming application to understand the request and response formats. There are widely used ones however, such as WADL (Web Application Definition Language) and Swagger.

REST focuses on resources and how effectively you perform operations on them using HTTP.

The Components of HTTP

HTTP defines the following for a request:

For the response, HTTP defines the:

HTTP Request Methods

The method used in a HTTP request indicates what action you want to perform with that request. Important examples are:

  • GET: Retrieve details of a resource
  • POST : Create a new resource
  • PUT: Update an existing resource
  • DELETE: Delete a resource

HTTP Response Status Code

A status code is always present in a HTTP response. Common examples are:

  • 200: Success
  • 404: Page not found
Summary

In this article, we had a high-level look at REST. We stressed the fact that HTTP is the building block of REST services. HTTP is a protocol that is used to define the structure of browser requests and responses. We saw that HTTP deals mainly with resources that are exposed on web servers. Resources are identified using URIs, and operations on these resources are performed using verbs defined by HTTP.

Finally, we looked at how REST services make the best use of features offered by HTTP to expose resources to the outside world. REST does not put any restrictions on the resource representation formats or on the service definition.