Skip to content

Commit

Permalink
Merge pull request #6 from Hangar-Tech/feat-add-swagger
Browse files Browse the repository at this point in the history
Feat add swagger
  • Loading branch information
MatheusVict authored Mar 4, 2024
2 parents 3b198b7 + 21e8d36 commit 4d4c9c9
Show file tree
Hide file tree
Showing 14 changed files with 233 additions and 7 deletions.
11 changes: 11 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
<description>sempre-alerta</description>
<properties>
<java.version>17</java.version>
<springdoc-openapi-starter-webmvc-ui.version>2.3.0</springdoc-openapi-starter-webmvc-ui.version>
</properties>
<dependencies>
<dependency>
Expand All @@ -37,6 +38,16 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<version>${springdoc-openapi-starter-webmvc-ui.version}</version>
</dependency>
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-api</artifactId>
<version>${springdoc-openapi-starter-webmvc-ui.version}</version>
</dependency>
<dependency>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-core</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@

import com.institutosemprealerta.semprealerta.domain.service.StorageService;
import com.institutosemprealerta.semprealerta.domain.ports.out.responses.FileResponse;
import com.institutosemprealerta.semprealerta.swagger.annotations.BadRequestResponse;
import com.institutosemprealerta.semprealerta.swagger.annotations.CreatedResponse;
import com.institutosemprealerta.semprealerta.swagger.annotations.NotFoundResponse;
import com.institutosemprealerta.semprealerta.swagger.annotations.OkResponse;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpHeaders;
Expand All @@ -13,19 +19,24 @@
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;

import java.io.IOException;
import java.net.URI;
import java.util.List;

