Esta es la parte final de nuestra descripción general de REST. En las partes anteriores, cubrimos:
Haga clic en el botón "Siguiente". En la siguiente ventana, especifique "Proyecto Maven" como tipo de proyecto, especifique el "Grupo" y el "Artefacto":
Haga clic en el botón "Siguiente". En la siguiente ventana, debemos seleccionar los componentes de Spring Framework necesarios para el proyecto. Spring Web será suficiente para nosotros:
Haga clic en el botón "Siguiente". Ahora todo lo que queda es indicar el nombre del proyecto y su ubicación en el sistema de archivos:
Haga clic en el botón "Finalizar". El proyecto está creado y ahora podemos ver su estructura:
IDEA generó un descriptor de implementación de Maven (pom.xml) y la clase principal de la aplicación (
Haga clic en el botón "Nuevo" en la esquina superior izquierda. A continuación, seleccione "Solicitud":
A continuación, asígnele un nombre y guárdelo. Ahora intentemos enviar una solicitud POST al servidor y crear el primer cliente:
Creamos varios clientes de esta manera. Luego cambiamos el tipo de solicitud a GET y enviamos la solicitud al servidor:

Creando un proyecto
En esta sección, crearemos una pequeña aplicación RESTful usando Spring Boot. Nuestra aplicación implementará operaciones CRUD (Crear, Leer, Actualizar, Eliminar) en los clientes del ejemplo en la parte anterior de la descripción general. Para comenzar, crearemos una nueva aplicación Spring Boot a través del menú: Archivo -> Nuevo -> Proyecto... En la ventana que se abre, seleccione Spring Initializr y especifique el SDK del proyecto:




RestExampleApplication
) para nosotros. Así es como se ven:
pom.xml:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.2.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.codegym.lessons/groupId>
<artifactId>rest_example</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>rest_example</name>
<description>REST example project</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Aplicación de ejemplo de descanso:
@SpringBootApplication
public class RestExampleApplication {
public static void main(String[] args) {
SpringApplication.run(RestExampleApplication.class, args);
}
}
Crear funcionalidad REST
Nuestra aplicación es un sistema de gestión de clientes. Entonces, lo primero que debemos hacer es crear una entidad de cliente. Será una clase POJO (objeto Java simple y antiguo). Cree unmodel
paquete dentro del com.codegym.lessons.rest_example
paquete. Dentro del model
paquete, crea el Customer
:
public class Customer {
private Integer id;
private String name;
private String email;
private String phone;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
}
El servicio implementará operaciones CRUD en los clientes. El siguiente paso es crear un servicio que implementará estas operaciones. En el com.codegym.lessons.rest_example
paquete, cree un service
paquete. Y dentro de eso, crea una CustomerService
interfaz. Aquí está el código de la interfaz con comentarios:
public interface CustomerService {
/**
* Creates a new customer
* @param customer - Customer to be created
*/
void create(Customer customer);
/**
* Returns a list of all existing customers
* @return List of customers
*/
List<Customer> readAll();
/**
* Returns a customer based on its ID
* @param id - Customer ID
* @return - Customer object with the given ID
*/
Customer read(int id);
/**
* Updates the customer with the given ID,
* according to the passed customer
* @param customer - Customer to use to update the data
* @param id - ID of the customer you want to update
* @return - true if the data has been updated, otherwise false
*/
boolean update(Customer customer, int id);
/**
* Deletes the customer with the given ID
* @param id - ID of the customer to be deleted
* @return - true if the customer was deleted, otherwise false
*/
boolean delete(int id);
}
A continuación, necesitamos implementar esta interfaz. Ahora una Map<Integer, Customer>
tienda de nuestros clientes. Las claves del mapa serán los ID de los clientes y los valores serán los propios clientes. Esto se hace para no sobrecargar este ejemplo con las especificaciones de trabajar con una base de datos real. Sin embargo, en el futuro podremos escribir otra implementación de la interfaz, que permitirá conectarse a una base de datos real. En el service
paquete, cree una implementación de la CustomerService
interfaz:
@Service
public class CustomerServiceImpl implements CustomerService {
// Customer repository
private static final Map<Integer, Customer> CUSTOMER_REPOSITORY_MAP = new HashMap<>();
// Variable for generating a customer ID
private static final AtomicInteger CUSTOMER_ID_HOLDER = new AtomicInteger();
@Override
public void create(Customer customer) {
final int customerId = CUSTOMER_ID_HOLDER.incrementAndGet();
customer.setId(customerId);
CUSTOMER_REPOSITORY_MAP.put(customerId, customer);
}
@Override
public List<Customer> readAll() {
return new ArrayList<>(CUSTOMER_REPOSITORY_MAP.values());
}
@Override
public Customer read(int id) {
return CUSTOMER_REPOSITORY_MAP.get(id);
}
@Override
public boolean update(Customer customer, int id) {
if (CUSTOMER_REPOSITORY_MAP.containsKey(id)) {
customer.setId(id);
CUSTOMER_REPOSITORY_MAP.put(id, customer);
return true;
}
return false;
}
@Override
public boolean delete(int id) {
return CUSTOMER_REPOSITORY_MAP.remove(id) != null;
}
}
La @Service
anotación le dice a Spring que esta clase es un servicio. Este es un tipo especial de clase que implementa alguna lógica de aplicación empresarial. Posteriormente, gracias a esta anotación, Spring utilizará la inyección de dependencias para proporcionarnos una instancia de esta clase en todos los lugares donde se necesite. Ahora es el momento de crear un controlador. Esta es una clase especial en la que implementaremos la lógica para procesar las solicitudes de los clientes enviadas a los puntos finales (URI). Para aclarar todo esto, crearemos esta clase de forma incremental. Primero, cree la clase en sí y agregue una dependencia en CustomerService
:
@RestController
public class CustomerController {
private final CustomerService customerService;
@Autowired
public CustomerController(CustomerService customerService) {
this.customerService = customerService;
}
}
Expliquemos las anotaciones: @RestController le dice a Spring que esta clase es un controlador REST. En otras palabras, esta clase implementa la lógica para procesar las solicitudes de los clientes. @Autowired le dice a Spring que se debe agregar una dependencia aquí. Pasamos la CustomerService
interfaz al constructor. Anteriormente, marcamos la implementación de este servicio con la @Service
anotación, y ahora Spring podrá pasar una instancia de esta implementación al constructor del controlador. A continuación, implementaremos cada método de controlador para manejar operaciones CRUD. Comencemos con la operación de creación. Para hacer esto, escribimos un create
método:
@PostMapping(value = "/customers")
public ResponseEntity<?> create(@RequestBody Customer customer) {
customerService.create(customer);
return new ResponseEntity<>(HttpStatus.CREATED);
}
Analicemos este método: @PostMapping(value = "/customers")
significa que este método procesa las solicitudes POST enviadas a la dirección "/clientes". El método devuelve un ResponseEntity<?>
. A ResponseEntity
es una clase especial para devolver respuestas. Más tarde, lo usaremos para devolver un código de estado HTTP al cliente. El método tiene un @RequestBody Customer customer
parámetro. El valor de este parámetro proviene del cuerpo de la solicitud. La @RequestBody
anotación así lo indica. Dentro del cuerpo del método, llamamos al create()
método en el servicio creado previamente y lo pasamos al controlador del cliente recibido en los parámetros. Luego devolvemos el estado "201 Creado" creando un nuevo ResponseEntity
objeto y pasándole el HttpStatus
campo de enumeración correspondiente. A continuación, implementaremos elread
operación: Primero, implementaremos la operación para obtener una lista de todos los clientes disponibles:
@GetMapping(value = "/customers")
public ResponseEntity<List<Customer>> read() {
final List<Customer> customers = customerService.readAll();
return customers != null && !customers.isEmpty()
? new ResponseEntity<>(customers, HttpStatus.OK)
: new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
Profundicemos: @GetMapping(value = "/customers")
todo aquí es similar a la @PostMapping
anotación, pero ahora estamos procesando solicitudes GET. Esta vez devolvemos un ResponseEntity<List<Customer>>
, y además de un estado HTTP, también devolveremos un cuerpo de respuesta, que será la lista de clientes. En los controladores REST de Spring, todo son objetos POJO y colecciones de objetos POJO, que se devuelven como cuerpos de respuesta y se serializan automáticamente en JSON, a menos que se especifique lo contrario. Esto nos queda perfecto. Dentro del método, usamos nuestro servicio para obtener una lista de todos los clientes. Luego, si la lista no es nula y no está vacía, entonces usamos elResponseEntity
class para devolver la lista de clientes y el código de estado HTTP "200 OK". De lo contrario, simplemente devolvemos el código de estado HTTP "404 Not Found". Ahora implementaremos la capacidad de obtener un cliente usando su ID:
@GetMapping(value = "/customers/{id}")
public ResponseEntity<Customer> read(@PathVariable(name = "id") int id) {
final Customer customer = customerService.read(id);
return customer != null
? new ResponseEntity<>(customer, HttpStatus.OK)
: new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
Una cosa nueva aquí es la variable de ruta. La variable se define en la URI: value = "/customers/{id}"
. Lo indicamos entre llaves. Y lo recibimos como un int
parámetro de método usando la @PathVariable(name = "id")
anotación. Este método aceptará solicitudes enviadas a URI en el formulario /customers/{id}
, donde {id}
representa cualquier valor numérico. Este valor se pasa posteriormente a través de la int id
variable al parámetro de método. En el cuerpo, obtenemos el Customer
objeto usando nuestro servicio y el recibido id
. Y luego, por analogía con la lista, devolvemos el estado "200 OK" y el Customer
objeto en sí, o simplemente el estado "404 No encontrado" si el sistema no tiene ningún cliente con ese id
. Todavía necesitamos implementar dos operaciones: actualizar y eliminar. Aquí está el código para estos métodos:
@PutMapping(value = "/customers/{id}")
public ResponseEntity<?> update(@PathVariable(name = "id") int id, @RequestBody Customer customer) {
final boolean updated = customerService.update(customer, id);
return updated
? new ResponseEntity<>(HttpStatus.OK)
: new ResponseEntity<>(HttpStatus.NOT_MODIFIED);
}
@DeleteMapping(value = "/customers/{id}")
public ResponseEntity<?> delete(@PathVariable(name = "id") int id) {
final boolean deleted = customerService.delete(id);
return deleted
? new ResponseEntity<>(HttpStatus.OK)
: new ResponseEntity<>(HttpStatus.NOT_MODIFIED);
}
No hay nada esencialmente nuevo en estos métodos, por lo que omitiremos la descripción detallada. Lo único que vale la pena mencionar es que el update()
método maneja las solicitudes PUT ( @PutMapping
anotación) y el delete()
método maneja las solicitudes DELETE ( DeleteMapping
anotación). Aquí está el código completo para el controlador:
@RestController
public class CustomerController {
private final CustomerService customerService;
@Autowired
public CustomerController(CustomerService customerService) {
this.customerService = customerService;
}
@PostMapping(value = "/customers")
public ResponseEntity<?> create(@RequestBody Customer customer) {
customerService.create(customer);
return new ResponseEntity<>(HttpStatus.CREATED);
}
@GetMapping(value = "/customers")
public ResponseEntity<List<Customer>> read() {
final List<Customer> customers = customerService.readAll();
return customers != null && !customers.isEmpty()
? new ResponseEntity<>(customers, HttpStatus.OK)
: new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
@GetMapping(value = "/customers/{id}")
public ResponseEntity<Customer> read(@PathVariable(name = "id") int id) {
final Customer customer = customerService.read(id);
return customer != null
? new ResponseEntity<>(customer, HttpStatus.OK)
: new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
@PutMapping(value = "/customers/{id}")
public ResponseEntity<?> update(@PathVariable(name = "id") int id, @RequestBody Customer customer) {
final boolean updated = customerService.update(customer, id);
return updated
? new ResponseEntity<>(HttpStatus.OK)
: new ResponseEntity<>(HttpStatus.NOT_MODIFIED);
}
@DeleteMapping(value = "/customers/{id}")
public ResponseEntity<?> delete(@PathVariable(name = "id") int id) {
final boolean deleted = customerService.delete(id);
return deleted
? new ResponseEntity<>(HttpStatus.OK)
: new ResponseEntity<>(HttpStatus.NOT_MODIFIED);
}
}
Como resultado, la estructura de nuestro proyecto es la siguiente: 
Lanzamiento y prueba
Para iniciar nuestra aplicación, simplemente ejecute elmain()
método en la RestExampleApplication
clase. Pero para probar los servicios web RESTful, necesitamos descargar software adicional. El hecho es que las solicitudes GET son bastante simples de enviar desde un navegador común, pero un navegador común no puede enviar solicitudes POST, PUT y DELETE. No te preocupes: puedes usar un programa llamado Postman para enviar cualquier solicitud HTTP. Puedes descargarlo aquí . Después de descargar e instalar Postman, comenzamos a probar nuestra aplicación. Para hacer esto, abra el programa y cree una nueva solicitud: 



Resumen
¡Felicidades! Hemos cubierto lo suficiente REST. Hubo un gran volumen de material, pero espero que haya sido útil para usted:-
Aprendimos qué es REST.
-
Aprendimos cómo nació REST.
-
Hablamos sobre las limitaciones y los principios detrás de este estilo arquitectónico:
- arquitectura cliente-servidor
- apátrida
- almacenamiento en caché
- interfaz uniforme
- capas
- código bajo demanda (opcional)
-
Exploramos los beneficios proporcionados por REST
-
Examinamos en detalle cómo el servidor y el cliente interactúan entre sí a través del protocolo HTTP.
-
Echamos un vistazo más de cerca a las solicitudes y respuestas. Diseccionamos sus partes constituyentes.
-
Finalmente, obtuvimos algo de experiencia práctica al escribir nuestra propia aplicación RESTful pequeña usando Spring Boot. E incluso aprendimos a probarlo usando Postman.
Tarea
Prueba lo siguiente:- Siguiendo la descripción anterior, cree su propio proyecto Spring Boot e implemente la misma lógica que en la lección. Repite todo exactamente.
- Iniciar la aplicacion.
- Descargue y configure Postman (o cualquier otra herramienta para enviar solicitudes, por ejemplo, curl).
- Pruebe las solicitudes POST y GET de la misma manera que se describe en la lección.
- Pruebe las solicitudes PUT y DELETE usted mismo.
GO TO FULL VERSION