Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

How to Write Your Own Spring Boot REST Service

DZone's Guide to

How to Write Your Own Spring Boot REST Service

Save time writing framework components and boilerplate code with the Spring Boot REST service.

· Java Zone ·
Free Resource

Secure your Java app or API service quickly and easily with Okta's user authentication and authorization libraries. Developer accounts are free forever. Try Okta Instead.

In this article, we will write our own Spring Boot REST Service from scratch. Spring Boot’s auto-configuration comes in handy when you want to concentrate on your business rather than spend time writing framework components and boilerplate code.

Today, we will create a Simple RESTful Service. So first, let’s write a Dog Service. The quickest way to get on with a Spring Boot project is to use the Spring Initializr.

Tutorial Outline:

  1. Create a Spring Boot project
  2. Mock Data Provider
  3. Create Dogs Controller with the GET, POST, and DELETE methods.
  4. See the Dogs Service running

Note:

  • Use mock repository instead of the actual data store
  • Here is a separate article on Spring REST Service Exception Handling
  • Keep unit tests out of scope. (we will cover testing REST services in a separate tutorial).

1. Create Spring Boot Project

Let’s write our basic project components.

1.1 build.gradle

As of now, we have added spring-boot-starter-web — denoting we want to build a web application — and Lombok dependencies.

Lombok helps to get rid of typical boiler plate code, and I always love using it. I generally use Lombok to avoid writing Constructors, Getters, Setters, etc. Visit Project Lombok for more information.
buildscript {
    ext {
        springBootVersion = '2.1.0.RELEASE'
    }
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
    }
}

apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'

group = 'com.amitph.spring'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = 1.8

repositories {
    mavenCentral()
}


dependencies {
    implementation('org.springframework.boot:spring-boot-starter-web')
    compile('org.projectlombok:lombok:1.18.4')
    testImplementation('org.springframework.boot:spring-boot-starter-test')
}


1.2 Application.java

Here is our starting point — Application.java has the friendly public static void main method, where we can actually start a Spring Boot application.

package com.amitph.spring.dogs;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Application {

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


At this point, you have your Spring Boot application up and running. You can confirm by running the Application.java like any other Java class and see the server being up and listening for port 8080 (configurable).

2. Mock Data Provider

First, let’s start and create the Service and Data layer in the application. As mentioned above, we are not going to have a real data store in the tutorial, but we will use a mock data provider, which will act as a datastore for our needs.

2.1 MockDogProvider

Mock Dog Provider has an instance level pre-populated list of Dogs. The various CRUD methods in the class, actually perform the operation on the Dogs List.

package com.amitph.spring.dogs.repo;

import com.amitph.spring.dogs.model.DogDto;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;

@Component
public class MockDogProvider {
    private List<Dog> mockDogStore;

    public MockDogProvider() {
        mockDogStore = new ArrayList<>();
        mockDogStore.add(Dog.of(1, "Benji", 10));
        mockDogStore.add(Dog.of(2, "Baxter", 9));
        mockDogStore.add(Dog.of(3, "Brinkley", 8));
        mockDogStore.add(Dog.of(4, "Daisy", 10));
        mockDogStore.add(Dog.of(5, "Cujo", 12));
    }

    public List<Dog> getDogs() {
        return mockDogStore;
    }

    public Dog findDogById(long id) {
        for (Dog dog : mockDogStore) {
            if (dog.getId() == id) {
                return dog;
            }
        }
        return null;
    }

    public void add(DogDto dto) {
        mockDogStore.add(Dog.of(dto.getId(), dto.getName(), dto.getAge()));
    }

    public void delete(long id) {
        int idx = 0;
        for (; idx < mockDogStore.size(); idx++) {
            if (mockDogStore.get(idx).getId() == id) {
                break;
            }
        }
        mockDogStore.remove(idx);
    }
}


2.2 DogsService

Dogs service is a routine Service Layer of our web application. It just decouples the controller and data provider. Because no business logic is involved, it just delegates the calls to Data Provider.

3. Controller

We are almost there. What we need in the end is a controller that handles the REST calls and delegate to Service.

package com.amitph.spring.dogs.web;

import com.amitph.spring.dogs.model.DogDto;
import com.amitph.spring.dogs.repo.Dog;
import com.amitph.spring.dogs.service.DogsService;
import lombok.RequiredArgsConstructor;
import lombok.Setter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
@RequestMapping("/dogs")
@RequiredArgsConstructor
@Setter
public class DogsController {
    @Autowired private final DogsService service;

    @GetMapping
    public List<Dog> getDogs() {
        return service.getDogs();
    }

    @PostMapping
    public void postDogs(@RequestBody DogDto dto) {
        service.add(dto);
    }

    @GetMapping("/{id}")
    public Dog getById(@PathVariable(required = true) long id) {
        return service.getDogById(id);
    }

    @DeleteMapping("/{id}")
    public void delete(@PathVariable(required = true) long id) {
        service.delete(id);
    }
}


4. Run the Application

/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.1.0.RELEASE)

