Arquivo para abril de 2016

Criando o primeiro endpoint REST com SpringBoot



Neste post daremos continuidade a uma série de postagens sobre Web-Services divididos entre conceitos teóricos e praticos. Nos 3 primeiros posts focou-se em teoria com um sobre Web Services, outro sobre RESTful Web Services e mais um sobre os HTTP Status Codes mais comuns. Este post por sua vez complementa o que foi desenvolvido no post Do zero ao REST em 5 minutos com SpringBoot. Então antes de começar veja o post anterior ou baixe o código e vamos entender na prática como funcionam os verbos REST.



Agora faremos algumas alterações no projeto desenvolvido no post anterior. Para começar crie os seguintes pacotes br.com.erudio.models, br.com.erudio.services, br.com.erudio.services.implementations e br.com.erudio.web.controllers. Depois mova a classe Greeting para o pacote br.com.erudio.models e a classe GreetingController para o pacote br.com.erudio.web.controllers. A estrutura de pacotes deve ficar similar a imagem abaixo.

postagem_2_0



Feito isto crie uma classe chamada Person, no pacote br.com.erudio.models, com as informações que serão representadas pelo nosso endpoint REST.

package br.com.erudio.models;

import java.io.Serializable;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;

@JsonIgnoreProperties(ignoreUnknown = true)
public class Person implements Serializable{
    
    private static final long serialVersionUID = 1L;
    
    private Long id;
    private String firstName;
    private String lastName;
    private String address;
    
    public Long getId() {
        return id;
    }
    
    public void setId(Long id) {
        this.id = id;
    }
    
    public String getFirstName() {
        return firstName;
    }
    
    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }
    
    public String getLastName() {
        return lastName;
    }
    
    public void setLastName(String lastName) {
        this.lastName = lastName;
    }
    
    public String getAddress() {
        return address;
    }
    
    public void setAddress(String address) {
        this.address = address;
    }
}


Feito isto crie uma interface com o nome PersonService no pacote br.com.erudio.models.


package br.com.erudio.services;

import java.util.List;

import br.com.erudio.models.Person;

public interface PersonService {
    
    Person create(final Person person);
    Person findById(final String personId);
    List<Person> findAll();
    Person update(Person person);
    void delete(final String personId);

}



Agora vamos criar a implementação para a interface PersonService. No pacote br.com.erudio.services.implementations crie a classe PersonServiceImpl que implementa a interface que acabamos de criar.

package br.com.erudio.services.implementations;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicLong;

import org.springframework.stereotype.Service;

import br.com.erudio.models.Person;
import br.com.erudio.services.PersonService;

@Service
public class PersonServiceImpl implements PersonService {
    
	// Contador responsável por gerar um fake ID já que não estamos
	// acessando nenhum banco de dados
    private final AtomicLong counter = new AtomicLong();

	// Metodo responsável por criar uma nova pessoa
	// Se tivéssemos um banco de dados esse seria o
	// momento de persistir os dados
    @Override
    public Person create(Person person) {
        return person;
    }

	// Método responsável por retornar uma pessoa
	// como não acessamos nenhuma base de dados
	// estamos retornando um mock
    @Override
    public Person findById(String personId) {
        Person person = new Person();
        person.setId(counter.incrementAndGet());
        person.setFirstName("Leandro");
        person.setLastName("Costa");
        person.setAddress("Uberlândia - Minas Gerais - Brasil");
        return person;
    }

	// Método responsável por retornar todas as pessoas
	// mais uma vez essas informações são mocks
    @Override
    public List<Person> findAll() {
        ArrayList<Person> persons = new ArrayList<>();
        for (int i = 0; i < 8; i++) {
            Person person = mockPerson(i);
            persons.add(person);
        }
        return persons;
    }
    
	// Método responsável por atualizar uma pessoa
	// por ser mock retornamos a mesma informação passada
    @Override
    public Person update(Person person) {
    	return person;
    }

	// Método responsável por deletar
	// uma pessoa a partir de um ID
    @Override
    public void delete(String personId) {

    }
		
	// Método responsável por mockar uma pessoa
    private Person mockPerson(int i) {
        Person person = new Person();
        person.setId(counter.incrementAndGet());
        person.setFirstName("Person Name " + i);
        person.setLastName("Last Name " + i);
        person.setAddress("Some Address in Brasil " + i);
        return person;
    }
}



Por fim crie a classe PersonController, responsável por expor o endpoint de pessoas, no pacote br.com.erudio.web.controllers.

