Cree una API REST de Spring Boot con Java - Guía completa

En este tutorial, crearemos una aplicación de API REST Spring Boot de demostración, con funcionalidad CRUD. Cubriremos la configuración de la base de datos, el modelo de dominio, la capa de persistencia y la capa empresarial.

Introducción

REST significa Representational State Transfer, un enfoque estandarizado para crear servicios web.

Una API REST es una Interfaz de programación de aplicaciones intermediaria que permite que dos aplicaciones se comuniquen entre sí a través de HTTP, de forma muy similar a como los servidores se comunican con los navegadores.

RESTful es el enfoque más común para construir servicios web debido a lo fácil que es aprender y construir.

Supongamos que pide algo en un restaurante de comida rápida y el cajero le solicita la información necesaria para procesar su pedido. Una vez procesado, te entregan el pedido que solicitaste. Esta transacción es un ejemplo de la vida real de cómo funciona la API REST.

En este tutorial, repasaremos cómo crear una API REST en Java con Spring Boot. Aceptará las cargas útiles de solicitud POST y GET para ver y agregar entradas de una entidad - Usuario.

Requisitos

  • IDE o editor de texto
  • JDK 1.8+
  • Experto 3+ o gradle 4+ (Estaremos confiando en Experto para este artículo)

Inicializar un proyecto Spring Boot

Usando Spring Initializr

Una manera fácil de inicializar un nuevo proyecto Spring Boot es usando Spring Initializr, que genera automáticamente un proyecto básico de Spring Boot para usted:

spring initializr

Agregaremos algunas dependencias aquí también, ya que querremos usarlas en nuestro proyecto:

  • Spring Web - Para incluir Spring MVC y Tomcat integrado en su proyecto
  • Spring Data JPA - API de persistencia de Java e Hibernate
  • Spring Boot DevTools - Herramientas de desarrollo muy útiles
  • Controlador MySQL - Controlador JDBC (Puede ser cualquier base de datos que le gustaría usar)

Luego, presiona generar. A continuación, se descargará un archivo zip que contiene el proyecto generado.

Usando Spring CLI

Si tiene Primavera CLI instalado, entonces puede optar por usar la consola para construir su proyecto base usando este comando:

1
spring init --build=maven -p=jar UserDemo

Nota: Spring CLI llama directamente a Spring Initializr para realizar esta operación. Ambas opciones producirán el mismo proyecto.

Después de construir su proyecto base, descárguelo e impórtelo a su IDE o editor de texto de su elección. Si desea construir, compilar y ejecutar su aplicación a través de su IDE, asegúrese de importarla como un proyecto Maven o Gradle.

Al importar, la base pom.xml generada en su proyecto se verá así:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<!-- Project information-->
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
        <scope>runtime</scope>
        <optional>true</optional>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</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 information -->

Todas las configuraciones que hiciste se verán reflejadas en este archivo. Además de eso, las dependencias predeterminadas, su instantánea base 0.0.1-SNAPSHOT y el complemento de compilación de Maven también se configuran automáticamente.

Como referencia, si desea crear un Proyecto Gradle, su build.gradle se verá así:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
plugins {
    id 'org.springframework.boot' version '2.3.5.RELEASE'
    id 'io.spring.dependency-management' version '1.0.10.RELEASE'
    id 'java'
}

group = 'com.howto'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '11'

repositories {
    mavenCentral()
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    implementation 'org.springframework.boot:spring-boot-starter-web'
    developmentOnly 'org.springframework.boot:spring-boot-devtools'
    runtimeOnly 'com.mysql:mysql-connector-java'
    testImplementation('org.springframework.boot:spring-boot-starter-test') {
        exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
    }
}

test {
    useJUnitPlatform()
}

