90% of the time services does CRUD operations with REST over HTTP protocol so in this post we'll look into different HTTP methods and annotations we can use to communicate with the service to perform crud operations.
We'll be building a simple todo API where you can:
- Create a todo (method: HTTP POST, endpoint: **/api/1/0/todos)
- Read list of todos (method: HTTP GET, endpoint: **/api/1/0/todos)
- Read a single todo (method: HTTP GET, endpoint: **/api/1/0/todos/{id})
- Delete a todo (method: HTTP DELETE, endpoint: **/api/1/0/todos/{id})
**To keep things simple and not shift the focus out of the controller class, we will store all these todos in in-memory using a simple Map
controller code using java:
package com.artifactsbyrake.restdemo.controller; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.util.ObjectUtils; import org.springframework.web.bind.annotation.*; import org.springframework.web.server.ResponseStatusException; import org.springframework.web.servlet.support.ServletUriComponentsBuilder; import java.net.URI; import java.util.HashMap; import java.util.Map; import java.util.stream.IntStream; @RestController @RequestMapping("/api/1/0") public class TodoController { private int seq = 1; private Map<Integer, String> todos = createDefaultTodos(); private Map<Integer, String> createDefaultTodos() { Map todoMap = new HashMap(); IntStream .range(seq, 5) .forEach(i -> { seq = i; String todo = "Todo - " + seq; todoMap.put(seq, todo); }); return todoMap; } @GetMapping("/hello") public String sayHello() { return "Hello Rest demo"; } @GetMapping("/todos") public ResponseEntity<Map> getListOfTodos() { return ResponseEntity.ok(todos); } @GetMapping("/todos/{id}") public ResponseEntity<String> getTodo(@PathVariable int id) { if (id < 0) throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Invalid ID - Please provide a valid ID and retry"); if (!todos.containsKey(id)) throw new ResponseStatusException(HttpStatus.NOT_FOUND, "No todo found with ID"); return ResponseEntity.ok(todos.get(id)); } @PostMapping("/todos") public ResponseEntity<Object> addTodo(@RequestBody String todo) { if (ObjectUtils.isEmpty(todo)) throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Empty todo"); todos.put(++seq, todo + " - " + seq); URI todoLoc = ServletUriComponentsBuilder.fromCurrentRequest() .path("/{id}") .buildAndExpand(seq) .toUri(); return ResponseEntity.created(todoLoc).build(); } @DeleteMapping("/todos/{id}") public ResponseEntity<Object> deleteTodo(@PathVariable int id) { if (id < 0) throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Invalid ID - Please provide a valid ID and retry"); if (!todos.containsKey(id)) throw new ResponseStatusException(HttpStatus.NOT_FOUND, "No todo found with ID"); todos.remove(id); return ResponseEntity.noContent().build(); } }
Whenever you hit a HTTP request (http://localhost:9000/api/1/0/todos), Spring handles the request using controllers which are usually annotated with @RestController
@RequestMapping
- This annotation is used to map requests onto a class or method which can handle the request.
- These days this annotation is used mostly at class level and specific composed annotations like @GetMapping are used at method level
@GetMapping, @PutMapping, @PostMapping...
- These annotations are used mostly at method level to map requests onto specific handler methods which can handle those GET, PUT and POST requests
ResponseEntity<Type>
- This is the extension of HttpEntity along with an HttpStatus code
- As shown in the code ResponseEntity.ok(todos.get(id)); you can set the standard HttpStatus codes to communicate the status of the request
ResponseStatusException
- You throw this exception when you want to communicate any scenario to the client where you're not able to complete the request
You can find source code here
Happy Coding 👨💻
Comments
Post a Comment