@Controller
@RequestMapping("/api/v1/files")
@Tag(name = "Files", description = "Files management")
public class FilesStorageController {
private StorageService storageService;

public FilesStorageController(StorageService storageService) {
this.storageService = storageService;
}

@PostMapping("/upload")
public ResponseEntity<String> uploadFile(@RequestParam("file") MultipartFile file, @RequestParam("file_type") String fileType) {
@Operation(summary = "Faça o upload de um arquivo", description = "Upload de um arquivo para o servidor")
@PostMapping(value = "/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
@CreatedResponse
@BadRequestResponse
public ResponseEntity<String> uploadFile(@RequestPart("file") MultipartFile file, @RequestParam("file_type") String fileType) {

String fileName = storageService.store(file, fileType);

Expand All @@ -34,11 +45,16 @@ public ResponseEntity<String> uploadFile(@RequestParam("file") MultipartFile fil
.path(fileName)
.toUriString();

return ResponseEntity.ok("File uploaded successfully, file name: " + fileName + " on path: " + fileDownloadUri);
URI uri = URI.create(fileDownloadUri);
return ResponseEntity.created(uri).body("File uploaded successfully, file name: " + fileName + " on path: " + fileDownloadUri);
}

@GetMapping("/download/{fileName:.+}")
@ResponseBody
@Operation(summary = "Download de um arquivo", description = "Baixe um arquivo pelo nome do arquivo")
@OkResponse
@NotFoundResponse
@BadRequestResponse
public ResponseEntity<Resource> downloadFile(
@PathVariable String fileName,
HttpServletRequest request
Expand All @@ -62,6 +78,9 @@ public ResponseEntity<Resource> downloadFile(
}

@GetMapping("/list")
@Operation(summary = "List todos os arquivos", description = "Liste todos os arquivos do servidor")
@OkResponse
@BadRequestResponse
public ResponseEntity<List<FileResponse>> listFiles() throws IOException {
List<FileResponse> fileNames = storageService.loadAll();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

import com.institutosemprealerta.semprealerta.domain.service.PostService;
import com.institutosemprealerta.semprealerta.domain.model.Post;
import com.institutosemprealerta.semprealerta.swagger.annotations.*;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
Expand All @@ -12,6 +15,7 @@

@RestController
@RequestMapping("api/v1/posts")
@Tag(name = "Post", description = "Post management")
public class PostController {
private final PostService postService;

Expand All @@ -20,28 +24,43 @@ public PostController(PostService postService) {
}

@GetMapping
@Operation(summary = "Lista de todos os posts", description = "Lista de todos os posts com paginação")
@OkResponse
public ResponseEntity<Page<Post>> getAllPosts(Pageable pageable) {
return ResponseEntity.ok(postService.listAll(pageable));
}

@PostMapping
@Operation(summary = "Criar postagem", description = "Crie uma nova postagem")
@CreatedResponse
@BadRequestResponse
public ResponseEntity<?> createPost(@Valid @RequestBody Post post) {
String slug = postService.save(post);
return ResponseEntity.created(URI.create("/api/v1/posts/" + slug)).build();
}

@GetMapping("/{slug}")
@Operation(summary = "Pegar post pelo slug", description = "Procura um post pelo seu slug")
@OkResponse
@NotFoundResponse
public ResponseEntity<Post> getPostBySlug(@PathVariable String slug) {
return ResponseEntity.ok(postService.findBySlug(slug));
}

@PutMapping("/{id}")
@Operation(summary = "Atualizar post", description = "Atualize um post existente pelo seu id")
@NoContentResponse
@NotFoundResponse
@BadRequestResponse
public ResponseEntity<?> updatePost(@PathVariable Long id, @Valid @RequestBody Post post) {
postService.update(id, post);
return ResponseEntity.noContent().build();
}

@DeleteMapping("/{id}")
@Operation(summary = "Deletar post", description = "Deleta um post existente pelo seu id")
@NoContentResponse
@NotFoundResponse
public ResponseEntity<?> deletePost(@PathVariable Long id) {
postService.delete(id);
return ResponseEntity.noContent().build();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,17 @@
import com.institutosemprealerta.semprealerta.domain.model.UserDTO;
import com.institutosemprealerta.semprealerta.domain.ports.out.responses.UserResponse;
import com.institutosemprealerta.semprealerta.infrastructure.entity.user.User;
import com.institutosemprealerta.semprealerta.swagger.annotations.*;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("api/v1/user")
@Tag(name = "User", description = "Administração de usuários")
public class UserController {

private final UserService userService;
Expand All @@ -20,30 +24,46 @@ public UserController(UserService userService) {
}

@PostMapping
@Operation(summary = "Criação de um usuário", description = "Criação de um usuário no sistema")
@CreatedResponse
@ConflictResponse
public ResponseEntity<?> createUser(@Valid @RequestBody UserDTO user) {
userService.save(user.toDomain());
return ResponseEntity.status(HttpStatus.CREATED).build();
}

@GetMapping("/{id}")
@Operation(summary = "Busca de um usuário", description = "Busca de um usuário pelo id")
@OkResponse
@NotFoundResponse
public ResponseEntity<UserResponse> findById(@PathVariable int id) {
User userFound = userService.findById(id);
return ResponseEntity.ok().body(UserResponse.toResponse(userFound));
}

@GetMapping("/registration/{reg}")
@Operation(summary = "Busca de um usuário", description = "Busca de um usuário pela matrícula")
@OkResponse
@NotFoundResponse
public ResponseEntity<UserResponse> findByRegistration(@PathVariable String reg) {
User userFound = userService.findByRegistration(reg);
return ResponseEntity.ok().body(UserResponse.toResponse(userFound));
}

@PutMapping("/{id}")
@Operation(summary = "Atualização de um usuário", description = "Atualização de um usuário pelo id")
@NoContentResponse
@NotFoundResponse
@ConflictResponse
public ResponseEntity<?> updateUser(@PathVariable int id, @RequestBody UserDTO user) {
userService.update(id, user.toDomain());
return ResponseEntity.status(HttpStatus.NO_CONTENT).build();
return ResponseEntity.noContent().build();
}

@DeleteMapping("/{id}")
@Operation(summary = "Deleção de um usuário", description = "Deleção de um usuário pelo id")
@NoContentResponse
@NotFoundResponse
public ResponseEntity<?> deleteUser(@PathVariable int id) {
userService.delete(id);
return ResponseEntity.status(HttpStatus.NO_CONTENT).build();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.institutosemprealerta.semprealerta.domain.model;

import io.swagger.v3.oas.annotations.Hidden;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import lombok.Getter;
import lombok.Setter;
Expand All @@ -10,15 +12,24 @@
@Setter
public class Post {

@Hidden
private Long id;
@NotBlank(message = "Title is mandatory")

@NotBlank(message = "Title é obrigatorio")
@Schema(description = "Title do post", example = "Titulo do post")
private String title;

private String slug;

@NotBlank(message = "Content is mandatory")
@NotBlank(message = "Content é obrigatorio")
@Schema(description = "Contenteudo do post", example = "Conteudo do post")
private String content;
@NotBlank(message = "Banner is mandatory")

@NotBlank(message = "Banner é obrigatorio")
@Schema(description = "Banner do post", example = "https://www.https://github.com/MatheusVict.png")
private String banner;

@Hidden
private LocalDateTime createdAt;

public Post(Long id, String title, String slug, String content, String banner, LocalDateTime createdAt) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,28 +7,40 @@
import com.institutosemprealerta.semprealerta.infrastructure.entity.user.User;
import com.institutosemprealerta.semprealerta.infrastructure.entity.user.UserRoles;
import com.institutosemprealerta.semprealerta.utils.DateManipulation;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.*;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;

public record UserDTO(
@NotBlank
@Schema(description = "Nome do usuário", example = "Matheus Victor")
String name,
@Email
@Schema(description = "Email do usuário", example = "muryllo@gg.com")
String email,
@NotBlank
@Schema(description = "Senha do usuário", example = "123456")
String password,
@NotBlank
@Schema(description = "Telefone do usuário", example = "123456")
String phone,
@Schema(description = "Gênero do usuário", example = "Masculino")
String gender,
@PastOrPresent
@Schema(description = "Data de nascimento do usuário", example = "1999-12-12")
LocalDate birthDate,
@NotNull
@Schema(description = "Papel do usuário", example = "ADMIN")
UserRoles roles,
@Schema(description = "Rua do usuário", example = "Rua 1")
String street,
@Schema(description = "Número da casa do usuário", example = "123")
String number,
@Schema(description = "Cidade do usuário", example = "Igarassu e Lima")
String city,
@Schema(description = "CEP do usuário", example = "123456")
String zipCode

) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,22 @@

import com.institutosemprealerta.semprealerta.domain.ports.in.SlugGenerator;
import com.institutosemprealerta.semprealerta.domain.ports.in.impl.SlugifySlugGenerator;
import io.swagger.v3.oas.models.Components;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.info.Contact;
import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.oas.models.info.License;
import io.swagger.v3.oas.models.security.SecurityRequirement;
import io.swagger.v3.oas.models.security.SecurityScheme;
import io.swagger.v3.oas.models.servers.Server;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;

import java.util.List;

@Configuration
public class ApplicationConfig {

Expand All @@ -20,4 +30,29 @@ public SlugGenerator slugGenerator() {
public Pageable defaultPageable() {
return PageRequest.of(0, 10, Sort.by("createdAt").descending());
}

public SecurityScheme createAPIKeyScheme() {
return new SecurityScheme()
.type(SecurityScheme.Type.HTTP)
.bearerFormat("JWT")
.scheme("bearer");
}

@Bean
public OpenAPI openAPI() {
return new OpenAPI()
.addSecurityItem(new SecurityRequirement()
.addList("Bearer Authentication"))
.components(new Components().addSecuritySchemes(
"Bearer Authentication",
createAPIKeyScheme()
))
.info(new Info().title("Instituto Sempre Alerta API")
.description("API do Instituto Sempre Alerta.")
.version("1.0").contact(new Contact().name("Matheus Victor")
.email("matheusvictorhenrique@gmail.com")
.url("https://www.instituto-sempre-alerta.com.br/"))
.license(new License().name("License of API")
.url("https://opensource.org/license/mit/")));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.institutosemprealerta.semprealerta.swagger.annotations;

import com.institutosemprealerta.semprealerta.domain.ports.out.exceptions.ExceptionPattern;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@ApiResponse(responseCode = "400", description = "Erro de requisição inválida, no lado do cliente",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionPattern.class)))
public @interface BadRequestResponse {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.institutosemprealerta.semprealerta.swagger.annotations;

import com.institutosemprealerta.semprealerta.domain.ports.out.exceptions.ExceptionPattern;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@ApiResponse(responseCode = "409", description = "Possui alguns conflitos na requisição",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionPattern.class)))
public @interface ConflictResponse {
}
Loading

0 comments on commit 4d4c9c9

Please sign in to comment.