package br.com.erudio.web.controllers;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.PathVariable;
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.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;

import br.com.erudio.models.Person;
import br.com.erudio.services.PersonService;

@RestController
//Mapeia as requisições de localhost:8080/person/
@RequestMapping("/person/")
public class PersonController {
    
    @Autowired
    private PersonService personService;
    
    @ResponseStatus(HttpStatus.OK) //Por padrão responde com o status code 200 success
    @RequestMapping(value = "/{personId}",
		//Mapeia as requisições GET para localhost:8080/person/
		//recebendo um ID como @PathVariable
		method = RequestMethod.GET, 
		produces = MediaType.APPLICATION_JSON_VALUE)
		// Produz JSON como retorno
    public Person get(@PathVariable(value = "personId") String personId){
        return personService.findById(personId);
    }
    
    @ResponseStatus(HttpStatus.OK)
	//Por padrão responde com o status code 200 success
    @RequestMapping(value = "/findAll",
		//Mapeia as requisições GET para localhost:8080/person/findAll
		method = RequestMethod.GET,
		produces = MediaType.APPLICATION_JSON_VALUE)
		// Produz JSON como retorno
    public List<Person> findAll(){
        return personService.findAll();
    }
    
    @ResponseStatus(HttpStatus.OK)
	//Por padrão responde com o status code 200 success
    @RequestMapping(method = RequestMethod.PUT,
	//Mapeia as requisições PUT para localhost:8080/person/
		consumes = MediaType.APPLICATION_JSON_VALUE,
		// Consome JSON enviado no corpo da requisição
		produces = MediaType.APPLICATION_JSON_VALUE)
		// Produz JSON como retorno
    public Person create(@RequestBody Person person){
        return personService.create(person);
    }
    
    @ResponseStatus(HttpStatus.OK)
	//Por padrão responde com o status code 200 success
    @RequestMapping(method = RequestMethod.POST,
	//Mapeia as requisições POST para localhost:8080/person/
		consumes = MediaType.APPLICATION_JSON_VALUE)
		// Consome JSON enviado no corpo da requisição
    public Person update(@RequestBody Person person){
        return personService.update(person);
    }

    @ResponseStatus(HttpStatus.OK)
	//Por padrão responde com o status code 200 success
    @RequestMapping(value = "/{personId}",
		method = RequestMethod.DELETE)
		//Mapeia as requisições DELETE para localhost:8080/person/ 
		//recebendo um ID como @PathVariable
    public void delete(@PathVariable(value = "personId") String personId){
        personService.delete(personId);
    }
}



Agora que terminamos nossa codificação acesse a classe Application e inicie a aplicação como no post anterior. Para testar nosso endpoint e cada uma de suas operações usaremos o plugin do Chrome Postman.


Primeiro faremos uma requisição do tipo GET chamando a operação findAll para o recurso localhost:8080/person/findAll. Como se pode ver na imagem abaixo obtemos como resposta um JSON com um array de pessoas.

postagem_2_2



Agora faremos uma requisição do tipo GET chamando a operação localhost:8080/person/1 passando como @PathVariable o ID da pessoa que desejamos recuperar. Da mesma forma que na requisição anterior recebemos como resposta um JSON com 1 objeto pessoa.

postagem_2_1

Agora faremos uma requisição do tipo POST (esse é o verbo REST usado para persistir informações) chamando a operação localhost:8080/person/ passando como parâmetro um JSON com um objeto pessoa no corpo da requisição. Para isso no Postman precisamos setar o tipo de requisição como POST, na aba Body definimos o JSON que representa o objeto pessoa a ser gravado, selecionamos a opção raw, definimos a opção JSON(application/json) e por fim executamos a request através do botão send.

postagem_2_3

Na imagem abaixo podemos ver o body da response retornada com um ID definido pela aplicação.


postagem_2_4

Agora faremos uma requisição do tipo PUT (esse é o verbo REST usado para atualizar informações) chamando a operação localhost:8080/person/ passando como parâmetro um JSON com um objeto pessoa no corpo da requisição. Lembrando que essa representação de pessoa deve ter um ID que será usado pra localizar e atualizar um recurso na base. Para isso no Postman precisamos setar informações similares ao post a unica diferença é que o tipo de requisição deve ser o PUT.



postagem_2_5

Como se pode ver na imagem abaixo o body da response retorna o nosso objeto JSON com as alterações.

postagem_2_6



