# Creating RESTful API Using Spring Boot for The First Time #WeekendBuild

Last time I wrote Java was early 2013 for my undergraduate thesis. It was a image processing program. I decided wrote in Java because during college era, Java was like main programming language that been taught. Also recently while job hunting, I saw many jobs mentioned Spring Boot as their main stack, so I wonder why not try this stack for my [#WeekendBuild](https://blog.didiktrisusanto.dev/series/weekend-build) series?

# Preparation

> I am using Windows machine (Windows 11) here so it could be Windows specific

* Simply went to [spring.io](https://spring.io) and check [quick start page](https://spring.io/quickstart).
    
* Download and install JDK. I am using [JDK 21 LTS](https://bell-sw.com/pages/downloads/#jdk-21-lts)
    
* Install Extension Pack for Java in VSCode
    
* Once JDK installed, check Windows Environment Variable. Need to add `JAVA_HOME` path from installed JDK in user variable. Check in terminal or powershel with `java —version`. If showed up then ready to go.
    
* Install Extension Pack for Java in VSCode. Then in `settings.json` add this config. If not, the package name would display a red mark although it’s fine.
    

```json
"java.project.sourcePaths": [""]
```

# Generate Spring Project

It’s good to know we don’t have initialize the project from scratch, we can use spring initializr.

![screenshot of spring initializr](https://cdn.hashnode.com/res/hashnode/image/upload/v1728814322333/b14bb5a3-53f1-4a30-810f-af383f7c7e1d.png align="center")

We can define the project attributes here. My setup:

* Gradle
    
* Spring Boot default (3.3.4)
    
* Metadata default (demo)
    
* Packaging default (Jar)
    
* Java 17
    
* `Spring Web` as dependencies because need to build RESTful API
    

`Generate` the code and later just extract the downloaded code.

I also noticed when it opened with VSCode and the extension pack already installed, Gradle will automatically download the dependencies in background so later we don’t have to do it manually.

# First Web Service API

The goal is I want to create a RESTful API that accept `GET /greeting` request and returned JSON response.

```json
{
    "id": 1,
    "content": "Hello, World!"
}
```

To do that, I need to create resource representation class.

> Spring uses [https://github.com/FasterXML/jackson](https://github.com/FasterXML/jackson) that automatically marshal the class into JSON

```java
// /src/main/java/com/example/demo/Greeting.java
package com.example.demo;

public record Greeting(long id, String content) { }
```

Next, create a REST Controller to serve the request.

```java
// /src/main/java/com/example/demo/GreetingController.java
package com.example.demo;

import java.util.concurrent.atomic.AtomicLong;

import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.GetMapping;

@RestController
public class GreetingController {
    private static final String template = "Hello %s!";
    private final AtomicLong counter = new AtomicLong();

    @GetMapping("/greeting")
    public Greeting greeting(@RequestParam(value = "name", defaultValue = "world") String name) {
        return new Greeting(counter.incrementAndGet(), String.format(template, name));
    }
}
```

* `@RestController` annotation to identify that this controller will handle HTTP requests as part of RESTful service.
    
* `@GetMapping(“/greeting“)` annotation it’s like a route, to ensure HTTP request to `GET /greeting` will be handled by `Greeting` function.
    
* `@RequestParam()` annotation for binds the value of the query string parameter `name` into the `name` parameter of the `greeting()` method. In this case if the value empty, default value `world` will be used.
    
* Finally it returned resource `Greeting` that we previously defined.
    

# Running The Service

Go to Terminal and run this command to run the service

```bash
./gradlew bootRun
```

Or we can build the project and execute the `.jar` file

```bash
./gradlew build
java -jar build/libs/demo-0.0.1-SNAPSHOT.jar
```

My first attempt of running `bootRun` was failed. Later that was my mistake because my generated project was set to JDK 17 but I installed JDK 21 instead. Changing the language version in the `toolchain` was solved the problem.

```java
java {
	toolchain {
		languageVersion = JavaLanguageVersion.of(21)
	}
}
```

After the service is running, the API now is accessible at `http://localhost:8080/greeting`

# Tests

Lets digging more to the tests. It’s possible to test the controller using `MockMvc` package. In this case I want to test that `Greeting` controller is giving `200` HTTP Code and proper JSON format.

```java
// src/tests/java/com/example/demo/GreetingControllerTest.java
package com.example.demo;

import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.http.MediaType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;

@SpringBootTest
@AutoConfigureMockMvc
public class GreetingControllerTest {
    @Autowired
    private MockMvc mvc;

    @Test
    public void getGreeting() throws Exception {
        mvc.perform(MockMvcRequestBuilders.get("/greeting").accept(MediaType.APPLICATION_JSON))
            .andExpect(status().isOk())
            .andExpect(jsonPath("$.id").isNumber())
            .andExpect(jsonPath("$.content").isString())
            .andExpect(jsonPath("$.content").value("Hello world!"));
    }

    @Test
    public void getGreetingWithName() throws Exception {
        mvc.perform(MockMvcRequestBuilders.get("/greeting?name=johndoe").accept(MediaType.APPLICATION_JSON))
            .andExpect(status().isOk())
            .andExpect(jsonPath("$.id").isNumber())
            .andExpect(jsonPath("$.content").isString())
            .andExpect(jsonPath("$.content").value("Hello johndoe!"));
    }
}
```

* `@SpringBootTest` annotation tells Spring Boot to look for a main configuration class (one with `@SpringBootApplication`, for instance) and use that to start a Spring application context.
    
* `@AutoConfigureMockMvc` annotation to auto inject `MockMvc` as the test component. It useful to only test the function layer instead of running full server.
    
* `@Autowired` annotation is like a automatic dependency injection for `MockMvc` into the class test
    
* `@Test` annotation to tell Spring that the particular function is a test case. My first attempt I missed this annotation and when I ran the tests, the test case wouldn’t be detected.
    

So by the code above you will know what the expectation of the test case, right?

Running the tests could be achieved at VSCode by navigate to `Testing` Icon on the left and click `Play` icon to run the tests.

![screenshot of running spring tests in VSCode](https://cdn.hashnode.com/res/hashnode/image/upload/v1728823026456/2b4411c2-308b-40b6-8671-497f5a75ffbb.png align="center")

Other approach is using command `./gradlew test`

![screenshot of running spring test using gradlew](https://cdn.hashnode.com/res/hashnode/image/upload/v1728823094450/36de75c5-f776-4c88-93ac-ad54dba8f206.png align="center")

# Code Repository

I already published the full code on this repository [https://github.com/didikz/my-first-spring](https://github.com/didikz/my-first-spring).

Happy building, Folks!
