Creando un API REST

Vamos a crear un API REST sencillo apra implementar los métodos HTTP y entender un poco como funciona. En un primer momento debemos instalarlos Spring Boot.

Para instalarlo vale con acudir a nuestro IDE (en este caso Eclipse) y en el menú superior pulsamos en Help > Eclipse Marketplace. Nos saldrá un cuadro de dialogo donde podremos hacer nuestra búsqueda. A mi me valió con buscar "spring boot", no deberíais de tener problemas al respecto.

installed_spring

Una vez instalado el componente y reiniciado nuestro IDE, vamos a comenzar a crear nuestro proyecto. Para ello volvemos a nuestro menú superior y selecionamos File > New > Other, aquí os debería de aparecer Spring boot, seleccionamos "Spring Starter Project".

Nos saldrá la pantalla donde definiremos nuestro proyecto. Podéis llamarlo como queráis.

inicio_proyecto

Lo mejor de usar Spring boot es que os crea todas las carpetas automáticamente. Hay dos archivos muy importantes, que son el pom.xml, donde añadiremos las dependencias necesarias para realizar nuestro proyecto y el archivo application.properties, donde definiremos nuestra conexión a la base de datos además de diversas configuraciones.

La estructura de vuestro proyecto debería quedar más o menos como os enseño en la imagen.

proyecto

Comenzaremos con el pom.xml, donde debemos añadir nuestras dependencias. En este caso deben las dependencias que debéis de tener son las siguientes:

<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-thymeleaf</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>2.9.2</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
</dependencies>

Luego nos iremos al archivo de application.properties, donde haremos las configuraciones a nuestra BBDD.

server.port= (podéis poner aquí el puerto que queráis)
spring.datasource.url = jdbc:mysql://localhost:3306/clientes?zeroDateTimeBehavior=convertToNull&serverTimezone=UTC
spring.datasource.username = root
spring.datasource.password = (contraseña que sea)

spring.jpa.show-sql = true (esto hará que veamos en consolas las consultas sql que se hagan)

spring.jpa.hibernate.ddl-auto = update (crea el esquema en BBDD)
spring.jpa.open-in-view = false

spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5Dialect

Otro archivo importante se encuentra en el paquete, principal que estaría en src/main/java  que será nuestra clase de entrada a la aplicación.

 


package com.init.clientes;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class ProyectoApi3Application {

	public static void main(String[] args) {
		SpringApplication.run(ProyectoApi3Application.class, args);
	}

}

Ahora nos crearemos nuestro POJO. Un objeto POJO es una instancia de una clase que no extiende ni implementa nada en especial. : 

Por definición los POJOs no pueden:

  • Extender otras clases
  • Implementar interfaces (aunque no está mal visto que implementen interfaces marcadoras, al no aumentar la complejidad del código)
  • Contener decoradores

 

En mi caso me he creado uno que se llama Cliente:

 