Conexión de Spring Boot a la base de datos {#conexión de Spring Boot a la base de datos}

A continuación, antes de comenzar a trabajar en la aplicación, querremos configurar la base de datos. Esto se puede hacer fácilmente a través de Spring Data JPA, que nos permite configurar esta conexión con solo un par de parámetros.

Abstrae todo lo que el desarrollador debe hacer y nos permite cambiar las bases de datos subyacentes si lo deseamos, simplemente cambiando un par de propiedades.

Para decirle a Spring cómo conectarse a su base de datos preferida, en su archivo application.properties, deberá agregar información rudimentaria:

1
2
3
4
5
spring.datasource.url = jdbc:mysql://localhost:3306/user
spring.datasource.username = user
spring.datasource.password = user
spring.jpa.hibernate.ddl-auto = update
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5Dialect

Aquí, hemos configurado datasource.url en nuestra URL de conexión JDBC. Esto depende de su base de datos. Hemos proporcionado el ’nombre de usuario’ y la ‘contraseña’ necesarios para autenticarse en esa base de datos, así como configurar la propiedad ‘ddl-auto’ para ‘actualizar’. La propiedad jpa.hibernate.ddl-auto influye directamente en la propiedad hibernate.hbm2ddl.auto y esencialmente define cómo Hibernate debe manejar la administración de herramientas de esquema.

Para las aplicaciones de producción, este valor normalmente se establece en ninguno, ya que el personal dedicado realiza la gestión. En desarrollo, es más común usar actualizar, para permitir que el esquema se actualice cada vez que reinicia la aplicación, lo que le brinda flexibilidad mientras trabaja en el desarrollo.

Finalmente, hemos configurado la propiedad hibernate.dialect. Hibernate tiene diferentes dialectos para diferentes bases de datos. Puede establecer automáticamente el dialecto en función de su configuración, aunque, para mayor seguridad, siempre es una buena idea especificarlo explícitamente.

Modelo de dominio: creación de un modelo de usuario

Ahora que la conexión de la base de datos está funcionando, podemos continuar y saltar al Modelo de dominio. Este es un conjunto de clases, o más bien modelos, que usaremos en nuestra aplicación. Con Hibernate, también se denominan Entidades, y se anotan con la anotación @Entity.

Cada @Entidad es recogida por Hibernate, se crea una tabla para ella, se mapean los campos y se convierte en una entidad administrada para la base de datos que ha configurado.

Primero, vamos a crear una entidad Usuario simple. Anotaremos la clase con @Entity y la anotación opcional @Table para especificar el nombre de nuestra tabla.

Si no se configura, solo usará el mismo nombre que la clase:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
@Entity
@Table(name = "user")
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long id;
    private String name;

    // Constructor, getters and setters   
}

Para anotar un campo como el id de una entidad, utilice la anotación @Id, y se establecerá como la clave principal de incremento automático de la tabla. Además, también puede establecer que sea un @GeneratedValue y establecer GenerationType en AUTO.

Esta es la configuración predeterminada, si omite la anotación @GeneratedValue. Otros valores que puede establecer son IDENTIDAD, SECUENCIA y TABLA. Estos justifican un artículo propio en Hibernate.

Además, puede establecer anotaciones @Column para cada uno de los campos, proporcionando un nombre para cada uno de ellos si desea nombres personalizados - @Column(name = "user_id"), guardaría el id campo como user_id en lugar de solo id.

Si desea automatizar la generación de constructores, getters y setters y simplemente evitar el código repetitivo en su totalidad, puede usar herramientas ingeniosas como [Lombok](/proyecto-lombok-reduciendo-el-codigo-repetitivo-de- Java/).

Esta clase (entidad) ahora está registrada con Hibernate. Si ejecutamos la aplicación, teniendo en cuenta nuestra configuración ddl-auto, la tabla aparecerá en su base de datos respectiva, con la tabla y las asignaciones correctas para los tipos de datos.

Capa de persistencia: creación de clases de repositorio

A continuación, trabajemos en la capa de persistencia. Querremos tener un UserRepository para realizar operaciones CRUD en nuestras entidades User. Para hacer esto, especificaremos una interfaz que extienda CrudRepository y la anotaremos con @Repository.

@Repository es una variante de la anotación @Component, que le permite a Spring saber que es un componente que debe ser administrado por el contenedor IoC. Específicamente, los repositorios están destinados a definir la lógica para la capa de persistencia.

