APIREST-DROPWIZARD

Api restfull con maven y dropwizard


APIREST-DROPWIZARD

Indice

Iniciando Proyecto Base

Adicionales

Temas a considerar

Creacion de proyecto en NetBeans

  • El proyecto parent fue creado en NetBeans con la opción: Maven -> POM Project

alt text

  • Para los modulos se utiliza la opción: Maven -> Java Application

alt text

Arriba

Ajustes en el POM

  • Agregar propiedad de versión de Dropwizard
      <properties>
          <dropwizard.version>INSERT VERSION HERE</dropwizard.version>
      </properties>
    
  • Adicionar la libreria como dependencia. ```xml
io.dropwizard dropwizard-core ${dropwizard.version}
[Arriba](#indice)

## Creando la clase de Configuracion

* Crear clase `RestConfiguration.java` base:

```java
import com.fasterxml.jackson.annotation.JsonProperty;
import io.dropwizard.Configuration;
import org.hibernate.validator.constraints.NotEmpty;
import io.federecio.dropwizard.swagger.SwaggerBundleConfiguration;

/**
 *
 * @author ISORTEGAH
 */
public class RestConfiguration extends Configuration{
    @NotEmpty
    @JsonProperty
    private String baseUrl;

    public String getBaseUrl() {
        return baseUrl;
    }

    public void setBaseUrl(String baseUrl) {
        this.baseUrl = baseUrl;
    }
    
    @JsonProperty("swagger")
    public SwaggerBundleConfiguration swaggerBundleConfiguration;
}

Referencia a ejemplo básico

  • Adicionar al pom.xml del modulo rest la siguiente dependencia:
<dependency>
    <groupId>com.smoketurner</groupId>
    <artifactId>dropwizard-swagger</artifactId>
    <version>1.0.0-rc2-1</version>
</dependency>
  • Contruir el archivo de configuración config.yml
    ```yml baseUrl: http://localhost swagger: resourcePackage: com.corpfolder.rest.resources server: applicationConnectors:
    • type: http port: 8080 ``` Arriba

      Crear la clase de la aplicacion

      • Dentro del siguiente código se puede ver la integración de swagger como opción de exposición gráfica de los servicios. ```java import io.dropwizard.Application; import io.dropwizard.setup.Bootstrap; import io.dropwizard.setup.Environment; import io.federecio.dropwizard.swagger.SwaggerBundle; import io.federecio.dropwizard.swagger.SwaggerBundleConfiguration;

/** *

  • @author ISORTEGAH */ public class ApiRestService extends Application{

    public static void main(String[] args) throws Exception { new ApiRestService().run(args); }

    @Override public void initialize(Bootstrap bootstrap) { bootstrap.addBundle(new SwaggerBundle() { protected SwaggerBundleConfiguration getSwaggerBundleConfiguration(RestConfiguration configuration) { return configuration.swaggerBundleConfiguration; } }); }

    @Override public void run(RestConfiguration configuration, Environment environment) { } ```

  • Adicionar healthCheck

Archivo AppHealthCheck.java

public class AppHealthCheck extends HealthCheck {
    @Override
    protected Result check() throws Exception {
        return Result.healthy();
    }

}

Adicionar al archivo ApiRestService.java

@Override
    public void run(RestConfiguration configuration,
                    Environment environment) {
        configFromAws( configuration.getAws() );
        environment.healthChecks().register("app", new AppHealthCheck());
    }

Esto evitara que se muestre el mensaje:

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!    THIS APPLICATION HAS NO HEALTHCHECKS. THIS MEANS YOU WILL NEVER KNOW      !
!     IF IT DIES IN PRODUCTION, WHICH MEANS YOU WILL NEVER KNOW IF YOU'RE      !
!    LETTING YOUR USERS DOWN. YOU SHOULD ADD A HEALTHCHECK FOR EACH OF YOUR    !
!         APPLICATION'S DEPENDENCIES WHICH FULLY (BUT LIGHTLY) TESTS IT.       !
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

Referencia

Application Health Checks with DropWizard Dropwizard Core

  • Adicionar plugins de contrucción del jar
      <build>
      <plugins>
              <plugin>
                      <groupId>org.apache.maven.plugins</groupId>
                      <artifactId>maven-surefire-plugin</artifactId>
                      <version>2.17</version>
                      <configuration>
                              <skipTests>true</skipTests>
                      </configuration>
              </plugin>
              <plugin>
                  <groupId>org.apache.maven.plugins</groupId>
                  <artifactId>maven-shade-plugin</artifactId>
                  <version>2.1</version>
                  <executions>
                      <execution>
                          <phase>package</phase>
                          <goals>
                              <goal>shade</goal>
                          </goals>
                          <configuration>
                              <transformers>
                                  <transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
                                  <transformer
                                      implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                                      <mainClass>com.isortegah.rest.ApiRestService</mainClass>
                                  </transformer>
                              </transformers>
                          </configuration>
                      </execution>
                  </executions>
              </plugin>
              <plugin>
                      <groupId>org.codehaus.mojo</groupId>
                      <artifactId>exec-maven-plugin</artifactId>
                      <version>1.2.1</version>
                      <executions>
                          <execution>
                              <goals>
                                  <goal>java</goal>
                              </goals>
                          </execution>
                      </executions>
                      <configuration>
                              <mainClass>com.isortegah.rest.ApiRestService</mainClass>
                              <arguments>
                                      <argument>server</argument>
                                      <argument>config.yml</argument>
                              </arguments>
                      </configuration>
              </plugin>
          </plugins>
      </build>
    

    Arriba

    Crear clase ejemplo