Por fim faremos uma requisição do tipo DELETE (verbo REST usado excluir informações) chamando a operação localhost:8080/person/1 passando como @PathVariable o ID da pessoa que desejamos remover da base. Esse tipo de requisição retorna como resposta um body vazio e um StatusCode 200 caso a operação seja executada com sucesso os StatusCode 204 (no content), 401 (Unauthorized), 403 (forbiden), 404 (not found) ou 500 (internal server error) podem ser retornados.


postagem_2_7


Dessa forma abordamos os 4 verbos principais do HTTP usados em aplicações REST. Lembrando que você pode baixar o código aqui e descompactar o arquivo zip e importar não sua IDE de preferencia ou clonar usando Git:

git clone https://github.com/leandrocgsi/simple-rest-example-verbs.git



Continue ligado no blog, por que no próximo post iremos documentar a nossa API com o framewrok Swagger. E claro a abordagem nesses posts também será totalmente mão na massa. É isso aí bons estudos.

Tags: , , , ,

Do zero ao REST em 5 minutos com SpringBoot



Este post visa explicar de forma simples como criar um “hello world” RESTFul web service com Spring Boot.



Fique ligado no blog, por que, como já foi dito, nos próximos 2 posts entraremos em maiores detalhes sobre a sopa de letrinhas dos verbos REST, POST, PUT, GET e DELETE na prática e depois documentaremos a nossa API com o framewrok Swagger. E abordagem nesses posts será totalmente mão na massa. É isso aí bons estudos.

Cerca de 5 minutos
Qualquer IDE de preferência o Eclipse
JDK 1.8 ou superior
Maven 3.33+



Onde baixar os códigos do projeto

Você pode baixar o código aqui e descompactar o arquivo zip e importar não sua IDE de preferencia ou clonar usando Git:

git clone https://github.com/leandrocgsi/simple-rest-example.git



Para mais detalhes e para evoluir este projeto acesse a página de guias de inicialização da fundação Spring. Além disso serão feitos mais 2 posts fechando uma série sobre Spring Boot e RESTful abordando os 4 principais verbos REST e como documentar API’s com o framework Swagger. O código dos próximos posts já está implementado e você pode acessar o de verbos aqui e o com Swagger aqui.



E a teoria como fica?


Se você está lendo este post eu acredito que você conheça o mínimo de teoria sobre REST e Web-Services mas se não conhece temos 3 posts que abordam esses temas de forma teórica sendo um sobre Web Services, outro sobre RESTful Web Services e outro sobre os HTTP Status Codes em Serviços REST mais comuns.

Hora de codar



Então chega de conversa e vamos botar a mão na massa ou melhor no código. Com o Eclipse aberto clique em novo escolha a opção Maven Project como na imagem abaixo.

1



Na próxima janela selecione a opção “Create a simple project(skyp archetype selection)”. Isso “diz” ao Maven que você irá construir seu projeto do zero com uma estrutura padrão Maven mas sem usar nenhum Archetype pronto.

2



Na próxima tela defina o Goup Id do seu projeto, no nosso caso “br.com.erudio”. Defina também o Artifact Id (nome) do seu projeto e a versão. Feito isto clique em next.

3



Se tudo tiver corrido bem você terá um projeto com uma estrutura similar à imagem abaixo. Abra o arquivo “pom.xml” e vamos fazer algumas alterações nele.

4



A estrutura original do pom deve ser algo similar a esta:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    
    <groupId>br.com.erudio</groupId>
    <artifactId>simple-rest-example</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    
</project>



Primeiro informamos o “parentesco” do nosso projeto em relação ao Spring boot. Logo abaixo adicionamos a dependência do Spring Boot Starter Web que como o próprio nome diz é o responsável por inicializar nossa aplicação. Definimos também a versão do Java no nosso caso 1.8. Depois precisamos configurar o processo de build que é extremamente simples. E por fim adicionamos os repositórios de onde o Maven irá baixar as dependências e plug-ins necessários ao projeto. Feito isso nos já temos a estrutura básica de um projeto Spring Boot.

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    
    <groupId>br.com.erudio</groupId>
    <artifactId>simple-rest-example</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    
    <!-- Adicionando o Spring Boot ao projeto -->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.3.3.RELEASE</version>
    </parent>
    
    <!-- Adicionando a dependencia do Spring Boot Starter Web -->
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>

    <!-- Configurando a versão do Java -->
    <properties>
        <java.version>1.8</java.version>
    </properties>
    
    <!-- Configurando o processo de build da aplicação -->
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
    
    <!-- Adicionando o repositório do Spring de onde o Maven irá baixar as dependências -->
    <repositories>
        <repository>
            <id>spring-releases</id>
            <url>https://repo.spring.io/libs-release</url>
        </repository>
    </repositories>
    
    <!-- Adicionando o repositório do Spring de onde o Maven irá baixar os plugins -->
    <pluginRepositories>
        <pluginRepository>
            <id>spring-releases</id>
            <url>https://repo.spring.io/libs-release</url>
        </pluginRepository>
    </pluginRepositories>
    
