Desarrollo basado en pruebas para las API de Spring Boot

     

    Introducci贸n

    Con el aumento de la adopci贸n de tel茅fonos inteligentes en el mundo actual, ha habido una afluencia de aplicaciones m贸viles para lograr una amplia variedad de tareas. Algunas de las aplicaciones que usamos a diario se comunican con otros sistemas para brindarnos una experiencia perfecta en m煤ltiples dispositivos y plataformas.

    驴C贸mo es esto posible? Las interfaces de programaci贸n de aplicaciones (API) son responsables de esta conectividad ampliada. Hacen posible que las aplicaciones m贸viles y web interact煤en y faciliten la transferencia de datos entre ellas y otros sistemas.

    En este art铆culo, analizaremos las API, las mejores pr谩cticas al crearlas y tambi茅n crearemos una API utilizando el enfoque de desarrollo basado en pruebas y el marco Spring Boot .

    El auge de las API

    Una API define un conjunto de rutinas y protocolos para la interacci贸n entre sistemas de software. Muchas aplicaciones m贸viles y web interact煤an con servidores que manejan solicitudes y responden a ellas, lo que se conoce como clientes.

    A medida que los sistemas aumentan de tama帽o, se vuelven robustos y pueden resultar dif铆ciles de mantener y realizar actualizaciones. Al desacoplar un sistema en varias API espec铆ficas, se logra flexibilidad y las partes del sistema robusto ahora pueden actualizarse o implementarse en partes f谩cilmente sin afectar el tiempo de actividad o el rendimiento del resto del sistema.

    Esto da como resultado una arquitectura de microservicios, que depende en gran medida del desarrollo de API. En dicho sistema, las API proporcionan un modo de comunicaci贸n dentro del sistema y las diversas partes del sistema a煤n pueden interactuar y compartir la carga de trabajo.

    Los tel茅fonos inteligentes nos permitieron estar conectados y con su poder cada vez mayor, podemos lograr mucho m谩s. El acceso a Internet tambi茅n se ha vuelto m谩s com煤n, por lo que la mayor铆a de los tel茅fonos inteligentes est谩n constantemente conectados a Internet. Estos dos factores impulsan el uso de aplicaciones m贸viles que interact煤an con servidores web donde las API entran en escena.

    Las API facilitan la comunicaci贸n entre las aplicaciones m贸viles y los servidores y el aumento en el uso de aplicaciones m贸viles ha impulsado el aumento de las API.

    Las aplicaciones web tambi茅n han evolucionado con el tiempo y la complejidad ha aumentado. Esto, a su vez, ha llevado a la separaci贸n de las capas de presentaci贸n y l贸gica de una aplicaci贸n web normal. Inicialmente, tendr铆a ambas capas de una aplicaci贸n web compiladas juntas y desplegadas como una para que la usen las masas. Ahora, la secci贸n del frontend est谩 desacoplada del backend para facilitar la separaci贸n de preocupaciones.

    Las API tambi茅n permiten a las empresas realizar una configuraci贸n de backend 煤nica para servir aplicaciones m贸viles y aplicaciones web al mismo tiempo. Esto ahorra tiempo de desarrollo y deuda t茅cnica, ya que el sistema backend solo se modifica en un punto.

    Los tel茅fonos inteligentes tambi茅n son tan diversos y las empresas ahora tienen que atender a varios tipos de tel茅fonos inteligentes al mismo tiempo para brindar una experiencia uniforme a sus usuarios. Las API hacen posible que las aplicaciones m贸viles que se ejecutan en diferentes plataformas interact煤en de manera uniforme con un 煤nico sistema backend o API.

    Es muy importante mencionar que las API tambi茅n hacen posible que otros desarrolladores que utilizan diferentes lenguajes de programaci贸n accedan a nuestro sistema para obtener informaci贸n. Esto facilita la integraci贸n de sistemas que utilizan diferentes lenguajes de programaci贸n.

    Esto, de nuevo, nos permite crear aplicaciones modulares, utilizando varios lenguajes, herramientas y marcos juntos para sacar lo mejor de cada uno.

    Construyendo mejores API

    Las API tambi茅n act煤an como un punto de contacto con el trabajo de otros desarrolladores, ya que pueden permitir que otros desarrolladores las consuman para su propio uso.

    Por ejemplo, Twitter ha expuesto algunas de sus API para que las utilicen otros desarrolladores para crear otros clientes de Twitter y utilizar la plataforma de otras formas 煤nicas. Algunos han construido bots en plataformas como Telegram para enviar tweets o buscar tweets, todo lo cual se logra a trav茅s de API.

    Esto hace que las API sean importantes en los ecosistemas de software actuales y futuros, ya que nos permiten integrarnos con otros sistemas de manera flexible. No solo API, sino buenas API.

    Es primordial que nuestra API est茅 bien construida y documentada para que cualquier otra persona que la consuma tenga m谩s facilidad. La documentaci贸n es el aspecto m谩s importante de una API, le permite a otros desarrolladores saber qu茅 logra y qu茅 se requiere para aprovechar esa funcionalidad. Tambi茅n ayuda a los encargados de mantenimiento a saber con qu茅 se enfrentan y asegurarse de que sus cambios no afecten ni interrumpan la funcionalidad existente.

    Los c贸digos de estado HTTP se definieron para identificar diversas situaciones que pueden ocurrir cuando una aplicaci贸n interact煤a con una API.

    Se dividen en cinco categor铆as que incluyen c贸digos para:

    • Respuestas informativas : estados 1xx , como 100 Continuar, 101 Protocolos de conmutaci贸n, etc.
    • 脡xito : estados 2xx , como 200 OK, 202 Aceptado, etc.
    • Redirecci贸n : estados 3xx , como 300 opciones m煤ltiples, 301 movido permanentemente, etc.
    • Errores del cliente : estados 4xx , como 400 Bad Request, 403 Forbidden, 404 Not Found, etc.
    • Errores del servidor : estados 5xx , como 500 Internal Server Error, 502 Bad Gateway, 503 Service no disponible, etc.

    Estos c贸digos ayudan al sistema y a las personas que interact煤an con 茅l a identificar y comprender la naturaleza de los eventos que ocurren y las causas de los errores.

    Al adherirnos a los c贸digos de estado HTTP en nuestras API, podemos hacer que nuestras API sean f谩ciles de interactuar e integrar. Adem谩s de estos, tambi茅n podemos definir nuestros propios c贸digos de error para nuestras API, pero es importante que los documentemos claramente para que sea m谩s f谩cil para los consumidores y mantenedores de las API.

    Antes de que los autom贸viles, tel茅fonos o dispositivos electr贸nicos se entreguen a sus usuarios, se someten a pruebas exhaustivas para garantizar que no funcionen mal cuando est谩n en uso. Las API se han vuelto m谩s comunes e importantes, por lo tanto, tambi茅n necesitan la misma cantidad de atenci贸n a los detalles.

    Deben probarse minuciosamente antes de su lanzamiento para evitar un mal funcionamiento durante la producci贸n.

    Construyendo una API

    Arquitectura del proyecto

    Supongamos que estamos creando una aplicaci贸n que ayuda a los usuarios a mantener una lista de sus coches. Podr谩n agregar autos nuevos, actualizar autos existentes e incluso eliminar autos que ya no poseen. Esta aplicaci贸n estar谩 disponible para dispositivos Android e iOS y tambi茅n como aplicaci贸n web.

    Usando Spring Boot Framework, podemos construir una 煤nica API que pueda servir a las tres aplicaciones, o clientes, simult谩neamente.

    Nuestro viaje comienza en la herramienta Spring Initializer que nos ayuda a iniciar r谩pidamente nuestra API Spring Boot en cuesti贸n de minutos. Hay muchas dependencias y paquetes que nos ayudan a lograr varias funcionalidades en nuestras API y la herramienta Spring Initializer ayuda a integrarlas en nuestro proyecto de inicio.

    Esto tiene como objetivo facilitar nuestro proceso de desarrollo y permitirnos dirigir nuestra atenci贸n a la l贸gica de nuestra aplicaci贸n:

    La herramienta nos permite elegir entre Maven y Gradle , que son herramientas que nos ayudan a automatizar algunos aspectos de nuestro flujo de trabajo de compilaci贸n, como probar, ejecutar y empaquetar nuestra aplicaci贸n Java. Tambi茅n tenemos la opci贸n de elegir entre usar Java o Kotlin cuando construimos nuestra API usando Spring Boot para lo cual podemos especificar la versi贸n.

    Cuando hacemos clic en “Cambiar a la versi贸n completa”, obtenemos m谩s opciones para agrupar en nuestra API. Muchas de estas opciones son 煤tiles al crear microservicios, como las secciones “Cloud Config” y “Cloud Discovery”.

    Para nuestra API, elegiremos las siguientes dependencias:

    • Web para ayudarnos a desarrollar una API basada en web
    • MySQL que nos ayudar谩 a conectarnos a nuestra base de datos MySQL,
    • JPA que es la API de persistencia de Java para satisfacer nuestras necesidades de interacci贸n con la base de datos, y
    • Actuator para ayudarnos a mantener y monitorear nuestra aplicaci贸n web.

    Con las dependencias establecidas, hacemos clic en el bot贸n “Generar proyecto” para obtener un zip que contiene nuestro c贸digo est谩ndar.

    Identifiquemos lo que viene en el paquete usando el treecomando:

    $ tree .
    .
    鈹溾攢鈹 HELP.md
    鈹溾攢鈹 mvnw
    鈹溾攢鈹 mvnw.cmd
    鈹溾攢鈹 pbcopy
    鈹溾攢鈹 pom.xml
    鈹斺攢鈹 src
        鈹溾攢鈹 main
        鈹   鈹溾攢鈹 java
        鈹   鈹   鈹斺攢鈹 com
        鈹   鈹       鈹斺攢鈹 example
        鈹   鈹           鈹斺攢鈹 cars
        鈹   鈹               鈹斺攢鈹 CarsApplication.java
        鈹   鈹斺攢鈹 resources
        鈹       鈹溾攢鈹 application.properties
        鈹       鈹溾攢鈹 static
        鈹       鈹斺攢鈹 templates
        鈹斺攢鈹 test
            鈹斺攢鈹 java
                鈹斺攢鈹 com
                    鈹斺攢鈹 example
                        鈹斺攢鈹 cars
                            鈹斺攢鈹 CarsApplicationTests.java
    

    En la carpeta ra铆z, hay un pom.xmlarchivo que contiene la configuraci贸n del proyecto para nuestra API Spring Boot. Si us谩ramos Gradle, tendr铆amos un build.gradlearchivo en su lugar. Incluye informaci贸n como los detalles de nuestra nueva API y todas sus dependencias.

    Trabajaremos principalmente en las carpetas mainy testdentro de la srccarpeta source ( ). Aqu铆 es donde colocaremos nuestros controladores, modelos, clases de utilidad entre otros.

    Comencemos creando nuestra base de datos y configurando nuestra API para usarla. Siga esta gu铆a para instalar y verificar que MySQL se est茅 ejecutando.

    Una vez listo, creemos nuestra base de datos de la siguiente manera:

    $ mysql -u root -p
    
    mysql> CREATE DATABASE cars_database;
    Query OK, 1 row affected (0.08 sec)
    

    Algunos detalles de nuestro servicio ser谩n diferentes de un entorno a otro. Por ejemplo, la base de datos que usamos durante el desarrollo no ser谩 la misma que los usuarios finales usar谩n para almacenar su informaci贸n.

    Los archivos de configuraci贸n nos facilitan el cambio de esos detalles, lo que facilita la migraci贸n y modificaci贸n de nuestra API. Esto se logra a trav茅s del archivo de configuraci贸n, que en una API de Spring Boot es el application.propertiesarchivo que se encuentra en la src/main/resourcescarpeta.

    Para permitir que nuestra dependencia JPA acceda y modifique nuestra base de datos, modificamos el archivo de configuraci贸n agregando las propiedades:

    # Database Properties
    spring.datasource.url = jdbc:mysql://localhost:3306/cars_database?useSSL=false
    spring.datasource.username = root
    spring.datasource.password = password
    
    # Hibernate Properties
    # The SQL dialect makes Hibernate generate better SQL for the chosen database
    spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5InnoDBDialect
    
    # Hibernate ddl auto (create, create-drop, validate, update)
    spring.jpa.hibernate.ddl-auto = update
    

    Ahora necesitamos una clase de entidad para definir los recursos de nuestra API y sus detalles, ya que se guardar谩n en nuestra base de datos. A Cares nuestro recurso en esta API y lo que esto significa es que representa nuestro objeto o elemento de la vida real en cuya informaci贸n realizaremos acciones. Tales acciones incluyen Crear, Leer, Actualizar y Eliminar, simplemente como operaciones CRUD .

    Estas operaciones est谩n detr谩s de los m茅todos o verbos HTTP que se refieren a varias operaciones que una API puede exponer. Incluyen:

    • GET que es una operaci贸n de lectura que solo obtiene los datos especificados,
    • POSTque posibilita la creaci贸n de resourcesmediante el suministro de su informaci贸n como parte de la solicitud,
    • PUT que nos permite modificar un recurso, y
    • DELETE que usamos para eliminar un recurso y su informaci贸n de nuestra API.

    Para organizar mejor nuestro c贸digo, introduciremos algunas carpetas m谩s en nuestro proyecto a src/main/java/com/example/cars/nivel. Agregaremos una carpeta llamada modelspara alojar las clases que definen nuestros objetos.

    Las otras carpetas que se agregar谩n incluyen una controllerscarpeta que contiene nuestros controladores, una repositorycarpeta para las clases de administraci贸n de la base de datos y una utilscarpeta para cualquier clase auxiliar que necesitemos agregar a nuestro proyecto. La estructura de carpetas resultante ser谩:

    $ tree .
    .
    鈹溾攢鈹 HELP.md
    鈹溾攢鈹 mvnw
    鈹溾攢鈹 mvnw.cmd
    鈹溾攢鈹 pbcopy
    鈹溾攢鈹 pom.xml
    鈹斺攢鈹 src
        鈹溾攢鈹 main
        鈹   鈹溾攢鈹 java
        鈹   鈹   鈹斺攢鈹 com
        鈹   鈹       鈹斺攢鈹 example
        鈹   鈹           鈹斺攢鈹 cars
        鈹   鈹               鈹溾攢鈹 CarsApplication.java
        鈹   鈹               鈹溾攢鈹 controllers
        鈹   鈹               鈹溾攢鈹 models
        鈹   鈹               鈹溾攢鈹 repository
        鈹   鈹               鈹斺攢鈹 utils
        鈹   鈹斺攢鈹 resources
        鈹       鈹溾攢鈹 application.properties
        鈹       鈹溾攢鈹 static
        鈹       鈹斺攢鈹 templates
        鈹斺攢鈹 test
            鈹斺攢鈹 java
                鈹斺攢鈹 com
                    鈹斺攢鈹 example
                        鈹斺攢鈹 cars
                            鈹斺攢鈹 CarsApplicationTests.java
    
    

    Modelo de dominio

    Definamos nuestra Carclase en la modelscarpeta:

    /**
    * This class will represent our car and its attributes
    */
    @Entity
    @Table(name="cars") // the table in the database tht will contain our cars data
    @EntityListeners(AuditingEntityListener.class)
    public class Car {
    
        @Id
        @GeneratedValue(strategy=GenerationType.AUTO)
        private long id; // Each car will be given an auto-generated unique identifier when stored
    
        @Column(name="car_name", nullable=false)
        private String carName; // We will also save the name of the car
    
        @Column(name="doors", nullable=false)
        private int doors; // We will also save the number of doors that a car has
    
        // getters and setters
    }
    

    Nota : he eliminado las importaciones para acortar el fragmento de c贸digo. Consulte el repositorio de Github adjunto al final del art铆culo para obtener el c贸digo completo.

    DAO

    Con nuestro modelo de autom贸vil listo, creemos ahora el CarRepositoryarchivo que se utilizar谩 en la interacci贸n con la base de datos:

    public interface CarRepository extends JpaRepository<Car, Long> { }
    

    Pruebas de escritura

    Ahora podemos exponer la funcionalidad de nuestra API a trav茅s de nuestro controller, pero en el esp铆ritu del desarrollo basado en pruebas (TDD), escribamos las pruebas primero en el CarsApplicationTestsarchivo:

    // These are a subset of the tests, the full test file is available on the Github repo attached at the end of this article
    ....
    
        /**
         * Here we test that we can get all the cars in the database
         * using the GET method
         */
        @Test
        public void testGetAllCars() {
            HttpHeaders headers = new HttpHeaders();
            HttpEntity<String> entity = new HttpEntity<String>(null, headers);
    
            ResponseEntity<String> response = restTemplate.exchange(getRootUrl() + "/cars",
                HttpMethod.GET, entity, String.class);
    
            Assert.assertNotNull(response.getBody());
        }
    
        /**
         * Here we test that we can fetch a single car using its id
         */
        @Test
        public void testGetCarById() {
            Car car = restTemplate.getForObject(getRootUrl() + "/cars/1", Car.class);
            System.out.println(car.getCarName());
            Assert.assertNotNull(car);
        }
    
        /**
         * Here we test that we can create a car using the POST method
         */
        @Test
        public void testCreateCar() {
            Car car = new Car();
            car.setCarName("Prius");
            car.setDoors(4);
    
            ResponseEntity<Car> postResponse = restTemplate.postForEntity(getRootUrl() + "/cars", car, Car.class);
            Assert.assertNotNull(postResponse);
            Assert.assertNotNull(postResponse.getBody());
        }
    
        /**
         * Here we test that we can update a car's information using the PUT method
         */
        @Test
        public void testUpdateCar() {
            int id = 1;
            Car car = restTemplate.getForObject(getRootUrl() + "/cars/" + id, Car.class);
            car.setCarName("Tesla");
            car.setDoors(2);
    
            restTemplate.put(getRootUrl() + "/cars/" + id, car);
    
            Car updatedCar = restTemplate.getForObject(getRootUrl() + "/cars/" + id, Car.class);
            Assert.assertNotNull(updatedCar);
        }
    

    Las pruebas simulan diversas acciones que son posibles en nuestra API y esta es nuestra forma de verificar que la API funciona como se espera. Si se hiciera un cambio ma帽ana, las pruebas ayudar谩n a determinar si alguna de las funciones de la API est谩 rota y, al hacerlo, evitar谩n que rompamos la funcionalidad al realizar cambios.

    Piense en las pruebas como una lista de compras cuando vaya al supermercado. Sin 茅l, podr铆amos terminar eligiendo casi todo lo que encontramos y creemos que podr铆a ser 煤til. Puede que nos lleve mucho tiempo conseguir todo lo que necesitamos. Si tuvi茅ramos una lista de compras, podr铆amos comprar exactamente lo que necesitamos y terminar de comprar m谩s r谩pido. Las pruebas hacen lo mismo para nuestras API, nos ayudan a definir el alcance de la API para que no implementemos funcionalidad que no estaba en los planes o no era necesaria.

    Cuando ejecutamos nuestras pruebas usando el mvn testcomando, veremos errores surgidos y esto se debe a que a煤n no hemos implementado la funcionalidad que satisface nuestros casos de prueba.

    En TDD, primero escribimos las pruebas, las ejecutamos para asegurarnos de que inicialmente fallan y luego implementamos la funcionalidad para que las pruebas pasen.

    TDD es un proceso iterativo de escribir pruebas e implementar la funcionalidad para hacer que las pruebas pasen. Si introducimos cambios en el futuro, primero escribiremos las pruebas y luego implementaremos los cambios para que pasen las nuevas pruebas.

    Controlador

    Implementemos ahora nuestra funcionalidad API en una CarControllerque va a la controllerscarpeta:

    @RestController
    @RequestMapping("/api/v1")
    public class CarController {
    
        @Autowired
        private CarRepository carRepository;
    
        // GET Method for reading operation
        @GetMapping("/cars")
        public List<Car> getAllCars() {
            return carRepository.findAll();
        }
    
        // GET Method for Read operation
        @GetMapping("/cars/{id}")
        public ResponseEntity<Car> getCarsById(@PathVariable(value = "id") Long carId)
            throws ResourceNotFoundException {
    
            Car car = carRepository
                      .findById(carId)
                      .orElseThrow(() -> new ResourceNotFoundException("Car not found on :: " + carId));
            return ResponseEntity.ok().body(car);
        }
    
        // POST Method for Create operation
        @PostMapping("/cars")
        public Car createCar(@Valid @RequestBody Car car) {
            return carRepository.save(car);
        }
    
        // PUT Method for Update operation
        @PutMapping("/cars/{id}")
        public ResponseEntity<Car> updateCar(
            @PathVariable(value = "id") Long carId, @Valid @RequestBody Car carDetails)
            throws ResourceNotFoundException {
                Car car = carRepository
                          .findById(carId)
                          .orElseThrow(() -> new ResourceNotFoundException("Car " + carId + " not found"));
    
            car.setCarName(carDetails.getCarName());
            car.setDoors(carDetails.getDoors());
    
            final Car updatedCar = carRepository.save(car);
            return ResponseEntity.ok(updatedCar);
        }
    
        // DELETE Method for Delete operation
        @DeleteMapping("/car/{id}")
        public Map<String, Boolean> deleteCar(@PathVariable(value = "id") Long carId) throws Exception {
            Car car = carRepository
                      .findById(carId)
                      .orElseThrow(() -> new ResourceNotFoundException("Car " + carId + " not found"));
    
            carRepository.delete(car);
            Map<String, Boolean> response = new HashMap<>();
            response.put("deleted", Boolean.TRUE);
            return response;
        }
    }
    

    En la parte superior, tenemos la @RestControlleranotaci贸n para definir nuestra CarControllerclase como el controlador de nuestra API Spring Boot. Lo que sigue es @RequestMappingdonde especificamos la ruta base de nuestra URL de API como /api/v1. Esto tambi茅n incluye la versi贸n.

    El control de versiones es una buena pr谩ctica en una API para mejorar la compatibilidad con versiones anteriores. Si la funcionalidad cambia y ya tenemos a otras personas consumiendo nuestras API, podemos crear una nueva versi贸n y hacer que ambas se ejecuten al mismo tiempo para darles tiempo suficiente para migrar a la nueva API.

    Anteriormente, aprendimos sobre las operaciones Crear, Leer, Actualizar y Eliminar en una API y c贸mo se asignan a los m茅todos HTTP. Estos m茅todos se alojan en el marco del resorte como PostMapping, GetMapping, PutMappingy DeleteMappinganotaciones, respectivamente. Cada una de estas anotaciones nos ayuda a exponer los puntos finales que solo realizan la operaci贸n CRUD especificada.

    Tambi茅n podemos tener un 煤nico punto final que maneje varios m茅todos HTTP:

    @RequestMapping(value="/cars", method = { RequestMethod.GET, RequestMethod.POST })
    

    Ahora que hemos implementado la funcionalidad, ejecutemos nuestras pruebas:

    Las pruebas aprobadas nos muestran que hemos implementado la funcionalidad deseada al escribir las pruebas y nuestra API funciona.

    Perm铆tanos interactuar con nuestra API a trav茅s de Postman , que es una herramienta que ayuda a interactuar con las API al desarrollarlas o consumirlas.

    Empezamos por buscar todos los coches que tenemos almacenados en nuestra base de datos:

    Al principio, no tenemos coches almacenados. Agreguemos nuestro primer auto:

    La respuesta es el idy los detalles del coche que acabamos de a帽adir. Si agregamos algunos autos m谩s y recuperamos todos los autos que hemos guardado:

    Estos son los autos que hemos creado usando nuestra API Spring Boot. Una comprobaci贸n r谩pida de la base de datos devuelve la misma lista:

    IU de Swagger

    Hemos construido y probado nuestra API usando TDD y ahora para mejorar nuestra API, la documentaremos usando Swagger UI , lo que nos permite crear una interfaz generada autom谩ticamente para que otros usuarios interact煤en y aprendan sobre nuestra API.

    Primero, agreguemos las siguientes dependencias en nuestro pom.xml:

    <dependency>
      <groupId>io.springfox</groupId>
      <artifactId>springfox-swagger2</artifactId>
      <version>2.7.0</version>
    </dependency>
    
    <dependency>
      <groupId>io.springfox</groupId>
      <artifactId>springfox-swagger-ui</artifactId>
      <version>2.7.0</version>
    </dependency>
    

    A continuaci贸n, crearemos un SwaggerConfig.javaen la misma carpeta que CarsApplication.java, que es el punto de entrada a nuestra API.

    El SwaggerConfig.javaarchivo tambi茅n permite agregar informaci贸n sobre nuestra API:

    @Configuration
    @EnableSwagger2
    public class SwaggerConfig {
        @Bean
        public Docket api() {
            return new Docket(DocumentationType.SWAGGER_2)
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.example.cars"))
                .paths(PathSelectors.any())
                .build()
                .apiInfo(metadata());
        }
    
        /**
         * Adds metadata to Swagger
         *
         * @return
         */
        private ApiInfo metadata() {
            return new ApiInfoBuilder()
                .title("Cars API")
                .description("An API to store car details built using Spring Boot")
                .build();
        }
    }
    

    Ahora anotamos nuestros puntos finales para que aparezcan en la interfaz de IU de Swagger que se generar谩. Esto se consigue de la siguiente manera:

    // Add this import in our controller file...
    import io.swagger.annotations.ApiOperation;
    
    // ...then annotate our HTTP Methods
    @ApiOperation(value="Fetches all cars in the database", response=Car.class)
    @PostMapping("/...") // Our endpoint
    

    Hemos especificado nuestra clase de respuesta como la Carclase, ya que es la que se utilizar谩 para completar los detalles de nuestras respuestas. Hemos hecho esto porque Swagger UI nos permite agregar informaci贸n sobre las cargas 煤tiles de la solicitud y los detalles de la respuesta. Esto ayudar谩 a proporcionar m谩s informaci贸n sobre las cargas 煤tiles, como el tipo de valores que requiere nuestra API y el tipo de respuesta que se devolver谩. Tambi茅n podemos especificar campos obligatorios en la documentaci贸n.

    En nuestro caso, tambi茅n usaremos la Carclase para formatear y validar nuestros par谩metros de solicitud. Por lo tanto, anotamos sus “captadores” de la siguiente manera:

        @ApiModelProperty(name="id",
                          value="The id of the car",
                          example="1")
        public long getId() {
            return id;
        }
    
        @ApiModelProperty(name="carName",
                          value="The name of the car to be saved",
                          example="Bugatti",
                          required=true)
        public String getCarName() {
            return carName;
        }
    
        @ApiModelProperty(name="doors",
                          value="The number of doors that the car has",
                          example="2",
                          required=true)
        public int getDoors() {
            return doors;
        }
    

    隆Eso es todo! Nuestra documentaci贸n est谩 lista. Cuando ejecutamos nuestra API usando mvn spring-boot:runy navegamos http://localhost:8080/swagger-ui.html, podemos ver la documentaci贸n de nuestra API:

    La interfaz de usuario de Swagger ha documentado todos nuestros puntos finales e incluso ha proporcionado funciones para interactuar con nuestra API directamente desde la documentaci贸n. Como se puede ver en la secci贸n inferior derecha de la captura de pantalla, nuestros valores de ejemplo se han completado previamente para que podamos probar r谩pidamente la API sin tener que volver a escribir los valores.

    Conclusi贸n

    Java es un lenguaje poderoso y hemos aprovechado su poder para construir una interfaz de programaci贸n de aplicaciones, o API, utilizando el marco Spring Boot. Hemos podido implementar cuatro de los m茅todos HTTP para manejar las diversas operaciones de creaci贸n, lectura, actualizaci贸n y eliminaci贸n de los detalles de nuestros coches.

    Swagger UI tambi茅n nos ha permitido documentar nuestra API de una manera simple pero detallada y tener esta documentaci贸n expuesta como un punto final en nuestro servicio. Habiendo notado las ventajas del desarrollo basado en pruebas, seguimos adelante y escribimos pruebas para nuestros puntos finales y nos aseguramos de que nuestra funcionalidad y pruebas est茅n alineadas.

    El c贸digo fuente de este proyecto est谩 disponible aqu铆 en Github .

     

    Etiquetas:

    Deja una respuesta

    Tu direcci贸n de correo electr贸nico no ser谩 publicada. Los campos obligatorios est谩n marcados con *