La extensión CrudRepository acepta la clase de entidad, así como el tipo de datos id que debe usar para consultar:

1
2
@Repository
public interface UserRepository extends CrudRepository<User, Long> {}

CrudRepository declara métodos como findAll(), findOne() y save() que constituyen la funcionalidad CRUD básica de un repositorio. Puede usar este UserRepository tal como está, para realizar operaciones CRUD en entidades User ahora, sin necesidad de configuración adicional.

Puede * anular parte de este comportamiento, si lo desea, sin embargo, se configura automáticamente para ayudarlo a iniciar algunas funciones básicas.

Business Layer: creación de un controlador

Finalmente, hemos llegado a la capa comercial, donde implementamos la lógica comercial real de procesamiento de información y usamos los componentes de la capa de persistencia, junto con el modelo de dominio para almacenar datos.

Vamos a crear un controlador, márcalo como @RestController, ya que estamos creando una API REST, y agrégale @RequestMapping. @RestController es solo una combinación de @Controller y @ResponseBody, lo que significa que en lugar de mostrar páginas, solo responderá con los datos que le hemos dado. Esto es natural para las API REST: devolver información una vez que se ha alcanzado un punto final de la API.

Si quieres leer más sobre @RequestMapping y sus variantes derivadas, tenemos un gran artículo dedicado precisamente a eso ¡tema!

Avancemos y hagamos un UserController:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
@RestController
@RequestMapping("/api/user")
public class UserController {

    @Autowired
    private UserRepository userRepository;
        
    @GetMapping
    public List<User> findAllUsers() {
        // Implement
    }

    @GetMapping("/{id}")
    public ResponseEntity<User> findUserById(@PathVariable(value = "id") long id) {
       // Implement
    }

    @PostMapping
    public User saveUser(@Validated @RequestBody User user) {
        // Implement
    }
}

Tenemos @Autowired nuestro UserRepository. Se usa para inyección de dependencia, ya que la clase de repositorio es una dependencia aquí.

If you'd like to read more about Anotaciones de Core Spring Framework, check out our guide!

También hemos usado las anotaciones @GetMapping y @PostMapping para especificar qué tipos de solicitudes HTTP aceptan y manejan nuestros métodos. Estas son variantes derivadas de la anotación @RequestMapping, con method = RequestMethod.METHOD establecido para los tipos respectivos.

Comencemos con la implementación del punto final findAll():

1
2
3
4
@GetMapping
public List<User> findAllUsers() {
    return userRepository.findAll();
}

Este método simplemente llama a userRepository para findAll() usuarios y devuelve la lista como respuesta.

A continuación, implementemos el punto final para obtener a cada usuario por su id:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
@GetMapping("/{id}")
public ResponseEntity<User> findUserById(@PathVariable(value = "id") long id) {
    Optional<User> user = userRepository.findById(id);

    if(user.isPresent()) {
        return ResponseEntity.ok().body(user.get());
    } else {
        return ResponseEntity.notFound().build();
    }
}

A con el ‘id’ dado podría no estar presente en la base de datos, por lo que envolvemos el ‘Usuario’ devuelto en un ‘Opcional’.

Si desea leer más sobre Opcional en Java 8, ¡tenemos una guía detallada!

Luego, si user.isPresent(), devolvemos una respuesta HTTP 200 OK y establecemos la instancia user como el cuerpo de la respuesta. De lo contrario, devolvemos un ResponseEntity.notFound().

Finalmente, hagamos un punto final para salvar a los usuarios:

1
2
3
4
@PostMapping
public User saveUser(@Validated @RequestBody User user) {
    return userRepository.save(user);
}

El método save() del repositorio de usuarios guarda un nuevo usuario si aún no existe. Si el usuario con el id dado ya existe, lanza una excepción. Si tiene éxito, devuelve el usuario persistente.

La anotación @Validated es un validador de los datos que proporcionamos sobre el usuario y aplica la validez básica. Si la información del usuario no es válida, los datos no se guardan. Además, la anotación @RequestBody mapea el cuerpo de la solicitud POST enviada al punto final a la instancia Usuario que nos gustaría guardar.

