Get a quick overview of how to get started with building a simple REST API using Spring Boot.
Get a quick overview of how to get started with building a simple REST API using Spring Boot.
Spring and Spring Boot are vast topics that you can spend weeks together to get a grasp of. It may be much easier to start with some basic understanding of them from wikipedia and then immediately jump into the tasks. When you start using more and more features of Spring, you will start to appreciate why it exists.
Spring
In layman’s terms, it’s an application framework that helps you build Java applications with all bells and whistles really fast.
Spring Boot
Spring Boot is a solution for creating stand-alone, production-grade Spring-based Applications that you can "just run" with very little configuration. In simple terms, it can help you get started in building a REST API server in less than 30 minutes.
Build a simple REST API server using Spring Boot
Understand asynchronous flow of a REST API server
Understand some of the basic annotations to create a REST API
Understand Jackson and Java<>JSON conversion
Get a quick overview of how to get started with building a simple REST API using Spring Boot.
Spring and Spring Boot are vast topics that you can spend weeks together to get a grasp of. It may be much easier to start with some basic understanding of them from wikipedia and then immediately jump into the tasks. When you start using more and more features of Spring, you will start to appreciate why it exists.
Spring
In layman’s terms, it’s an application framework that helps you build Java applications with all bells and whistles really fast.
Spring Boot
Spring Boot is a solution for creating stand-alone, production-grade Spring-based Applications that you can "just run" with very little configuration. In simple terms, it can help you get started in building a REST API server in less than 30 minutes.
Build a simple REST API server using Spring Boot
Understand asynchronous flow of a REST API server
Understand some of the basic annotations to create a REST API
Understand Jackson and Java<>JSON conversion
You can download the source code from here using one of the following commands:
git clone https://gitlab.crio.do/crio_bytes/springboot.git
git clone git@gitlab.crio.do:crio_bytes/springboot.git
We are using a slightly modified version of Spring Boot’s tutorial - https://spring.io/guides/gs/rest-service/. Except for some minor changes like we running it on port 8081, the flow is very similar.
Can you start the server now using the following command? It may take upto a minute when you run it the first time as a lot of dependencies get downloaded.
./gradlew bootRun
It will print the Hello World message
if you now visit http://localhost:8081/greeting on your browser or
# type in terminal
curl http://localhost:8081/greeting
You are now running a REST API server which will respond back to your API requests.
You didn’t write a whole lot of code, but in an instant able to run a rest server. That was easy enough, but how did it happen?
// File: src/main/java/com/example/restservice/GreetingController.java
@GetMapping("/greeting")
public Greeting greeting(@RequestParam(value = "name", defaultValue = "World") String name) {
// System.out.println("Learn By Doing");
Greeting greetingMessage = new Greeting(counter.incrementAndGet(), String.format(template, name));
return greetingMessage;
}
Change @GetMapping("/greeting") to @GetMapping(“/learningisdoing”)
Stop ./gradlew bootRun command by pressing ctrl-c and rerun it; this step is called restarting your server.
Is your curl command still working? Answer the question given below.
Revert the change you did in the previous step and uncomment System.out.println("Learn By Doing") like this:
@GetMapping("/greeting")
public Greeting greeting(@RequestParam(value = "name", defaultValue = "World") String name) {
System.out.println("Learn By Doing");
return new Greeting(counter.incrementAndGet(), String.format(template, name));
}
Now restart your server by rerunning ./gradlew bootRun and issue the same curl command again. Do you see "Learn By Doing" printed below ./gradlew bootRun command?
Who is calling greeting() function? Search for it throughout the codebase. Are you able to find the caller? If you are not able to find the function, who calls it?
You may sometimes see this error when you run ./gradle bootRun command
It means that a different instance of your server is running. You may have to kill it before restarting it using lsof -i :8081 and kill commands.
Now change the function name "public Greeting greeting()" to “public Greeting learningisfun()”.
Restart the server and see if you are able to do curl http://localhost:8081/greeting? Answer the question below.
Revert the function name back to greeting() once you are done with this experiment.
Did you take a look at main function?
public static void main(String[] args) {
SpringApplication.run(RestServiceApplication.class, args);
}
Isn’t your main function supposed to execute this single line SpringApplication.run() and then exit the program? How is that your curl command still able to get replies back if your process terminated after executing this single line?
That’s where Spring’s magic comes into picture - with couple of annotations, Spring is running a a server that keeps listening on a port though your main function completed.
Read a bit about
@SpringBootApplication annotation and what it helps with
What this line does - SpringApplication.run(RestServiceApplication.class, args)
Java annotations
As you can see, GreetingController.greeting(String) is the last stack frame, but you are probably not able to find anything else meaningful and you see some functions/variables containing HTTP. That is precisely the point!
Here is what is happening behind the scenes:
You are sending a HTTP request (http://localhost:8081/greeting) to the web server running on port 8081 either through curl or through your browser - both send the exact same request
Your spring server receives this HTTP request, processes it all the way up the stack, and hands it over to some function which is marked with @GetMapping("/greeting") annotation.
Spring uses the @GetMapping annotation to find which function to call - so if you add one more annotation + function, you would have created one more end point and you call it by curl http://localhost:8081/newendpoint
@GetMapping("/newendpoint")
public Greeting functionNameIrrelevant(@RequestParam(value = "name", defaultValue = "World") String name) {
System.*out*.println("My New Endpoint");
Greeting greetingMessage = new Greeting(counter.incrementAndGet(), String.format(template, name));
return greetingMessage;
}
What are the other annotations you see in the code? Can you guess what they do? If you spend time now to understand what they mean, you will save hours of debugging time later when you work on a larger code base.
@RestController - Tip: Assume your Java code has 1000s of classes. Which classes should your Spring search for to find @GetMapping?
@RequestParam
How did we tell the server to listen on 8081 when the tutorial you referred to used 8080? Tip: grep for the "8081" across all files.
How do you create an endpoint for a POST request? Look for annotations to do that in Spring.
If you had a keen eye, you would have seen greeting() function returning a Java object.
public Greeting greeting()
But the caller of this function, which is your curl command or your browser through indirect hops will not be able to understand Java objects. In fact they received a JSON response.
{
"id":1,
"content":"Hello, World!"
}
How did this happen? Did you ever remember converting the Greeting java object to a JSON string?
Jackson is a java library that helps you convert a Java object into JSON and back. Whenever required Spring automagically uses Jackson library to convert Java objects into JSON and back. It uses a class in Jackson library called ObjectMapper to do this. Now how do you see for yourself that this is happening? Again breakpoints are our friends.
Set a breakpoint at setName() function in CreditCard.java and run the server in debug mode.
Issue the curl command to the json-request endpoint.
curl --header "Content-Type: application/json" \
--request POST \
--data '{"name":"Santa","creditCardNumber":"0202-2323-2323-1999"}' \
http://localhost:8081/json-request
You will be hitting the breakpoint and look at the stack trace. Are you able to see ObjectMapper.readValue()?
If you walk down the stack trace further, it will be obvious that Spring called it when trying to process the request.
You noticed the setter being called when deserializing the JSON string into a Java object. What do you think will get called when serialization happens? Can you prove that by setting an appropriate breakpoint in Greeting class?
How did Jackson know which variable to store creditCardNumber in from the JSON string? Try playing around with the input JSON and variable names in the CreditCard.java class and see if you can make out the relationship.
Add @JsonIgnore on top of id field in Greeting.java
@JsonIgnore
private final long id;
See what output you get for your curl command. Try to read/reason out about the output.
Can you now write a simple HTTP end-point using Spring Boot? Btw, no one writes these from scratch including the build.gradle - pick the tutorial code and keep adding more endpoints!
Spring Initializr is usually an easy way to get the overall structure of your Spring project including build.gradle dependencies.
Are you now comfortable with the following annotations?
@RequestParam
@GetMapping, @PostMapping
@RestController
@SpringBootApplication
Can you now explain how Spring converts JSON to Java and back?
What do serialization and deserialization processes use - getters/setters?