llms.txt: machine-readable documentation index. Markdown version of this page is also available.

IntelliJ IDEA 2026.3 Help

Spring Boot REST API tutorial, part 2: Add GET and DELETE endpoints

Continue the project from Spring Boot REST API tutorial, part 1: Create and run a project. In this part, add a photo model, a service that stores photos in memory, and endpoints to list, retrieve, and delete them.

Create the Photo model class

The greeting endpoint returns a string, but the photo endpoints need to work with structured data. A Photo represents that data in Java. It starts with an identifier and a file name; the image bytes arrive in the next part, when you add uploads.

  1. In the model package, create a class named Photo with an identifier, a file name, and two constructors:

    public class Photo { private String id; private String fileName; public Photo() { } public Photo(String id, String fileName) { this.id = id; this.fileName = fileName; } }

    The two-argument constructor creates the example photo used below. The no-argument constructor is used when adding uploaded photos in the next part.

  2. Generate accessors for both fields: place the caret inside the class, press Alt+Insert, select Getter and Setter, then select both fields, and click OK.

    Generate popup open in the Photo class with Getter and Setter selected to create accessor methods for the id and fileName fields.

    Spring uses Jackson to convert the photos returned by your endpoints into JSON. Jackson reads the photo properties through the getters, so the JSON response includes id and fileName. The setters let you assign these values when creating photos.

Create and inject a photo service

A controller translates an HTTP request into a call, and a result back into a response. Create a service to store the photos that PhotosController will return.

In the next part, you will add a second controller to serve image downloads. Both controllers will need the same photos. Giving each its own map would leave the application with two separate sets of photos, so both will use the same service.

The service also becomes the place for logic that is not HTTP translation, such as building a photo out of an uploaded file. Both controllers can use this service, and the service can switch from a map to a database without putting database operations in either controller.

  1. In the service package, create PhotosService:

    @Service public class PhotosService { private final Map<String, Photo> db = new HashMap<>(); public PhotosService() { db.put("1", new Photo("1", "hello.jpg")); } public Collection<Photo> get() { return db.values(); } public Photo get(String id) { return db.get(id); } public Photo remove(String id) { return db.remove(id); } }

    Use the java.util imports for Map, HashMap, and Collection, and import Photo from your model package that IntelliJ IDEA suggests.

    @Service tells Spring to create an instance at startup, the same way @RestController does. The map stores photos by identifier, so retrieving or removing one does not require searching a list. It starts with one example, hello.jpg, to give the endpoints something to return. This is metadata only, there is no image file yet.

  2. In PhotosController, add a field and a constructor for the service. Keep the hello() method:

    private final PhotosService photosService; public PhotosController(PhotosService photosService) { this.photosService = photosService; }

    Nothing calls this constructor in your code. At startup Spring sees that PhotosController requires a PhotosService, finds the class annotated with @Service, creates one instance, and passes it in. This is constructor injection, and one instance is created and shared — which is what lets the second controller see the same photos in the next part.

Add a GET endpoint for all photos

The model and storage are in place. The first photo endpoint connects them to the browser by asking the service for all stored photos and returning the result.

  1. In PhotosController, add a method for GET requests mapped to /photos:

    @GetMapping("/photos") public Collection<Photo> get() { return photosService.get(); }
  2. Restart the application: click the Rerun button Rerun in the Run tool window. Then open http://localhost:8080/photos. The browser shows a JSON array holding the one photo:

    [{"fileName":"hello.jpg","id":"1"}]
    Browser at localhost:8080/photos showing a JSON array with one photo object that has the identifier 1 and the file name hello.jpg.

    Nothing in the method explicitly creates JSON. It returns a Java collection, and because the class is a @RestController, Spring converts the return value into the response. The getters you generated provide the photo properties that appear in the JSON array.

Add a GET endpoint for one photo

  1. Add another get() method to PhotosController:

    @GetMapping("/photos/{id}") public Photo get(@PathVariable String id) { Photo photo = photosService.get(id); if (photo == null) { throw new ResponseStatusException(HttpStatus.NOT_FOUND); } return photo; }

    The braces in /photos/{id} identify a variable part of the path. @PathVariable passes it into the parameter with the same name, so a request for /photos/1 looks up the photo with identifier 1.

    The service returns null when it finds no photo. The controller turns that absence into 404 Not Found by throwing ResponseStatusException. This keeps the HTTP response handling in the controller.

  2. Restart the application and open http://localhost:8080/photos/1 to see the photo as a JSON object. Open http://localhost:8080/photos/2 to check the 404 response. Because there is no photo with this identifier, the browser shows the default Spring Boot Whitelabel Error Page with the type=Not Found, status=404 message.

    Whitelabel Error Page at localhost:8080/photos/2 with a Not Found error and status 404 because no photo with this identifier exists.

Add a DELETE endpoint

  1. Add a method for DELETE requests to PhotosController:

    @DeleteMapping("/photos/{id}") public void delete(@PathVariable String id) { Photo photo = photosService.remove(id); if (photo == null) { throw new ResponseStatusException(HttpStatus.NOT_FOUND); } }

    @DeleteMapping handles a different HTTP verb on the same path. The service returns the removed photo, or null if it was absent, which the controller turns into a 404.

  2. Restart the application and open http://localhost:8080/photos.

    Open the browser developer tools, and switch to the Console tab.

    Send a DELETE request for the photo that exists:

    (async function deletePhoto(id) { await fetch("http://localhost:8080/photos/" + id, { method: "DELETE" }) })("1")
    Browser developer tools Console tab with an async fetch call that sends a DELETE request to http://localhost:8080/photos/1.

    Reload http://localhost:8080/photos. The list is now empty: [].

    Browser at http://localhost:8080/photos showing an empty JSON array after the DELETE request removed photo 1.

Next part

15 October 2026