apuntes:api
Differences
This shows you the differences between two versions of the page.
Next revision | Previous revision | ||
apuntes:api [17/07/2020 10:17] – created Santiago Faci | apuntes:api [21/12/2022 10:12] (current) – Santiago Faci | ||
---|---|---|---|
Line 1: | Line 1: | ||
- | ====== | + | ====== |
+ | |||
+ | ===== Documentar | ||
+ | |||
+ | {{ openapi.png? | ||
+ | |||
+ | Una vez que ya hemos visto [[https:// | ||
+ | |||
+ | Para ello, comenzaremos añadiendo algunas dependencias a nuestro proyecto, que nos permitirán documentar nuestra aplicación y cada uno de los endpoints y generar un portal desde donde podremos publicarla como API. | ||
+ | |||
+ | <code xml> | ||
+ | < | ||
+ | < | ||
+ | < | ||
+ | < | ||
+ | </ | ||
+ | </ | ||
+ | |||
+ | Para comenzar, implementaremos una clase de configuración donde definiremos algunas propiedades generales para toda la aplicación, | ||
+ | |||
+ | <code java> | ||
+ | @Configuration | ||
+ | public class ShopConfig { | ||
+ | |||
+ | @Bean | ||
+ | public OpenAPI customOpenAPI() { | ||
+ | return new OpenAPI() | ||
+ | .components(new Components()) | ||
+ | .info(new Info().title(" | ||
+ | .description(" | ||
+ | .contact(new Contact() | ||
+ | .name(" | ||
+ | .email(" | ||
+ | .url(" | ||
+ | .version(" | ||
+ | } | ||
+ | } | ||
+ | |||
+ | </ | ||
+ | |||
+ | Y ya, para cada uno de los controladores (en este caso solamente tenemos uno), definiremos toda la documentación tanto para el propio controlador como para cada uno de los endpoints que se expongan: | ||
+ | |||
+ | * '' | ||
+ | * '' | ||
+ | * '' | ||
+ | |||
+ | <code java> | ||
+ | /** | ||
+ | * Controlador para productos | ||
+ | * @author Santiago Faci | ||
+ | * @version Curso 2020-2021 | ||
+ | */ | ||
+ | @RestController | ||
+ | @Tag(name | ||
+ | public class ProductController { | ||
+ | |||
+ | private final Logger logger = LoggerFactory.getLogger(ProductController.class); | ||
+ | |||
+ | @Autowired | ||
+ | private ProductService productService; | ||
+ | |||
+ | @Operation(summary = " | ||
+ | @ApiResponses(value = { | ||
+ | @ApiResponse(responseCode = " | ||
+ | content = @Content(array = @ArraySchema(schema = @Schema(implementation = Product.class)))), | ||
+ | }) | ||
+ | @GetMapping(value = "/ | ||
+ | public ResponseEntity< | ||
+ | logger.info(" | ||
+ | Set< | ||
+ | if (category.equals("" | ||
+ | products = productService.findAll(); | ||
+ | else | ||
+ | products = productService.findByCategory(category); | ||
+ | |||
+ | logger.info(" | ||
+ | return new ResponseEntity<> | ||
+ | } | ||
+ | |||
+ | @Operation(summary = " | ||
+ | @ApiResponses(value = { | ||
+ | @ApiResponse(responseCode = " | ||
+ | @ApiResponse(responseCode = " | ||
+ | }) | ||
+ | @GetMapping(value = "/ | ||
+ | public ResponseEntity< | ||
+ | Product product = productService.findById(id) | ||
+ | .orElseThrow(() -> new ProductNotFoundException(id)); | ||
+ | |||
+ | return new ResponseEntity<> | ||
+ | } | ||
+ | |||
+ | @Operation(summary = " | ||
+ | @ApiResponses(value = { | ||
+ | @ApiResponse(responseCode = " | ||
+ | }) | ||
+ | @PostMapping(value = "/ | ||
+ | public ResponseEntity< | ||
+ | Product addedProduct = productService.addProduct(product); | ||
+ | return new ResponseEntity<> | ||
+ | } | ||
+ | |||
+ | @Operation(summary = " | ||
+ | @ApiResponses(value = { | ||
+ | @ApiResponse(responseCode = " | ||
+ | @ApiResponse(responseCode = " | ||
+ | }) | ||
+ | @PutMapping(value = "/ | ||
+ | public ResponseEntity< | ||
+ | Product product = productService.modifyProduct(id, | ||
+ | return new ResponseEntity<> | ||
+ | } | ||
+ | |||
+ | @Operation(summary = " | ||
+ | @ApiResponses(value = { | ||
+ | @ApiResponse(responseCode = " | ||
+ | @ApiResponse(responseCode = " | ||
+ | }) | ||
+ | @DeleteMapping(value = "/ | ||
+ | public ResponseEntity< | ||
+ | productService.deleteProduct(id); | ||
+ | return new ResponseEntity<> | ||
+ | } | ||
+ | |||
+ | @ExceptionHandler(ProductNotFoundException.class) | ||
+ | @ResponseBody | ||
+ | @ResponseStatus(HttpStatus.NOT_FOUND) | ||
+ | public ResponseEntity< | ||
+ | Response response = Response.errorResonse(NOT_FOUND, | ||
+ | logger.error(pnfe.getMessage(), | ||
+ | return new ResponseEntity<> | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | Además, podremos añadir algunas anotaciones a las clases de nuestro modelo de datos para ampliar la documentación de nuestra nueva API: | ||
+ | |||
+ | * @Schema: Documenta un atributo, considerado como un campo de entrada (o salida) | ||
+ | * @NotBlank: Documenta que el atributo es obligatorio | ||
+ | * @Min: Documenta el valor mínimo del atributo | ||
+ | |||
+ | <code java> | ||
+ | /** | ||
+ | * Un producto del catálogo | ||
+ | * @author Santiago Faci | ||
+ | * @version Curso 2020-2021 | ||
+ | */ | ||
+ | @Data | ||
+ | @AllArgsConstructor | ||
+ | @NoArgsConstructor | ||
+ | @Entity(name = " | ||
+ | public class Product { | ||
+ | |||
+ | @Schema(description = " | ||
+ | @Id | ||
+ | @GeneratedValue(strategy = GenerationType.IDENTITY) | ||
+ | private long id; | ||
+ | |||
+ | @Schema(description = " | ||
+ | @NotBlank | ||
+ | @Column | ||
+ | private String name; | ||
+ | |||
+ | @Schema(description = " | ||
+ | @Column | ||
+ | private String description; | ||
+ | |||
+ | @Schema(description = " | ||
+ | @NotBlank | ||
+ | @Column | ||
+ | private String category; | ||
+ | |||
+ | @Schema(description = " | ||
+ | @Column | ||
+ | @Min(value = 0) | ||
+ | private float price; | ||
+ | |||
+ | @Schema(description = "Fecha de registro del producto", | ||
+ | @Column(name = " | ||
+ | private LocalDateTime creationDate; | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | Asi, una vez que documentemos el proyecto como API, lo lanzaremos. Las librerías de SpringDoc incluidas unidas a la documentación que hemos añadido a las clases del proyecto, hacen que se generen tres nuevos endpoints: | ||
+ | |||
+ | * http:// | ||
+ | * http:// | ||
+ | * http:// | ||
+ | |||
+ | A continuación se muestran algunas capturas para ilustrar las posibilidades de ese nuevo portal que se genera con nuestro proyecto de API. | ||
+ | |||
+ | < | ||
+ | {{ swagger-ui.png }} | ||
+ | < | ||
+ | </ | ||
+ | |||
+ | < | ||
+ | {{ swagger-ui-schemas.png }} | ||
+ | < | ||
+ | </ | ||
+ | |||
+ | < | ||
+ | {{ swagger-ui-operation.png }} | ||
+ | < | ||
+ | </ | ||
+ | |||
+ | < | ||
+ | {{ swagger-ui-try.png }} | ||
+ | < | ||
+ | </ | ||
+ | |||
+ | ---- | ||
+ | |||
+ | https:// | ||
+ | |||
+ | ---- | ||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | ===== Proyectos de ejemplo ===== | ||
+ | |||
+ | Todos los proyectos de ejemplo de esta parte están en el [[http:// | ||
+ | |||
+ | Los proyectos que se vayan haciendo en clase estarán disponibles en el [[http:// | ||
+ | |||
+ | Para manejaros con Git recordad que tenéis una serie de videotutoriales en [[https:// | ||
+ | |||
+ | |||
+ | ---- | ||
+ | |||
+ | (c) 2021-{{date> | ||
+ |
apuntes/api.1594981058.txt.gz · Last modified: 17/07/2020 10:17 by Santiago Faci