I don't like to use Java (and please don't use it) but sometimes I have to... and that was the case.
A few weeks ago I started a new project at Indigo (please follow them!) and the chosen framework to do the job was Spring Boot and this time I had no option since the other person who is developing with me loves the combination Java + Spring Boot.
But why do I said "the combination"? ๐ค Well, there are some programming languages that work on the JVM such as Kotlin, Scala and my favorite Groovy!.
What is Groovy?
According to it's official page:
Apache Groovy is a powerful, optionally typed and dynamic language, with static-typing and static compilation capabilities, for the Java platform aimed at improving developer productivity thanks to a concise, familiar and easy to learn syntax. It integrates smoothly with any Java program, and immediately delivers to your application powerful features, including scripting capabilities, Domain-Specific Language authoring, runtime and compile-time meta-programming and functional programming.
In other words, you can do better stuff, write less code and get some cool features that Java cannot.
What will be our example?
This time we will create a Pokemon API!! Let's catch'em all
Our API must:
Get the information of all trainers
Get the information of a specific trainer
Get all caught pokemon of a specific trainer
What will be using to solve that?
Java 8
Gradle
Spring Boot
Groovy
MySQL
Flyway DB
What do I need to install?
Java 8 or greater
Gradle
MySQL
I highly recommend you to install Java and Gradle via SDKMAN.
Let's get started!
1. Create the base project with Gradle
Create a directory and then create a file named build.gradle. This file will:
The lines tell Gradle to configure Maven Central as the default repository, download and use the spring-boot-gradle-plugin and download the following dependencies:
Spring Boot Web: Exposes REST services
Groovy: Compiles and interprets all Groovy/Java code
Also our base package name will be com.pokemon so every class with this package name will be compiled by Gradle and used by Spring Boot.
2. Create the base code and run it for the first time
Create the directories src/main/groovy/com/pokemon in the root directory and then create a file named Application.groovy:
packagecom.pokemonimportorg.springframework.boot.SpringApplicationimportorg.springframework.boot.autoconfigure.SpringBootApplication// In groovy every class is public by default// so you don't need to write "public class" anymore@SpringBootApplicationclassApplication{// Every method is public as wellstaticvoidmain(String[]args){// You can omit the last method call parenthesis// This is the same as .run(Application, args)// also you can omit ;SpringApplication.runApplication,args}}
Open your terminal, go to your project directory and type the command gradle bootRun to get your application running like this:
3. SQL tables with Flyway DB
Working with SQL databases is often a pain.
How do you share the database structure with your team?
A way to deal with it is create a SQL script and share it with all the developers.
Sounds good, right?
But, when you need to add changes (like modifying existing tables or adding new ones) to the script, What do you do now? How do the dev team get notified from those changes?
Framework such as PHP Laravel introduce the migration concept. Every change to the database (creating a table, adding a field, changing a field type, etc) is a migration. Migrations are executed in certain order and keep the database always up-to-date.
Flyway DB will help us to solve the problem but in Java (Groovy).
According to it's official page:
Version control for your database.
Robust schema evolution across all your environments.
With ease, pleasure and plain SQL.
So now let's add Flyway DB, Spring Data and MySQL Connector to our project.
Edit build.gradle file and the following dependencies:
As you can see, it's easy to create entity classes based on tables. In the WildPokemon case we declared 2 many to one relationships, one to Pokemon class (or table) and the other one to Trainer class (or table). Only Trainer relationship can be null.
5. Repository classes (Persistence layer)
A Repository class is the place to define our queries. It's very easy and magical at the same time.
Remember our API goal:
Get the information of all trainers
Get the information of a specific trainer
Get all caught pokemon of a specific trainer
Okay, let's translate those features into SQL queries:
-- Get the information of all trainersSELECT*FROMtrainers;-- Get the information of a specific trainerSELECT*FROMtrainersWHEREid=?;-- Get all caught pokemon of a specific trainerSELECT*FROMwild_pokemonWHEREtrainer_id=?;
Seems legit.
But what if the queries were written in human readable text?
# Get the information of all trainers
find all trainers
# Get the information of a specific trainer
find trainer by id# Get all caught pokemon of a specific trainer
find wild pokemon by trainer id
And believe or not, using JpaRepository interface from Spring Data our queries are:
findAll
findById
findByTrainerId
Very easy!! ๐๐๐๐๐
Let's code them, in src/main/groovy/com/pokemon directory create a new one named repository and create 2 new files:
And finally you can use polymorphism to change the storage type whenever you need it:
// Save the file in Amazon S3Storagestorage=newS3Storage()// Save the file in Azure BlobStoragestorage=newBlobStorage()// Save the file in diskStoragestorage=newDiskStorage()
That's why we create interfaces, because the business logic can change anytime or whenever the client wants to.
So, let's create our 2 interfaces and their implementation:
@RequestMapping annotation configures the prefix of all endpoints defined in that controller. Also configures method type (GET, POST, PUT, DELETE, etc).
@Autowired annotation creates instances of service classes for us.
@PathVariable annotation passes the specified URL parameter to the method call.
For last, let's insert dummy data into MySQL using Flyway DB. Create a new migration (in src/main/resources/db/migration) named V2__inserting_example_data.sql:
In the next post we will improve our pokemon API adding more features and things like Data Transfer Objects, Exception Handler, Swagger, Testing and more!