DEV Community

scottshipp
scottshipp

Posted on • Edited on

Build a next-level RESTful web service with Spring Boot

The easiest way to learn how to use Spring Boot is hands-on with the Building a RESTful Web Service in Spring Boot Quickstart found on the Spring Boot web site.

In this post, we build on top of the result in order to take it to the next level!

So before you continue, please go through the Quickstart and then come back to here.

Building the next level

At this point you have a Spring Boot-based RESTful web service running on your machine. You can visit http://localhost:8080/greeting and you will see:

{"id":2,"content":"Hello, World!"}
Enter fullscreen mode Exit fullscreen mode

You can also visit http://localhost:8080/greeting?name=User and you will see:

{"id":3,"content":"Hello, User!"}
Enter fullscreen mode Exit fullscreen mode

Now, wouldn’t it be nice to be able to change the greeting? Instead of, “Hello, User!” what if it could say something like any of these examples:

  • Greetings, User!
  • Welcome, User!
  • Good Afternoon, User!

Adding a PUT

In order to change the greeting, we will use the PUT HTTP verb. It’s important to use the right verb when making RESTful web services, and PUT is typically what is used to update an existing resource. Since we can GET the /greeting resource right now, changing it will be an update rather than a create, and PUT is what we should use.

The PUT cannot be made easily with a web browser. Instead we will use the useful cURL command-line utility. Here is the cURL command that we can use. This can be executed within a terminal window.

$ curl -X PUT -d template='Welcome' localhost:8080/greeting
Enter fullscreen mode Exit fullscreen mode

Of course, this won’t work yet! But we will make it work in a moment below.

First, let me quickly explain, what the curl will do:

  • We start by calling curl
  • We pass “-X PUT” to tell it to make a put command
  • We pass “-d template=’Welcome'” in order to pass the “data” for the PUT command, and the data we pass is the new template String, passed as a key value pair.
  • Finally we supply the resource, “localhost:8080/greeting”

Preparing the existing code

Right now the existing GreetingController.java in the project only has a “GetMapping.” As you may have guessed, we will add a “PutMapping.” Since both will use the underlying logic to construct a “Greeting” and return it, we should do a slight refactor before adding the PutMapping. The refactor accomplishes the following:

  1. Change the method that is currently annotated with the GetMapping to call a separate private method to get the result.
  2. Change the template variable in the class to be a member of the class that can be changed, by removing the final keyword.
  3. Also, let’s stop using String.format because it will be confusing for people using our service to have to use Java-specific String formatting. Besides, the “%” symbol that is used will be confusing at best and a problem at worst since it is used in URIs to mean something else. So refactor the new private method to just use normal Java String concatenation. This way the “template” can be one of our previously mentioned options like “Welcome” or “Greeting” and the rest of the greeting can be constructed from the supplied name.

We end up with the following class:

package com.scottshipp.code.restservice;

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

import java.util.concurrent.atomic.AtomicLong;

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

    @GetMapping("/greeting")
    public Greeting greeting(@RequestParam(value = "name", defaultValue = "World") String name) {
        return customizeGreeting(name);
    }

    private Greeting customizeGreeting(String name) {
        return new Greeting(counter.incrementAndGet(), template + ", " + name);
    }
}
Enter fullscreen mode Exit fullscreen mode

Once you’ve made that refactor, it’s a good idea to pause at this point, rebuild the project, run it, and test it to see if it still performs the desired functionality. You can follow the section titled “Test the service” in the original tutorial to test this. When you are done, stop the service.

Adding a PUT mapping

Next, we will add a new method that sets a new value for the template variable.

    private Greeting customizeGreeting(String template, String name) {
        return new Greeting(counter.incrementAndGet(), template + ", " + name);
    }
Enter fullscreen mode Exit fullscreen mode

Since this duplicates the existing method somewhat, we can refer to the new method but preserve the existing behavior:

    private Greeting customizeGreeting(String name) {
        return customizeGreeting("Hello", name);
    }
Enter fullscreen mode Exit fullscreen mode

Now we just need a method to handle a PUT request. It iwll be annotated with “@PutMapping.” The new method looks like this:

@PutMapping
public ResponseEntity<Greeting> update(String template) {
  return customizeGreeting(template, "World");
}
Enter fullscreen mode Exit fullscreen mode

Simply by annotating this method with “@PutMapping(“/greeting”)” will now allow your web service to accept a PUT request at that URI. Because the variable the method takes is a String called “template,” the curl command we issue will pass data in the “-d” flag with the key name “template.”

After you’ve added the above method to your controller class, it should now look like this new full class:

package com.scottshipp.code.restservice;

import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.concurrent.atomic.AtomicLong;

@RestController
@RequestMapping("/greeting")
public class GreetingController {
    private static String template = "Hello";
    private final AtomicLong counter = new AtomicLong();

    @GetMapping
    public Greeting greeting(@RequestParam(value = "name", defaultValue = "World") String name) {
        return customizeGreeting(name);
    }

    @PutMapping
    public ResponseEntity<Greeting> update(String template) {
        return customizeGreeting(template, "World");
    }

    private Greeting customizeGreeting(String name) {
        return customizeGreeting("Hello", name);
    }

    private Greeting customizeGreeting(String template, String name) {
        return new Greeting(counter.incrementAndGet(), template + ", " + name);
    }
}
Enter fullscreen mode Exit fullscreen mode

Test the service

Now run the service according to the Test the service section of the original tutorial. While the service is running, issue the curl command in a separate terminal:

$ curl -X PUT -d template='Greetings' localhost:8080/greeting
Enter fullscreen mode Exit fullscreen mode

You should see the same response you would have seen with a GET request, only now using the new template:

{"id":1,"content":"Greetings, World"}
Enter fullscreen mode Exit fullscreen mode

When you issue any subsequent GET requests, you will find that the greeting will use the new template.

$ curl localhost:8080/greeting?name=Earthlings
Enter fullscreen mode Exit fullscreen mode
{"id":2,"content":"Greetings, Earthlings"}
Enter fullscreen mode Exit fullscreen mode

Congratulations

Congratulations! You just took your RESTful web service building skills in Spring Boot to the next level! Consider trying to add another HTTP verb like POST to your controller.

Top comments (0)