Representational State Transfer is an architectural style for distributed hypermedia systems.
Properties link RESTful systems have the following properties:
Client-Server: Server provides an independent service to clients. Stateless: No state should be saved by either the server nor the client between requests. Cacheable: Responses should be cached. Uniform Interface: The interface should be uniform. Layered System: The system should be layered (the user should only have one interface). Code on Demand (optional): The server can provide executable code to the client. Richardson Maturity Model link The Richardson Maturity Model (RMM) is a model for classifying RESTful systems.
Level 0: Swamp of POX link Level 0 is the lowest level of the RMM.
It is characterized by the use of HTTP as a transport protocol for remote procedure calls (RPC).
Level 1: Resources link Level 1 is characterized by the use of resources.
Resources are identified by URIs.
Level 2: HTTP Verbs link Level 2 is characterized by the use of HTTP verbs.
HTTP verbs are used to specify the action that should be performed on a resource.
HTTP status codes are used to indicate the result of the action.
Level 3 is characterized by the use of hypermedia controls.
Hypermedia controls are links that are embedded in the response.
They allow the client to navigate the API.
RESTful APIs link RESTful APIs can be implemented with Spring Boot.
The following example shows a simple RESTful API that allows users to create, read, update and delete (CRUD) notes.
The note class is a simple POJO with a title and a content.
public class Note {
@Size(min = 1, max = 100)
@NotNull
private String title;
@Size(min = 1, max = 1000)
@NotNull
private String content;
public Note() {}
public Note(String title, String content) {
this.title = title;
this.content = content;
}
public String getTitle() {
return title;
}
public String getContent() {
return content;
}
public void setTitle(String title) {
this.title = title;
}
public void setContent(String content) {
this.content = content;
}
}
The NoteController class is a simple controller that handles requests to the /notes endpoint.
@RestController
public class NoteController {
// use a simple list as persistance layer
private final List<Note> notes = new ArrayList<>();
@GetMapping("/notes")
public ResponseEntity<List<Note>> getNotes() {
return ResponseEntity.ok().body(notes);
}
@PostMapping("/notes")
public ResponseEntity<Note> createNote(@Valid @RequestBody Note note, BindingResult bindingResult) {
if (bindingResult.hasErrors())
return ResponseEntity.badRequest().build();
if (notes.add(note))
return ResponseEntity.ok().body(note);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
}
@GetMapping("/notes/{title}")
public ResponseEntity<Note> getNoteByTitle(@PathVariable String title) {
return notes.stream()
.filter(note -> note.getTitle().equals(title))
.findFirst()
.map(note -> ResponseEntity.ok().body(note))
.orElse(ResponseEntity.notFound().build());
}
@PutMapping("/notes/{title}")
public ResponseEntity<Note> updateNoteByTitle(@PathVariable String title, @Valid @RequestBody Note updatedNote, BindingResult bindingResult) {
if (bindingResult.hasErrors())
return ResponseEntity.badRequest().build();
ResponseEntity<Note> response = getNoteByTitle(title);
if (response.getStatusCode().isError())
return response;
Note note = response.getBody();
note.setTitle(updatedNote.getTitle());
note.setContent(updatedNote.getContent());
return ResponseEntity.ok().body(note);
}
@DeleteMapping("/notes/{title}")
public ResponseEntity<Note> deleteNoteByTitle(@PathVariable String title) {
if (notes.removeIf(note -> note.getTitle().equals(title)))
return ResponseEntity.noContent().build();
return ResponseEntity.notFound().build();
}
}
The Application class is a simple Spring Boot application.
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}