VersionResource.java

import com.codahale.metrics.annotation.Timed;
import com.isortegah.dtos.res.version.VersionDTO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

/**
 *
 * @author ISORTEGAH
 */
@Path("/version")
@Api(value = "/version")
@Produces(MediaType.APPLICATION_JSON)
public class VersionResource {
    @GET
    @Timed
    @ApiOperation(value = "Obtiene la información de la versión", position = 0)
    public VersionDTO version() {
        
       return new VersionDTO();
       
    }
}
  • Adicionar modulo dtos

alt text

  • Crear la clase VersionDTO.java

import com.fasterxml.jackson.annotation.JsonProperty;

/**
 *
 * @author ISORTEGAH
 */
public class VersionDTO {
    
    @JsonProperty
    private String nombre = "Versión 0.0.1-SNAPSHOT";

    @JsonProperty
    private String numero = "0.0.1";
    
    @JsonProperty
    private String autor = "ISORTEGAH";

    public String getAutor() {
        return autor;
    }

    public void setAutor(String autor) {
        this.autor = autor;
    }

    public String getNombre() {
            return nombre;
    }

    public void setNombre(String nombre) {
            this.nombre = nombre;
    }

    public String getNumero() {
            return numero;
    }

    public void setNumero(String numero) {
            this.numero = numero;
    }
    
}
  • Adicionar la dependencia del modulo dtos al pom.xml del modulo rest
<dependency>
    <groupId>${project.groupId}</groupId>
    <artifactId>dtos</artifactId>
    <version>${project.version}</version>
    <type>jar</type>
</dependency>  
  • Registrar el servicio en ApiRestService.java
    @Override
      public void run(RestConfiguration configuration,
                      Environment environment) {
          environment.jersey().register(new VersionResource());
      }
    

    Arriba

    Configuracion ejecucion en NetBeans

  • Adicionar Configutarion sobre modulo rest
    Alt Text

  • Registrar la configuración
    Alt Text

  • Seleccionar la opción Run y dentro seleccionar la configuración adicionada con los siguientes parametros:

    Main Class: com.isortegah.rest.ApiRestService
    Arguments: server config.yml
    Alt Text

Arriba

Proceso de dockerizacion

  1. Crear Dockerfile
FROM isortegah/java8:v1


EXPOSE 8080

RUN mkdir -p /app
WORKDIR /app

ADD bootstrap.sh bootstrap.sh
ADD rest/target/rest-0.1-SNAPSHOT.jar rest.jar
ADD config.yml config.yml

ENTRYPOINT ["/bin/bash", "./bootstrap.sh"]
  1. Crear archivo bootstrap.sh
#!/usr/bin/env bash
java -jar rest.jar server config.yml
  1. Construcción de imagen
docker build -t api-rest .
  1. Ejecución de imagen
docker run -it -p 8080:8080 < imagen id >
  1. Ejecutar bash
docker exec -it < id container > /bin/bash
  1. Borrar contenedores finalizados
docker ps -a | egrep Exited | cut -d ' ' -f 1|xargs docker rm
  1. Borrar imagenes < none >
docker images | egrep none | cut -c 41-53| xargs docker rmi

Adicionales

Log4j2

  • Agregar al POM del proyecto la siguiente dependencia:
<dependency> 
    <groupId>org.apache.logging.log4j</groupId> 
    <artifactId>log4j-core</artifactId>
    <version>2.8.2</version> 
</dependency>
  • Agregar el archivo de configuración en la carpeta resource del proyecto, con el nombre log4j.<properties|xml|yaml|json>.

Ejemplos

alt text

  • Código Java
import org.apache.logging.log4j.LogManager; 
import org.apache.logging.log4j.Logger; 

//Ejemplo de declaración de variable 
private static final Logger log = LogManager.getLogger("VersionResource");  

//Ejemplo de implementación
log.info("Se requiere servicio version"); 

Referencias

Log4j Users Guide
Referencia 1
Referencia 2
Referencia 3
Referencia 4
Referencia 5
Referencia 6

Heroku

Pre requisitos

heroku create < nombre app >
  • Establecer buildpack
    heroku buildpacks:set heroku/java
    
  • Establecer stack para despliegue con git
     heroku stack:set heroku-18
    
  • Establecer stack para despliegue como docker
     heroku stack:set container
    