2018-11-28 10:04:21.905 INFO 2752 --- [ main] com.amitph.spring.dogs.Application : Starting Application on Amits-office-mac.local with PID 2752 (/Users/aphaltankar/Workspace/personal/dog-service/out/production/classes started by aphaltankar in /Users/aphaltankar/Workspace/personal/dog-service)
2018-11-28 10:04:21.908 INFO 2752 --- [ main] com.amitph.spring.dogs.Application : No active profile set, falling back to default profiles: default
2018-11-28 10:04:22.745 INFO 2752 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http)
2018-11-28 10:04:22.760 INFO 2752 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2018-11-28 10:04:22.760 INFO 2752 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet Engine: Apache Tomcat/9.0.12
2018-11-28 10:04:22.765 INFO 2752 --- [ main] o.a.catalina.core.AprLifecycleListener : The APR based Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path: [/Users/aphaltankar/Library/Java/Extensions:/Library/Java/Extensions:/Network/Library/Java/Extensions:/System/Library/Java/Extensions:/usr/lib/java:.]
2018-11-28 10:04:22.837 INFO 2752 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2018-11-28 10:04:22.837 INFO 2752 --- [ main] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 893 ms
2018-11-28 10:04:22.857 INFO 2752 --- [ main] o.s.b.w.servlet.ServletRegistrationBean : Servlet dispatcherServlet mapped to [/]
2018-11-28 10:04:22.861 INFO 2752 --- [ main] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'characterEncodingFilter' to: [/*]
2018-11-28 10:04:22.861 INFO 2752 --- [ main] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'hiddenHttpMethodFilter' to: [/*]
2018-11-28 10:04:22.861 INFO 2752 --- [ main] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'formContentFilter' to: [/*]
2018-11-28 10:04:22.861 INFO 2752 --- [ main] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'requestContextFilter' to: [/*]
2018-11-28 10:04:23.044 INFO 2752 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor'
2018-11-28 10:04:23.194 INFO 2752 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
2018-11-28 10:04:23.197 INFO 2752 --- [ main] com.amitph.spring.dogs.Application : Started Application in 1.75 seconds (JVM running for 2.44)
2018-11-28 10:05:29.420 INFO 2752 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet'
2018-11-28 10:05:29.420 INFO 2752 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'
2018-11-28 10:05:29.428 INFO 2752 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 8 ms


4.1 Get All Dogs

Open the browser and execute (GET)

http://localhost:8080/dogs

And below is the output:

[
   {
      "id":1,
      "name":"Benji",
      "age":10
   },
   {
      "id":2,
      "name":"Baxter",
      "age":9
   },
   {
      "id":3,
      "name":"Brinkley",
      "age":8
   },
   {
      "id":4,
      "name":"Daisy",
      "age":10
   },
   {
      "id":5,
      "name":"Cujo",
      "age":12
   }
]


4.2 Get Dog by Id

Let’s make a GET request:

http://localhost:8080/dogs/3

Output:

{
   "id":3,
   "name":"Brinkley",
   "age":8
}


4.3 Add New Dog

This is a POST request I will use curl to make this call.

curl -X POST \
  http://localhost:8080/dogs \
  -H 'Content-Type: application/json' \
  -H 'Postman-Token: c6813aea-146c-49cd-9eba-1370aad4bff9' \
  -H 'cache-control: no-cache' \
  -d '{
    "id": 6,
    "name": "Hooch",
    "age": 11
}'


After this execute the GET /dogs again and you will see a new dog has been added.

4.4 Delete a Dog

This a DELETE request using curl here.

curl -X DELETE \
  http://localhost:8080/dogs/5 \
  -H 'Content-Type: application/json' \
  -H 'Postman-Token: b4b93304-7ee7-45c2-917b-c3bc2985a250' \
  -H 'cache-control: no-cache


After this, you should see that Dog with id 5 is gone from the list.

5. Summary

So, we have created our Spring Boot REST Example. We created a Dog Service with a simple Create, GET, and DELETE endpoints. We have seen how easy a service is with Spring Boot where you can skip a lot of crap and concentrate on your business.

In the next article, we will refer to the Same Dog Service and learn Spring REST Service Exception Handling. We will learn how Spring takes care of all the crappy exceptions handling stuff and let us do more important things.

For the full source code of the examples used here, please visit https://github.com/amitrp/dog-service.

Secure your Java app or API service quickly and easily with Okta's user authentication and authorization libraries. Developer accounts are free forever. Try Okta Instead.

Topics:
java ,spring ,spring boot ,rest ,web service ,tutoiral ,technology ,REST service ,tutorial ,spring boot tutorial

Published at DZone with permission of

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}