Skip to content

No code REST services with Spring Boot and Spring Data REST

CRUD REST services are the backbone of a microservice architecture. If we want to use microservices rather than monolithic applications, it’s essential that we can create a basic service with a minimum of effort. Spring Boot can be used to quickly create and deploy a new web service. Spring Data REST can be used to build out the REST interface based on a database entity model. Using both together allows us to create a running RESTful web service with zero custom Java code and no tricky XML.

This article describes how to build a RESTful web service as an executable JAR that provides CRUD operations against a single MySQL database table.

This demo can be downloaded from GitHub in the Spanners Demo Application version 4.0 (spanners-api module). You can run the working example as a docker-compose stack, along with the associated MySQL database and the Spring MVC web app that consumes the service (see the previous post on docker-compose for details on how to run this).

Spring Boot starters

The Spring Boot starter projects allow us to easily pull in the dependencies we need based on our broad requirements. It’s no longer necessary to explicitly define every library that we build on. Just pull in the Spring Boot starters for our application type and we’re good.

For a Spring Data REST project, we need the JPA starter (to configure our database mappings) and the Spring Data REST starter. We’ll most likely also want the test starter to allow us to write unit tests. The one dependency we need to explicitly define is our specific database driver (MySQL in my case).

If you dislike XML, this can be done with Gradle. I still prefer Maven so my pom.xml looks like this:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.3.5.RELEASE</version>
    </parent>

    <modelVersion>4.0.0</modelVersion>
    <groupId>spanners</groupId>
    <artifactId>spanners-api</artifactId>
    <version>4.0-SNAPSHOT</version>
    <packaging>jar</packaging>
    <name>Spanners REST API</name>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-rest</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!-- MySQL for production database connection -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

No need to specify version numbers for any of these. The Spring Boot parent manages all these. The Spring Boot Maven Plugin allows Maven to run Spring Boot applications directly, or to build an all in one executable jar so we can run our application from command line – no need to deploy to an application server.

Entity model and mapping

I have a database table that I want to model in my application:

CREATE TABLE `spanner` (
  `id` int(11) NOT NULL auto_increment,
  `name` varchar(255) default NULL,
  `size` int(11) default NULL,
  `owner` varchar(255) default NULL
)

This is mapped to a Java class using JPA annotations:

@Entity
public class Spanner {

    @Id
    @GeneratedValue(strategy= GenerationType.AUTO)
    private Long id;
    private String name;
    private int size;
    private String owner;
    
    // Getters and setters go here

}

Note that only the class and the id field are annotated. JPA is smart enough to correctly map the name, size and owner fields to the obvious database columns.

Data Repository

This is where it starts to get clever. A while back, if we needed to create a data repository (or Data Access Object / DAO), we’d define all the operations we want (create, read, update, delete) and then implement each operation as a method using Hibernate, SQL or whatever.

Now, the JpaRepository interface (with super interfaces PagingAndSortingRepository and CrudRepository) define methods for our standard CRUD operations. It’s a typed interface so we can define something like this:

public interface SpannerRepository extends JpaRepository<Spanner, Long> {
}

Where Spanner is the type of object managed by the repository and Long is the type of unique identifier – essentially the database table primary key.

The JpaRepository interface defines 18 methods. This could result in a great deal of boilerplate code if we were to implement by hand. Fortunately, JPA will create the implementation of this interface automatically. Mechanisms exist to trigger this implementation using XML or Java based Spring config. This configuration is enabled by default with the spring-boot-starter-data-jpa module so we need do nothing further at all.

Expose a REST interface

We now want a RESTful API for our repository. Again, we could hand craft this, but Spring Data REST takes care of this for us with a single annotation on our repository definition:

@RepositoryRestResource
public interface SpannerRepository extends JpaRepository<Spanner, Long> {
}

This will expose a well-defined RESTful API with repository CRUD operations correctly mapped to HTTP methods (POST  for create, GET for read etc) with API meta-data exposed using HAL.

Configuration

The only thing needing explicit configuration is the connection to a data source. This can be done in an application.properties file which can either be included inside the application (in src/main/resources) or provided at runtime. A connection to a MySQL database looks like this:

spring.datasource.url=jdbc:mysql://localhost:3306/spanners
spring.datasource.username=spanners
spring.datasource.password=password
spring.datasource.driver-class-name=com.mysql.jdbc.Driver

And now, the boilerplate…

There had to be some boilerplate somewhere. In this case, it’s the main class that bootstraps into Spring Boot. You always need one and it usually looks the same. It looks like this:

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

That’s it.

Running the app

This could be built as a WAR and deployed to an application server. Spring Boot offers us an alternative though. It can build as an executable JAR containing all dependencies and an embedded web server. So we build the app (using Maven) in the usual way:

mvn clean package

and then run like this:

java -jar ./target/spanners-api-4.0.jar

We can verify that the app is running by entering http://localhost:8080/spanners/ in a browser. It should return a valid JSON response:

{
  "_embedded" : {
    "spanners" : [ {
      "id" : 1,
      "name" : "Gertrude",
      "size" : 10,
      "owner" : "smith",
      "_links" : {
        "self" : {
          "href" : "http://localhost:8090/spanners/1"
        },
        "spanner" : {
          "href" : "http://localhost:8090/spanners/1"
        }
      }
    }, {
      "id" : 2,
      "name" : "Samantha",
      "size" : 16,
      "owner" : "smith",
      "_links" : {
        "self" : {
          "href" : "http://localhost:8090/spanners/2"
        },
        "spanner" : {
          "href" : "http://localhost:8090/spanners/2"
        }
      }
    }, {
      "id" : 3,
      "name" : "Susan",
      "size" : 20,
      "owner" : "jones",
      "_links" : {
        "self" : {
          "href" : "http://localhost:8090/spanners/3"
        },
        "spanner" : {
          "href" : "http://localhost:8090/spanners/3"
        }
      }
    } ]
  },
  "_links" : {
    "self" : {
      "href" : "http://localhost:8090/spanners"
    },
    "profile" : {
      "href" : "http://localhost:8090/profile/spanners"
    }
  },
  "page" : {
    "size" : 20,
    "totalElements" : 3,
    "totalPages" : 1,
    "number" : 0
  }
}

It shows the attributes of the three spanners currently in the database. It also shows paging information and a link to the service ALPS meta-data. That’s not at all bad for one annotated interface definition, a couple of annotated classes, a one line method implementation, some config and a build definition.

Published inHow ToJava TechnologiesSpring BootWeb Technologies

3 Comments

Leave a Reply

Your email address will not be published. Required fields are marked *