Despliege en Heroku

  • Crear archivo Procfile`
    web: java -Ddw.server.applicationConnectors[0].port=$PORT -jar rest/target/rest-0.2.0-SNAPSHOT.jar server config.yml
    
  • Desplegar app
    git push heroku master
    

Esta aplicación la podemos ver funcionando en api.isortegah.me/swagger Nota: Se encuentra desplegada como contenedor Docker.

Despliegue en heroku como docker

  • Instalar plugin
    heroku plugins:install heroku-container-registry
    
  • Login en contenedor
    heroku container:login
    
  • Push codigo
    heroku container:push web
    
  • Desplegar como docker
    heroku container:release web
    
  • Correr bash en heroku
    heroku run bash
    

    Referencia:

Container Registry and Runtime

Push multiple Docker images to Heroku Container Registry

[Container Registry and Runtime Heroku Dev Center](https://devcenter.heroku.com/articles/container-registry-and-runtime)

Especificar versión de Java

  • Crear archivo system.properties
    "java.runtime.version=1.8" 
    
  • Verificar la versión de java en Heroku
    heroku run java -version
    

    Referencia 1

JWT

  • Crear modulo authentication

    alt text

alt text

  • Agregar dependencia al pom.xml del modulo authentication ```xml
com.auth0 java-jwt 3.2.0

* Para resolver el problema de ejecución del `jar` del proyecto se requiere agregar lo siguiente en el `pom.xml`del modulo `rest`.

```xml
<filters>
    <filter>
        <artifact>*:*</artifact>
        <excludes>
            <exclude>META-INF/*.SF</exclude>
            <exclude>META-INF/*.DSA</exclude>
            <exclude>META-INF/*.RSA</exclude>
        </excludes>
    </filter>
</filters>
  • Verificar los cambios implementados para la funcionalidad de generar un token simple en GitHub.

Referencia

java-jwt JSON Web Token (JWT)

Aws

  • Crear modulo aws

alt text

alt text

  • Adicionar dependencia a pom.xml ```xml
com.amazonaws aws-java-sdk-s3 1.11.671
* Adicionar al archivo `config.yml` la configuración para `aws`
```yaml
aws: 
  credentialProvider: < File|Environment > @Deprecated
  region: <Clave de region aws>

Se depreco el uso de la clase AmazonS3Client y se implemento AmazonS3Client, para revisar la antigua documentación dirijase a la doc aws

Con la implementación de la clase AmazonS3Client, las credenciales para la conexión a aws es man sencilla, ya que toma las credneicales del archivo ~/.aws/credentials si existe, y de lo contrario busca las variables de ambiente.

El archivo credentials debe estar ubicado en el HOME del usuario:

~/.aws/credentials

~/ cat .aws/credentials

[default]
aws_secret_access_key=aaaa
aws_access_key_id=zzzz

Para el caso de las credenciales vía variables de ambiente el proceso es el siguiente:

  • Exportar las variables:
    export AWS_ACCESS_KEY_ID="xyz"
    export AWS_SECRET_ACCESS_KEY="aaa"
    

    En MacOs y Linux agregarlas en el archivo .bashrc o .bash_profile y recargarlo.

    source .bash_profile
    

    Para Windows usar el comando:

    set AWS_ACCESS_KEY_ID="xyz"
    set AWS_SECRET_ACCESS_KEY="aaa"
    

    Lo anterior para poder ejecutar el comando:

    java -jar rest/target/rest-0.1-SNAPSHOT.jar server config.yml
    
  • En el archivo config.ymlcambiar el valor File por Environment.
    aws: 
    credentialProvider: Environment
    region: US_EAST_1
    

Ejecución

Se presentan las siguientes opciones de ejecución de la imagen docker.

  • De forma directa:
docker run -it -p 8080:8080 -e PORT=8080 -e AWS_ACCESS_KEY_ID=xyzqwd -e AWS_SECRET_ACCESS_KEY=aaa fba5ce1e06db
  • Vía docker-compose:
    • Crear archivo docker-compose.yml ```yml version: ‘3’ services: web: image: api-rest env_file:
      • ./.env environment:
      • AMBIENTE=”DEV” ports:
      • “8080:8080” ```
    • Crear archivo .env donde registraremos las variables de ambiente
AWS_ACCESS_KEY_ID=xyz
AWS_SECRET_ACCESS_KEY=aaa

Nota: Lo recomendable por practico y seguro, cuando ejecutemos en local, es usar el docker-compose, en el caso que estemos desarrollando podemos utilizar el archivo de credenciales.

  • Despliege a heroku:

Agregar las variables de ambiente en settings dentro de la app en heroku. alt text

Referencia

Instalacion

Instalación de la AWS CLI con el instalador agregado (Linux, macOS, or Unix)

Credenciales

set Environment Variables aws doc
Working with AWS Credentials Loading Credentials in Node.js from the Shared Credentials File

https://javatutorial.net/java-s3-example http://docs.aws.amazon.com/sdk-for-java/v1/developer-guide/setup-credentials.html

Docker

Environment variables in Compose

Temas a considerar

Picked up JAVA_TOOL_OPTIONS: -Xmx350m -Xss512k -Dfile.encoding=UTF-8