If you'd like to read more about Obtener el cuerpo HTTP en Spring Boot, we've got you covered!

Ahora, es hora de ejecutar la aplicación y probar si funciona.

Compile, construya y ejecute

El puerto predeterminado en el que se ejecuta Spring Boot es 8080. Si desea cambiar el puerto por cualquier motivo, puede configurarlo en su archivo application.properties:

1
server.port = 9090

Si tiene un IDE como IntelliJ que tiene un amplio soporte para ejecutar proyectos Spring Boot, entonces puede continuar y ejecutarlo de esa manera.

Si no, usaremos la línea de comandos para ejecutar nuestro proyecto. Podemos ejecutar la aplicación directamente ejecutando ./mvnw spring-boot:run (o ./gradlew bootRun si está usando Gradle) en la línea de comando desde la carpeta de su proyecto base donde pom.xml se encuentra.

Otra opción es empaquetar su aplicación en un archivo jar y ejecutarlo de esa manera.

Para ello, solo tenemos que ejecutar ./mvnw clean package (.gradlew build en Gradle) y ejecutar el archivo jar ejecutando este comando:

1
$ java -jar target/DemoUser-0.0.1-SNAPSHOT.jar

Si está utilizando Gradle, la ruta al archivo jar será diferente:

1
$ java -jar build/libs/DemoUser-0.0.1-SNAPSHOT.jar

Sabrá cuándo su aplicación se ejecutó con éxito si ve estos registros de auditoría al final de su línea de comando:

1
2
3
2020-11-05 13:27:05.073  INFO 21796 --- [  restartedMain] o.s.b.d.a.OptionalLiveReloadServer       : LiveReload server is running on port 35729
2020-11-05 13:27:05.108  INFO 21796 --- [  restartedMain] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2020-11-05 13:27:05.121  INFO 21796 --- [  restartedMain] com.howto.DemoUser.DemoUserApplication   : Started DemoUserApplication in 1.765 seconds (JVM running for 2.236)

Prueba de las API

Ahora que su aplicación está funcionando en http://localhost:8080/, ahora podemos probar los puntos finales para ver si funcionan.

Para las solicitudes GET, podemos usar navegadores, curl o Postman, lo que sea más conveniente para usted.

Vayamos al punto final http://localhost:8080/api/user con una solicitud GET:

1
$ curl http://localhost:8080/api/user

O, en la barra de direcciones de su navegador, visite http://localhost:8080/api/user, y su navegador mostrará una respuesta JSON:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
[
   {
      "id": 1,
      "name":"John"
   },
   {
      "id": 2,
      "name":"Jane"
   },
   {
      "id": 3,
      "name": "Juan"
   }
]

Podemos modificar esta URL para incluir un parámetro de ruta, el id para obtener un usuario específico. Enviemos una solicitud HTTP GET a http://localhost:8080/api/user/3:

1
2
3
4
{
    "id": 3,
    "name": "Juan"
} 

Finalmente, enviemos una solicitud HTTP POST y agreguemos un usuario a nuestra base de datos, proporcionando los datos requeridos en nuestro modelo. Los campos en la carga útil de JSON deben coincidir con los nombres de los campos en nuestra base de datos/modelo:

1
2
3
$ curl --location --request POST 'http://localhost:8080/api/user' \
--header 'Content-Type: application/json' \
--data-raw '{ "id": 4, "name": "Jason" }'

La API devolverá 200 como respuesta con esto como el cuerpo de respuesta del usuario persistente:

1
2
3
4
{
    "id": 4,
    "name": "Jason"
}

Conclusión

Ahí tienes. ¡Ha creado con éxito su propia API REST de Spring Boot!

En este tutorial, hemos creado un proyecto Spring Boot completamente funcional que expone una API al usuario final. Usando esta API, un usuario puede realizar operaciones CRUD en una entidad Usuario.

Hemos cubierto el Modelo de Dominio, la Capa de Persistencia, así como la Capa de Negocios, después de configurar la conexión a la base de datos y configurar el proyecto.