DEV Community

Cover image for Spring Rest Repositories para acelerar MVP e PoC
Fabiano Góes • e-Programar
Fabiano Góes • e-Programar

Posted on

Spring Rest Repositories para acelerar MVP e PoC

1. O Problema que queremos resolver

As vezes precisamos criar um MVP e testar uma ideia rápido para ter feedback o quanto antes e é aqui que o Spring REST Repositories brilha acelerando muito o desenvolvimento de uma API REST.
Neste artigo vamos criar um CRUD de uma API REST utilizando alguns recursos muito interessantes no ecosistema Spring.

O que vamos usar:

  • Spring Data/JPA para fazer o trabalho duro de ORM e manipular os dados no Banco.
  • Spring REST Repositories para expor nosso CRUD através de uma API REST.
  • H2 como Banco de Dados Relacional em memória.
  • Lombok para automatizar nossos Getters, Setters, Constructors, ToString.

2. A Solução

Vamos usar o site SPRING INITIALIZR para criação do projeto, acesse a URL: https://start.spring.io/ e configure conforme a imagem e ao final clique em “Generate Project

SPRING INITIALIZR

Na sessão de Dependences digite: Web, JPA, H2, Rest Repositories. Após clicar em “Generate Project” será feito o download do projeto em um arquivo .zip, descompacte e importe em sua IDE de preferencia.

Agora vamos criar nosso modelo “Person”, que neste caso será bem simple pois o Foco é o “Spring Rest Repositories”.

import lombok.Data;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

@Data
@Entity
public class Person {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long id;

    private String firstName;
    private String lastName;

}
Enter fullscreen mode Exit fullscreen mode

Aqui usamos algumas annotations:

  • Entity: do conhecido JPA para tornar nosso modelo um ORM.
  • Id: do JPA para setar nosso id como Chave primária.
  • GeneratedValue: do JPA para setar nosso id como AutoIncrement.
  • Data: do Lombok para criar nossos Getters and Setters.

Com nosso modelo ORM criado podemos criar nossa Interface Repository, e aqui está o pulo do gato onde acontece toda a Magia do Spring.

import java.util.List;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.data.repository.query.Param;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;

@RepositoryRestResource(collectionResourceRel = "people", path = "people")
public interface PersonRepository extends PagingAndSortingRepository<Person, Long> {

   List<Person> findByLastName(@Param("name") String name);

}
Enter fullscreen mode Exit fullscreen mode

Aqui cabe alguns comentários:
Quem já está familiarizado com Spring Data sabe que é comum anotar essa Interface com @Repository e aqui estamos anotando com @RepositoryRestResource.
Com essa annotation o Spring irá fazer uma linda magia e apenas com essa interface ele já ira criar nossa camada de Repository que saberá receber nosso modelo Person e executar todas as tarefas de CRUD em nosso Banco de Dados, além disso ele criar uma camada de Controller internamente e irá expor esse nosso CRUD através de uma API REST.
Isso mesmo, não teremos que criar nem a nossa camada Service nem a nossa camada Controller, Automágicamente o Spring fará esse trabalha para nós através do Spring Rest Repositories =).
E ainda herdamos nossa interface de “PagingAndSortingRepository” que irá gerar nossas listas paginada, mais uma vez Automágicamente =).

Neste momento se executarmos nossa aplicação já temos uma API REST com todas as operações CRUD de Person além de um endpoint de consulta por “LastName”.

Aqui a lista de endpoints disponíveis na nossa API REST:

GET http://localhost:8080
GET http://localhost:8080/people
GET http://localhost:8080/people/{id}
GET http://localhost:8080/people/search
POST http://localhost:8080/people
PUT http://localhost:8080/people/{id}
PATCH http://localhost:8080/people/{id}
DELETE http://localhost:8080/people/{id}
Enter fullscreen mode Exit fullscreen mode

PUT substitui um registro inteiro. Campos não fornecidos serão substituídos por null.
PATCH pode ser usado para atualizar um subconjunto de itens.

Segue alguns exemplos de Teste utilizando o curl.

POST:

$ curl -i -X POST -H "Content-Type:application/json" -d '{"firstName": "Frodo", "lastName": "Baggins"}' 


http://localhost:8080/people
HTTP/1.1 201 
Location: http://localhost:8080/people/1
Content-Type: application/hal+json;charset=UTF-8
Transfer-Encoding: chunked
Date: Mon, 04 Feb 2019 21:03:47 GMT
{
  "firstName" : "Frodo",
  "lastName" : "Baggins",
  "_links" : {
    "self" : {
      "href" : "http://localhost:8080/people/1"
    },
    "person" : {
      "href" : "http://localhost:8080/people/1"
    }
  }
}%
Enter fullscreen mode Exit fullscreen mode