En esta clase vemos cosas interesantes: Establecemos la Entidad de la clase, y la tabla(Table(name="cliente") a la que hace referencia la base de datos. Cada una de las características de la clase, les asignamos una columna de la tabla, que hará que cada valor que llegue a cada una de ellas, ese valor se guardará en las diferentes columnas de la tabla. Por ejemplo el valor que llegue a nombre, ("Claudia") irá a la columna "nombre" de la tabla clientes. Existen parámetros como nullable=false, length=100, que hacen referencia a que no sea nulo, o que su longitud sea máxima de 100.


package com.init.clientes.entity;
import javax.persistence.Entity;
import javax.persistence.Table;
import javax.persistence.Id;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.Column;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;




@Entity
@Table(name="clientes")
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public class Cliente {
	
	@Id
	@Column(name="ID")
	@GeneratedValue(strategy=GenerationType.IDENTITY)
	private long id;
	
	@Column(name="nombre", nullable=false, length=50)
	private String nombre;
	
	@Column(name="apellido1", nullable=false, length=100)
	private String apellido1;
	
	@Column(name="apellido2", nullable=false, length=100)
	private String apellido2;
	
	@Column(name="tipodocu", nullable=false, length=3)
	private String tipoDocumento;
	
	@Column(name="numedocu", nullable=false, length=20)
	private String numeroDocumento;
	
	
	public Cliente (long id, String nombre, String apellido1, String apellido2, String tipoDocumento, String numeroDocumento) {
		this.id = id;
		this.nombre = nombre;
		this.apellido1 = apellido1;
		this.apellido2 = apellido2;
		this.tipoDocumento = tipoDocumento;
		this.numeroDocumento = numeroDocumento;
	}
	
	public Cliente() {
		
	}
	
	
	

	public long getId() {
		return id;
	}

	public void setId(long id) {
		this.id = id;
	}

	public String getNombre() {
		return nombre;
	}

	public void setNombre(String nombre) {
		this.nombre = nombre;
	}

	public String getApellido1() {
		return apellido1;
	}

	public void setApellido1(String apellido1) {
		this.apellido1 = apellido1;
	}

	public String getApellido2() {
		return apellido2;
	}

	public void setApellido2(String apellido2) {
		this.apellido2 = apellido2;
	}

	public String getTipoDocumento() {
		return tipoDocumento;
	}

	public void setTipoDocumento(String tipoDocumento) {
		this.tipoDocumento = tipoDocumento;
	}

	public String getNumeroDocumento() {
		return numeroDocumento;
	}

	public void setNumeroDocumento(String numeroDocumento) {
		this.numeroDocumento = numeroDocumento;
	}
	
	

}


 

Luego nos creamos otro paquete que albergará una clase a la cual he llamado ClientesDAO, que extenderé de la clase JpaRepository para hacer uso de sus métodos que nos ayudarán a la hora de hacer select, insert, delete....

 

 


package com.init.clientes.DAO;
import com.init.clientes.entity.Cliente;
import com.init.clientes.entity.Cliente.*;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;


public interface ClientesDAO extends JpaRepository {

}

Es ahora cuando nos vamos a la clase más importante. Donde definiremos las rutas a nuestros servicios y ejecutará las consultas o alteraciones en la tabla clientes. Esta clase se ha llamado ClientesRest.


package com.init.clientes.rest;
import com.init.clientes.DAO.ClientesDAO;
import com.init.clientes.entity.Cliente;
import java.util.Optional;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;



@RestController
@RequestMapping("clientes")
public class ClientesRest {

	@Autowired
	private ClientesDAO clienteDao;
	
	//@GetMapping 
	//Cuando devolvemos todos los valores almacenados
	@RequestMapping(value="getAllclientes", method =RequestMethod.GET)
	public ResponseEntity> getClientes(){
		List clientes = clienteDao.findAll();
		return ResponseEntity.ok(clientes);
	}
	
	//Cuando devolvemos un valor específico
	@RequestMapping(value="getAllclientes/{clienteId}", method =RequestMethod.GET)
	public ResponseEntity getClienteById(@PathVariable("clienteId") Long clienteId){
		Optional optionalCliente= clienteDao.findById(clienteId);
		if(optionalCliente.isPresent()) {
			return ResponseEntity.ok(optionalCliente.get());
		}
		return ResponseEntity.noContent().build();
	}
	
	@PostMapping(value="insertCliente")
	//Hacemos un insert de un cliente
	public ResponseEntity insertCliente(@RequestBody Cliente cliente){
		Cliente newCliente = clienteDao.save(cliente);
		return  new ResponseEntity<>(HttpStatus.CREATED);
	}
	
	@DeleteMapping(value="deleteCliente/{clienteId}")
	//eliminamos un cliente pasándole  un id
	public ResponseEntity deleteCliente(@PathVariable("clienteId") Long clienteId){
		clienteDao.deleteById(clienteId);
		return new ResponseEntity<>("Eliminado el registro: "+clienteId,  HttpStatus.NO_CONTENT);
	}
	
	
	@PutMapping(value="updateCliente/{clienteId}")
	//Actualizamos un registro de un cliente en concreto
	public ResponseEntity updateCliente(@RequestBody Cliente cliente){
		Optional optionalCliente= clienteDao.findById(cliente.getId());
		if(optionalCliente.isPresent()) {
			Cliente updateCliente = optionalCliente.get();
			updateCliente.setNombre(cliente.getNombre());
			clienteDao.save(updateCliente);
			return ResponseEntity.ok(updateCliente);
		}
		return ResponseEntity.noContent().build();
	}
	
}

 

 

La ruta inicial a nuestro servicio es "clientes" y por debajo de ella cuelgan los diferentes servicios que he creado. Tenemos getAllclientes donde obtendremos todos los clientes de nuestra BBDD

allclientes

Tenemos getAllclientes/6,  donde obtendremos el cliente con el id especificado en la ruta.

getcliente

Cuando utilizamos los métodos de consulta, no hay problema de realizarlos con el navegado, pero cuando es necesario hacer un insert, delete o update de algún registro de la BBDD será necesario utilizar postman que simula las llamadas a nuestro servicio.

Voy a probar el servicio inserCliente, donde pasaremos los valores y comprobaremos que se insertan correctamente. A continuación os muestro los registros de la BBDD para que veáis como después de la llamada, tendremos uno nuevo.

bbdd1

Realizo la llamada al servicio.

json

Consultamos otra vez la BBDD.

BBDD2

Sabemos cuales son los código HTTP de respuesta, cuando creamos un cliente lo ideal sería utilizar :

 


return  new ResponseEntity<>(HttpStatus.CREATED);

Esto hará que devolvamos un status code, que esto es importante para poder dar una pista a quien consuma nuestro servicio, en caso de que falle.

El resto de los servicios funcionan igual practicamente, en el caso de deleteCliente all pasar el id del que queremos eliminar, lo eliminará de nuestra BBDD.

Si queréis probarlo siempre podéis acudir a mi git para obtener el código y hacer pruebas en vuestro local.

Espero que os haya ayudado entender un poco más un API REST, Ahora sólo toca ampliar, y jugar con ello, haciéndolo cada vez más grande.