Starting point: Learning REST service

Let’s write a REST service with spring boot and run it in a Docker container

Introduction

We are in a practical journey towards a microservice architecture. In the previous post, I talked about SOAP service and how to create one with spring boot 2 (if you didn’t read it, do it now, we will continue appending information). Today we will learn how we can move towards microservices architecture by using a lighter, fast to parse JSON that will allow more services to talk to each other introducing REST. Also, for our business layer (promotion decisions) we will implement and explore a rule engine library called easy rule and learn how we move our previous business logic to this rule engine to enable extensibility for future rules.

So, What is REST?

Web services are a standardized way to communicate through messages on the internet as mailing is a way to communicate through letters in the real world, as the mailman is the communication protocol that delivers letters to the specific address (URL). In a previous post, we learn that SOAP service is pre-defined letters, like a legal notice of claim where it specifies how data that should be structured and sent in an XML file format (“eXtensible Markup Language). While in the other hand we have REST that is more like a normal letter with instructions where the envelope type represent the operation needed to be executed in a JSON file format (“JavaScript Object Notation”). REST stands for “REpresentational State Transfer” as a set of operations commonly used with web transactions, you’ll mainly use 4 types operations (there are more) that you can handle, those are:

  • GET used to obtain a resource
  • POST is used to create a resource
  • PUT to update an existing resource
  • DELETE is used to well, you got the idea.

We could simply say that REST is a simple and light way applications talk.

Advantage

  • Interoperability amongst applications: As already mention web services allow various applications to talk to each other, sharing data and services. Any application can talk to others no matter the code language is made as long as it implements this JSON notation and HTTP operators.
  • Human readable: If we compare JSON to XML, it’s way easier to read JSON because it doesn’t use tags to separate properties, it’s lightweight and goes directly to the point, so it’s more suitable for microservices architecture when several services are talking to other services and we need all the bandwidth juice we can get.
  • The separation between the client and the server: the REST separates the user interface from the server and the data storage. It improves the portability, increases scalability and allows the different components to be evolved independently.

What you will learn in this post

  • How to use Spring boot 2 to create a REST application.
  • REST principles as we already cover
  • How to make your unit and integration tests
  • Use of JUnit 5 with parameterized tests.
  • Package your service for delivery with Docker.
  • How to handle properties production ready.

Pre-requirements

Hands-on!

If you want to get a full script of the project you can find it in this repository.

Let’s start our project by creating a gradle.build file and populated with the dependencies we need.

Gradle build

File: build.gradle

This file defines the build task with the dependency needed for each task (test, build, etc), let’s take a look at each dependency.

“org.springframework.boot:spring-boot-starter-web-services”

We use spring boot web service dependency because includes all the necessary to create a RESTful web service like an embedded web container and a web service layer. Also, we can find the spring-boot-starter-test dependency enabling us with the tools to test the code.

“org.jeasy:easy-rules-core:3.2.0”

Easy rules is a production rule engine useful when we have actions based on a condition like if it’s a new user offer 20% discount for 6 months, but we will get into detail later on when we discuss the business layer.

“org.projectlombok:lombok”

Lombok it’s a great library to reduce tedious coding, it leaves the code cleaner and more readable by using annotations that simplify your life like @Data annotation that add getters and setters for all your private properties of your class among other things the library provides. If you don’t know about Lombok project capabilities, I suggest you visit his site and find more about, I really love this library is a must in every project.

“junit-jupiter-engine” and “junit-jupiter-params”

The latest unit test library that also works well with spring boot and I’m also adding the params module to reuse test cases and extend our coverage by adding parameters to the test function.

Rest controller

File: ValidatorController.java

This is our entry point where we expose a POST method to compute the user information provided and decide if it has any message, it’s kind of our deal.

Our controller use @RestController annotation to let spring boot autoconfigure this object so it can route any POST request made to “/validate/promo” to execute hasPromo method, spring will handle JSON serialization to a POJO.

Rule engine

Instead of using a consist sequence of commands with conditionals and loops, a rules engine use a set of ordered rules to organize actions based on conditional rules.

The advantage is organization and simplicity, achieved by separate each condition with its action by a class rule. Visualize it as a system running through all the rules, picks the ones for which the condition is true, and then evaluates the corresponding actions. The nice thing about this is that many problems naturally fit this model.

I’d used a couple of rule engines, the idea always is to have a file so any human can create new rules, in general, each engine has their own syntax, but I always find a developer creating or editing rules instead of data entry or business analyst. So, I decided to use Easy rule library that solves the dilemma with a builder pattern and annotations. This way I don’t have to deal with new syntax and the library help me organize the rules, once the rules start to grow is easy to mess up rules. Easy rules help to easily identify rules by name and description.

File: NewUserRule.java

With the help of only 3 annotations we can describe the rule with @Rule(name and description), specified the condition and properties needed to operate with @Condition and @Fact (fact is defined when the engine is created in PromoService.java) and @Action to define what to do if the condition is true, in our case we add it to a list of messages so we react on completion of the rule engine execution.

Test, test and more test

I had created 2 files, one with a test for each rule and other as an example of the integration test.

File: integration test and rule tests

It always forgot the automated test part, so I want to left here as a reference how you can accomplish both, integration test and unit test.

Let’s take a look to the unit tests in detail, check the NewUserRuleTest.java you will find that each test receives a parameter with days.

@ParameterizedTest
@ValueSource(ints = { -30, 0, -61, -91, -122, -152, -180 })
public void testValidNewUser(Integer days)

The first annotation is used to let JUnit know this test receive parameters.

The second annotation we define the parameters and the type we will use in this test, so this test will be executed 1 time for each value source defined.

This way we reduce repetitive code and ensure better coverage.

Properties

I always recommend using environment properties on anything that could be changed depending on the environment, this way we don’t need to build the app and generate a new image every time we change a property, and also is a practical way to hide sensitive information like crypto keys or tokens by externalizing them to environment properties and you can accomplish it by setting like in our case the server.port property in the application.properties file like this:

server.port=${SERVER_PORT:8080}

To set the property SERVER_PORT we only need to execute “export SERVER_PORT=8090” if we want to set the port 8090 for our service in the environment needed.

For docker we can provide that env when run our image by adding the -e parameter like this:

-e SERVER_PORT=8090

Docker

We will use docker to containerize our application to be production ready and be able to run in any machine since we contain everything we need to this application run inside our docker image.

You can find the script to run this app or any spring-boot application here and if you want to know more about each step in this script take a look into my previous post where I go into detail.

How to run this!

Easy steps to build and run it in a docker container.

Open a console and execute these steps:

  1. Create directory and get inside: mkdir ~/tutorials && cd ~/tutorials
  2. Clone repository: git clone https://github.com/Gueka/sb2-rest-tutorial.git
  3. Get inside the repository: cd sb2-rest-tutorial
  4. Make start file executable: chmod u+x start.sh
  5. Run that app!: ./start.sh

Conclusions

Structurally we didn’t change much since our last project, we have a web layer that exposes an operation and our business layer that keeps our logic apart, but we learn about REST, how to implemented and test it. Also, we learn how to organize our business logic with a rule engine that allows us to easily add new rules and separate its logic.

I always try to add 2 new implementations to each post, try to keep it simple and add links to further investigation about the topics.

If you are interested in microservices, java, how to program for the real world and keep your code clean, follow me in this journey towards microservices. I will be posting more information about these topics and adding more information through each post.

As a last reminder, always have fun coding and if you have any question or suggestions I’m all ears.

Happy coding!