GET All:

$ curl http://localhost:8080/people  


{
  "_embedded" : {
    "people" : [ {
      "firstName" : "Frodo",
      "lastName" : "Baggins",
      "_links" : {
        "self" : {
          "href" : "http://localhost:8080/people/1"
        },
        "person" : {
          "href" : "http://localhost:8080/people/1"
        }
      }
    } ]
  },
  "_links" : {
    "self" : {
      "href" : "http://localhost:8080/people{?page,size,sort}",
      "templated" : true
    },
    "profile" : {
      "href" : "http://localhost:8080/profile/people"
    },
    "search" : {
      "href" : "http://localhost:8080/people/search"
    }
  },
  "page" : {
    "size" : 20,
    "totalElements" : 1,
    "totalPages" : 1,
    "number" : 0
  }
}%

Enter fullscreen mode Exit fullscreen mode

Perceba neste exemplo que o resultado é paginado com: size, totalElements, totalPages, number.

Adicionando Swagger

  1. Adicione as dependências no pom.xml
<!-- Swagger -->
<dependency>
   <groupId>io.springfox</groupId>
   <artifactId>springfox-swagger2</artifactId>
   <version>3.0.0-SNAPSHOT</version>
</dependency>
<dependency>
   <groupId>io.springfox</groupId>
   <artifactId>springfox-data-rest</artifactId>
   <version>3.0.0-SNAPSHOT</version>
</dependency>
<dependency>
   <groupId>io.springfox</groupId>
   <artifactId>springfox-swagger-ui</artifactId>
   <version>3.0.0-SNAPSHOT</version>
</dependency>
Enter fullscreen mode Exit fullscreen mode
  1. Adicione também no pom.xml o repositório da dependência:
<repositories>
   <repository>
      <id>jcenter-snapshots</id>
      <name>jcenter</name>
      <url>http://oss.jfrog.org/artifactory/oss-snapshot-local/</url>
   </repository>
</repositories>
Enter fullscreen mode Exit fullscreen mode

É importante adicionar esse repository porque no repositório central ainda não tem essa versão do swagger, e é nela que estão implementando essa feature do Swagger para suportar o Spring Rest Repositories.

  1. A classe Configuration do Swagger
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.data.rest.configuration.SpringDataRestConfiguration;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2WebMvc;

@Configuration
@EnableSwagger2WebMvc
@Import(SpringDataRestConfiguration.class)
public class SwaggerConfiguration {

    private static final String PATH_MAPPING = "/";

    private static final String PACKAGE_BASE = "com.eprogramar.demorepositoryrestresource";

    @Value("${info.app.version}")
    private String projectVersion;

    @Value("${info.app.name}")
    private String projectName;

    @Value("${info.app.description}")
    private String projectDescription;

    @Value("${spring.profiles.active}")
    private String activeProfile;

    @Bean
    Docket rsApi() {
        return new Docket(DocumentationType.SWAGGER_12)
                .apiInfo(apiInfo())
                .select()
                .apis(RequestHandlerSelectors.any())
                .paths(PathSelectors.any())
                .build()
                .pathMapping(PATH_MAPPING)
                .useDefaultResponseMessages(false);
    }

    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                .title(projectName)
                .description(projectDescription + " - Profile: " + activeProfile)
                .version(projectVersion)
                .build();
    }

}
Enter fullscreen mode Exit fullscreen mode

Adicionei algumas properties no application.properites só pra facilitar as coisas não seria uma coisa obrigatória.

Ok, executando a aplicação agora podemos ver todos os endpoints documentados, acesse: http://localhost:8080/swagger-ui.html
Swagger

Disclimer

Veja Também meu video:
Como Criar uma API Rest Kotlin com Persistencia e Paginação em 6 minutos

3. Conclusão

Neste artigo aprendemos utilizar algumas magias do Spring onde ele automatizou a criação de nosso ORM e ainda criou nossa API REST automágicamente.
Com isso ganhamos muito tempo quando precisamos criar CRUD e expor através de uma API REST.
Claro, em caso simples onde não precisamos de regras para nosso CRUD isso pode ser uma boa opção, se combinar com Bean Validation para validar alguns campos e ainda utilizar de um Handle para interceptar os Erros e soltar uma mensagem mais amigável fica uma solução bem legal.
Em casos onde tem muitas regras ai é aconselhável utilizar o modelo mais conceitual com a Camada Service e Controller.

O código pode ser visto no Github:
https://github.com/e-programar/demo-repository-rest-resource

Referencia: https://spring.io/guides/gs/accessing-data-rest/

Top comments (0)