</project>



Como se pode ver o nosso projeto está com um marker de erro e a versão do Java está como 1.5 e não 1.8 como definimos no pom.xml.

7



Clique com o direito sobre o projeto escola a opção Build Path >> Configure Build Path

8



Na aba libraries selecione sua JRE System Library e clique em editar.

9



Na proxima janela selecione o radio Alternate JRE e escolha sua versão do Java e clique em Finish.

10



Como se pode ver agora a versão esta correta, então clique em OK.

11



Além disso temos um Mavem problem etratanto isso é apenas um bug do Eclipse e apesar do warning o projeto executa normalmente. Para remover basta escolher a opção quick fix.

12



Na janela a seguir escolha a opção Update project configuration clique em Finish e adeus warning.

13



Agora que eliminamos todos os warnings o ambiente está pronto. Selecione o source folder src/main/java.

14



Clique com o direito New >> Package

15



Na próxima janela defina o nome do pacote no nosso caso “br.com.erudio”.

16



Feito isso abra o souce folder e clicando sobre o pacote com o botão direito New >> Class

17



Na próxima janela defina o nome Greeting(Saudação em inglês já que é um Hello World) e insira o código abaixo. Como você pode perceber é um simples POJO que representa o objeto que será retornado aos clientes de nossa API.


package br.com.erudio;

public class Greeting {

    private final long id;
    private final String content;

    public Greeting(long id, String content) {
        this.id = id;
        this.content = content;
    }

    public long getId() {
        return id;
    }

    public String getContent() {
        return content;
    }
}



Agora crie uma nova classe com o nome GreetingController que é o nosso endpoit que receberá as requisições REST. Como se pode ver as requisições para a url {{contexto}}/greeting invocarão o método greeting que recebe um @RequestParam com um nome. Quando esse valor não é informado o valor padrão é “World”. As requisições para esse endpoint retornam uma saudação com um id automático simulando um acesso a um banco de dados e uma string com a saudação.


package br.com.erudio;

import java.util.concurrent.atomic.AtomicLong;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class GreetingController {

    private static final String template = "Hello, %s!";
    private final AtomicLong counter = new AtomicLong();

    @RequestMapping("/greeting")
    public Greeting greeting(@RequestParam(value="name", defaultValue="World") String name) {
        return new Greeting(counter.incrementAndGet(), String.format(template, name));
    }
}



Agora vamos definir a classe de inicialização de nossa aplicação chamada Application. Acredite ou não com apenas o trecho de código abaixo você tem sua aplicação pronta sem necessidade de container ou server. Sim o Spring Boot te liberta de Tomcat, Jetty ou os “obesos” JBoss e GlassFish e seus EJB’s.


package br.com.erudio;

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

@SpringBootApplication
public class Application {

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



Com a aplicação pronta clique com o direito dobre a classe Application Run As >> Java Application. Caso você esteja usando a Spring Source Tool Suite (ferramenta baseada no Eclipse com foco em desenvolvimento Spring) como é o meu caso pode excolher a opção Spring Boot App.

18



Se você tiver feito tudo corretamente terá um console parecido com a imagem abaixo observe que o endpoint /greeting foi mapeado e que nossa aplicação iniciou em apenas 4 segundos.

19



Vá no browser de sua preferencia e acesse localhost:8080/greeting e terá uma resposta parecida com a imagem abaixo.

20



Agora adicione um parametro a mais a nossa url localhost:8080/greeting?name=Olá Semeru Blog ou outro parametro de sua preferência e terá uma resposta similar à imagem abaixo.

21



Fique ligado no blog, por que, como já foi dito, nos próximos 2 posts entraremos em maiores detalhes sobre a sopa de letrinhas dos verbos REST, POST, PUT, GET e DELETE na prática e depois documentaremos a nossa API com o framewrok Swagger. E abordagem nesses posts será totalmente mão na massa. É isso aí bons estudos.

Tags: , ,