Commit bd81e140 authored by DANIEL DIAZ SANCHEZ's avatar DANIEL DIAZ SANCHEZ
Browse files

Update README_old.md, README.md files

parent 5bb99998
Este proyecto por su sencilles NO tiene código por lo que no se puede clonar.
# Acceso a API REST y decodificación de JSON
# Creando un interfaz REST
### Aplicaciones y librerías a utilizar
* Eclipse (**podéis usar el que descargásteis el primer día o el instalado en las máquinas de laboratorio**)
* [Unirest](http://unirest.io/java.html): librería de peticiones HTTP (más adelante veremos como descargarla)
* [Commons](https://commons.apache.org/): librerías de funciones auxiliares (más adelante veremos como descargarla)
* [Google-Gson](https://github.com/google/gson): librería de manipulación de JSON (más adelante veremos como descargarla)
## Prueba de Unirest
A continuación, crearemos un proyecto java nuevo (New > java project):
<img src="https://gitlab.pervasive.it.uc3m.es/distributed-computing-assignements/1-restAPIs-unirest-json/raw/master/img/image002.png" width="500px"/>
Dentro de ese proyecto creamos un paquete (package) con un nombre cualquiera (es mala práctica crear las clases directamente en la raíz, por eso es mejor usar un paquete) por ejemplo "cdistRest".
* SDK de Google Cloud que puedes descargar como hemos hecho anteriormente en la [Práctica 1](https://gitlab.gast.it.uc3m.es/distributed-computing-assignements/1-app-engine-servlet-jsp/-/blob/master/eclipse-google-installation.md). *Sigue los pasos unicamente de Google Cloud SDK* no es necesario que descargues Eclipse.
* Python 3 que debería estar instalado en las máquinas del laboratorio
* Por problemas de direccionamiento y presencia de un NAT en Eduroam *se recomienda usar las máquinas de laboratorio en lugar del portatil personal*
<img src="https://gitlab.pervasive.it.uc3m.es/distributed-computing-assignements/1-restAPIs-unirest-json/raw/master/img/image003.png" width="500px"/>
## Condigurar el entorno
Para realizar las peticiones vamos a usar una librería llamada UNIREST que es bastante clara y sencilla de usar.
En primer lugar, debes descargar el SDK en `/tmp` como se indica en los requisitos. Lo usaremos más adelante.
### Añadir dependencias a un proyecto
Al trabajar con Python, deberemos crear un *entorno virtual*, para ello:
Vamos a utilizar [Maven](https://maven.apache.org/) que ya viene integrado en eclipse para trabajar con las dependencias (librerías que usará nuestro programa). Si no usáramos maven tendríamos que añadir las librerías manualmente.
Por ejemeplo, para usar esta librería (Unirest) sería necesario bajarse un zip con la librería (ficheros jar) y las dependencias que dicha librería tenga. Más tarde habría que añadirlas manualmente añadiendo los jars (indicando la localización en el disco duro) en la pantalla de gestión de las dependencias ((Build Path> Configure Build Path pestaña Libraries) aunque lo vamos a hacer con maven que es más sencillo (la siguiente imagen es únicamente para tu información):
1. Crear la estructura de directorios desde tu cuenta. Abre un terminal y teclea (la máquina desde la que ha sido probada se llama vit131, en tu caso será otra máquina):
<img src="https://gitlab.pervasive.it.uc3m.es/distributed-computing-assignements/1-restAPIs-unirest-json/raw/master/img/image005.png" width="500px"/>
Con maven es más sencillo:
1. Lo primero es transformar el proyecto en un proyecto con gestión de dependencias Maven. Para ello hay que hacer click con el botón derecho sobre el proyecto, ir al menú Configure y hacer click en Convert to Maven Project.
2. Aceptar el diálogo que emerge tras convertirlo en Maven y dar una versión a nuestro programa (déjalo por defecto como propone eclipse)
3. Abrir el fichero pom.xml generado
4. Añadir la dependencia deseada como se indica a continuación
Para saber qué dependencia añadir lo más sencillo es buscar en la página de la librería que se desea utilizar. En este caso, visitando la página de [Unirest](http://unirest.io/java.html) veremos más abajo instrucciones de instalación, entre las que encontramos maven.
Editamos el fichero pom.xml del proyecto añadiendo el texto después de build:
```xml
</build>
<dependencies>
<dependency>
<groupId>com.konghq</groupId>
<artifactId>unirest-java</artifactId>
<version>3.11.02</version>
</dependency>
</dependencies>
</project>
```
quedando así (se muestra solo el final del fichero):
```xml
...
<build>
<sourceDirectory>src</sourceDirectory>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<release>11</release>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>com.konghq</groupId>
<artifactId>unirest-java</artifactId>
<version>3.11.02</version>
</dependency>
</dependencies>
</project>
vit131:~> mkdir -p cdist/rest
vit131:~> cd cdist
```
Guarda el fichero pom.xml y verás como Eclipse descarga los ficheros necesarios automáticamente. Podrás verlos en la carpeta Maven dependencies de tu proyecto.
Si alguna vez no encontramos alguna librería, se puede buscar en maven central (o google) y localizaremos la librería en esta [página](https://mvnrepository.com/artifact/com.mashape.unirest/unirest-java/1.4.9).
### Analizar las peticiones HTTP a una aplicación
Usaremos como ejemplo la aplicación de voto que hicimos el otro día o cualquier otra web.
En el caso de nuestra aplicación, podemos preguntar a las urls:
Vamos a analizar dicha aplicación desde el punto de vista de las peticiones que le hacemos. Sabemos que nuestra aplicación nos muestra un interfaz de usuario amigable en la página http://localhost:8888/vote.jsp.
Si analizamos las peticiones, encontramos lo siguiente.
* Para votar, recordamos que tenemos que hacer un POST a http://localhost:8080/vote, en el que mandamos los parámetros:
2. Crear un entorno virtual de python
```
POST /vote HTTP/1.1
host: localhost:8080
Content-Length: 34
vote=1&username=test%40example.com
vit131:~> python3 -m myenv $HOME/cdist/myenv
```
* Al enviar esta petición, obtendremos un código de redirección 302 que nos redirigirá de nuevo a la url http://localhost:8080/vote.jsp
Esto creará un entorno de python nuevo para nosotros. Uno de los problemas es que sólo es compatible con bash, así que hay que pasar a bash para activarlo (y habrá que hacerlo siempre que necesitemos python):
Y se contabilizará el voto. Podéis ver este funcionamiento con las herramientas de desarrollador de chrome o de firefox.
### Realizar peticiones HTTP con Unirest
Vamos a utilizar UniRest debido a que es sencilla de usar, fácil de entender, y además gestiona la concurrencia y los hilos por nosotros. Hay otras alternativas, pero esta es muy intuitiva.
En el proyecto que hemos creado para esta prácica, añadimos una clase llamada `MyRequest.java` dentro del paquete anteriormente creado (`CdistRest` o el que hayáis elegido).
Utiliza el siguiente código:
```java
package CdistRest;
import kong.unirest.HttpResponse;
import kong.unirest.Unirest;
public class MyRequest {
public static void main(String args[]) {
System.out.println("Test sending post to http://localhost:8080/vote");
HttpResponse<String> res = Unirest.post("http://localhost:8080/vote").field("vote", "1")
.field("username", "test@example").asString();
System.out.println(res.getBody());
}
}
```
En java 11 os pedirá que añadáis las dependencias al fichero `module-info.java` que quedará así:
vit131:~> bash
```
module CdistRest {
requires unirest.java;
}
```
Nota que el cuerpo del mensaje no se mostrará salvo error, es decir, la línea `System.out.println(res.getBody());` no tiene efecto dado que la página `/vote` no responde con nada, simplemente hace una redirección a `/vote.jsp`
Para probarlo, primerlo ejecuta la aplicación web, verifica que funciona con un navegador. Luego haz debug (ehecutar con debug en java) con el programa recién creado y observa como funciona.
**Verás que se ha contabilizado el voto**.
## Multiples peticiones
Podemos realizar múltiples peticiones con un bucle. En el caso que veremos ahora, cada petición se resolverá antes de que comience la siguiente, es decir, son secuenciales.
Para ello usaremos una clase nueva llamada `MyRequest_sequential.java` con el código:
```java
package CdistRest;
import kong.unirest.HttpResponse;
import kong.unirest.Unirest;
public class MyRequest_sequential {
public static void main(String args[]) {
System.out.println("Test sending post to http://localhost:8080/vote several times");
for (int i = 0; i < 5; i++) {
System.out.println();
HttpResponse<String> res = Unirest.post("http://localhost:8080/vote").field("vote", "1")
.field("username", "test@example").asString();
System.out.println("Request number " + i + " answered with status " + res.getStatus());
}
}
}
A partir de este momento, cambiará el prompt a:
```
Prueba con diferente número de peticiones y observa como los votos se contabilizan.
## Formato JSON
En la prueba anterior hemos realizado peticiones en un formato específico de la aplicación. En la vida real no se hace así, suele usarse JSON.
La información que obtenemos como respuesta a las peticiones que hacemos a nuestra aplicación es HTML, que es bastante complicado de interpretar de forma automática. De hecho, HTML está destinado a presentar información más que a comunicar información estructurada entre máquinas, por eso decimos que nuestra aplicación es rudimentaria (ya la evolucionaremos más adelante).
Uno de los formatos más comunes para intercambiar información es JSON. Aquí tenéis un ejemplo de una información codificada en JSON:
```json
[
{"firstName":"John", "lastName":"Doe"},
{"firstName":"Anna", "lastName":"Smith"},
{"firstName":"Peter", "lastName": "Jones"}
]
labgcd@vit131:~/cdist$
```
Para procesar JSON usaremos la librería [GSON de Google](https://github.com/google/gson).
Añadiremos esta dependencia usando maven a un nuevo proyecto, por ejemplo `JsonTest`. Lo convertimos en maven haciendo click derecho sobre el proyecto en `Configure > Convert to Maven Project`.
Donde `labgcd`es tu login (en vuestro caso 00XXXX), `vit131` la máquina y `~/cdist` el directorio en el que estáis
Añadimos la dependencia de Maven. La porción XML para añadir la puedes encontrar en la página del proyecto (https://github.com/google/gson), haciendo click en maven.
3. Activar el entorno. *Recuerda que es necesario usar bash para que funcione*
En la página puedes encontrar la porción de XML que sería, para la versión 2.8.6 (puede que haya otra versión, siempre usa la más moderna en tus aplicaciones aunque este código está probado para la versión 2.8.6):
```xml
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.6</version>
</dependency>
```
Quedando el final del fichero pom.xml así:
```xml
...
<build>
<sourceDirectory>src</sourceDirectory>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<release>11</release>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.6</version>
</dependency>
</dependencies>
</project>
labgcd@vit131:~/cdist$ source myenv/bin/activate
```
Guarda el fichero `pom` y continúa. Crea una clase llamada `TestJSON.java`.
Y usa el siguiente código:
```java
package cdistRest;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonParser;
import com.google.gson.reflect.TypeToken;
public class TestJSON {
public TestJSON() {
// Crear un JSON
Collection<Employee> colection = new ArrayList<Employee>();
Employee e1 = new Employee();
e1.firstName="John";
e1.lastName= "Doe";
Employee e2 = new Employee();
e1.firstName="Anna";
e1.lastName= "Smith";
Employee e3 = new Employee();
e1.firstName="Peter";
e1.lastName= "Jones";
colection.add(e1);
colection.add(e2);
colection.add(e3);
Gson gson = new Gson();
String json_represntation = gson.toJson(colection);
System.out.print("Representación : \n" + json_represntation);
System.out.print(json_represntation);
// al revés, pero más complicado
// procesar un mensaje recibido con JSON, en el que no solo hay tipos Empoyee
/*
{
"mensaje": "mi mensaje",
"id": "21"
}
[
{"firstName":"John", "lastName":"Doe"},
{"firstName":"Anna", "lastName":"Smith"},
{"firstName":"Peter", "lastName": "Jones"}
]
*/
/* los pares string : string son como Maps<String, String> */
/* los pares string : object son Maps<String, Object> */
Type jType = new TypeToken<HashMap<String,Object>>(){}.getType();
String json_recibido = "{\"mensaje\": \"mi mensaje\", \"id\": \"21\"}";
String json_recibido2 = "[{\"firstName\":\"John\", \"lastName\":\"Doe\"},{\"firstName\":\"Anna\", \"lastName\":\"Smith\"},{\"firstName\":\"Peter\", \"lastName\": \"Jones\"}]";
HashMap<String,Object> mensaje = gson.fromJson(json_recibido, jType);
System.out.println(" ----- ");
System.out.println(mensaje.get("mensaje"));
System.out.println(mensaje.get("id"));
//JsonParser parser = new JsonParser();
JsonArray employees = JsonParser.parseString(json_recibido2).getAsJsonArray();
for(JsonElement jemployee : employees)
{
Employee employee = gson.fromJson(jemployee, cdistRest.Employee.class);
System.out.println("Info empleado " + employee.toString());
}
}
public static void main(String args[]) {
new TestJSON();
}
}
```
Crea la clase Employee.java:
```java
package cdistRest;
public class Employee {
public String firstName;
public String lastName;
public Employee() {
// TODO Auto-generated constructor stub
}
public String toString() {
return "name : " + firstName + " surname : " + lastName;
}
}
```
Ahora el prompt cambiará a: `(myenv) labgcd@vit131:~/cdist$` dónde `(myenv)` indica el entorno virtual de python que estamos usando.
Si trabajas con Java 11, deberás cambiar el fichero `module-info.java` para que funcione:
4. Instalar las dependencias para que funcione nuestro servicio REST, que usará `Flask` para el servidor web, `Flask-Alchemy` para acceso a BBDD y `pymysql` para el driver de bases de datos. Se hace de la siguiente manera:
```java
module JsonTest {
requires com.google.gson;
exports cdistRest to com.google.gson;
}
```
(myenv) labgcd@vit131:~/cdist$ pip3 install flask
(myenv) labgcd@vit131:~/cdist$ pip3 install flask_sqlalchemy
(myenv) labgcd@vit131:~/cdist$ pip3 install pymysql
Este proyecto por su sencilles NO tiene código por lo que no se puede clonar.
# Acceso a API REST y decodificación de JSON
### Aplicaciones y librerías a utilizar
* Eclipse (**podéis usar el que descargásteis el primer día o el instalado en las máquinas de laboratorio**)
* [Unirest](http://unirest.io/java.html): librería de peticiones HTTP (más adelante veremos como descargarla)
* [Commons](https://commons.apache.org/): librerías de funciones auxiliares (más adelante veremos como descargarla)
* [Google-Gson](https://github.com/google/gson): librería de manipulación de JSON (más adelante veremos como descargarla)
## Prueba de Unirest
A continuación, crearemos un proyecto java nuevo (New > java project):
<img src="https://gitlab.pervasive.it.uc3m.es/distributed-computing-assignements/1-restAPIs-unirest-json/raw/master/img/image002.png" width="500px"/>
Dentro de ese proyecto creamos un paquete (package) con un nombre cualquiera (es mala práctica crear las clases directamente en la raíz, por eso es mejor usar un paquete) por ejemplo "cdistRest".
<img src="https://gitlab.pervasive.it.uc3m.es/distributed-computing-assignements/1-restAPIs-unirest-json/raw/master/img/image003.png" width="500px"/>
Para realizar las peticiones vamos a usar una librería llamada UNIREST que es bastante clara y sencilla de usar.
### Añadir dependencias a un proyecto
Vamos a utilizar [Maven](https://maven.apache.org/) que ya viene integrado en eclipse para trabajar con las dependencias (librerías que usará nuestro programa). Si no usáramos maven tendríamos que añadir las librerías manualmente.
Por ejemeplo, para usar esta librería (Unirest) sería necesario bajarse un zip con la librería (ficheros jar) y las dependencias que dicha librería tenga. Más tarde habría que añadirlas manualmente añadiendo los jars (indicando la localización en el disco duro) en la pantalla de gestión de las dependencias ((Build Path> Configure Build Path pestaña Libraries) aunque lo vamos a hacer con maven que es más sencillo (la siguiente imagen es únicamente para tu información):
<img src="https://gitlab.pervasive.it.uc3m.es/distributed-computing-assignements/1-restAPIs-unirest-json/raw/master/img/image005.png" width="500px"/>
Con maven es más sencillo:
1. Lo primero es transformar el proyecto en un proyecto con gestión de dependencias Maven. Para ello hay que hacer click con el botón derecho sobre el proyecto, ir al menú Configure y hacer click en Convert to Maven Project.
2. Aceptar el diálogo que emerge tras convertirlo en Maven y dar una versión a nuestro programa (déjalo por defecto como propone eclipse)
3. Abrir el fichero pom.xml generado
4. Añadir la dependencia deseada como se indica a continuación
Para saber qué dependencia añadir lo más sencillo es buscar en la página de la librería que se desea utilizar. En este caso, visitando la página de [Unirest](http://unirest.io/java.html) veremos más abajo instrucciones de instalación, entre las que encontramos maven.
Editamos el fichero pom.xml del proyecto añadiendo el texto después de build:
```xml
</build>
<dependencies>
<dependency>
<groupId>com.konghq</groupId>
<artifactId>unirest-java</artifactId>
<version>3.11.02</version>
</dependency>
</dependencies>
</project>
```
quedando así (se muestra solo el final del fichero):
```xml
...
<build>
<sourceDirectory>src</sourceDirectory>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<release>11</release>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>com.konghq</groupId>
<artifactId>unirest-java</artifactId>
<version>3.11.02</version>
</dependency>
</dependencies>
</project>
```
Guarda el fichero pom.xml y verás como Eclipse descarga los ficheros necesarios automáticamente. Podrás verlos en la carpeta Maven dependencies de tu proyecto.
Si alguna vez no encontramos alguna librería, se puede buscar en maven central (o google) y localizaremos la librería en esta [página](https://mvnrepository.com/artifact/com.mashape.unirest/unirest-java/1.4.9).
### Analizar las peticiones HTTP a una aplicación
Usaremos como ejemplo la aplicación de voto que hicimos el otro día o cualquier otra web.
En el caso de nuestra aplicación, podemos preguntar a las urls:
Vamos a analizar dicha aplicación desde el punto de vista de las peticiones que le hacemos. Sabemos que nuestra aplicación nos muestra un interfaz de usuario amigable en la página http://localhost:8888/vote.jsp.
Si analizamos las peticiones, encontramos lo siguiente.
* Para votar, recordamos que tenemos que hacer un POST a http://localhost:8080/vote, en el que mandamos los parámetros:
```
POST /vote HTTP/1.1
host: localhost:8080
Content-Length: 34
vote=1&username=test%40example.com
```
* Al enviar esta petición, obtendremos un código de redirección 302 que nos redirigirá de nuevo a la url http://localhost:8080/vote.jsp
Y se contabilizará el voto. Podéis ver este funcionamiento con las herramientas de desarrollador de chrome o de firefox.
### Realizar peticiones HTTP con Unirest
Vamos a utilizar UniRest debido a que es sencilla de usar, fácil de entender, y además gestiona la concurrencia y los hilos por nosotros. Hay otras alternativas, pero esta es muy intuitiva.
En el proyecto que hemos creado para esta prácica, añadimos una clase llamada `MyRequest.java` dentro del paquete anteriormente creado (`CdistRest` o el que hayáis elegido).
Utiliza el siguiente código:
```java
package CdistRest;
import kong.unirest.HttpResponse;
import kong.unirest.Unirest;
public class MyRequest {
public static void main(String args[]) {
System.out.println("Test sending post to http://localhost:8080/vote");
HttpResponse<String> res = Unirest.post("http://localhost:8080/vote").field("vote", "1")
.field("username", "test@example").asString();
System.out.println(res.getBody());
}
}
```
En java 11 os pedirá que añadáis las dependencias al fichero `module-info.java` que quedará así:
```
module CdistRest {
requires unirest.java;
}
```
Nota que el cuerpo del mensaje no se mostrará salvo error, es decir, la línea `System.out.println(res.getBody());` no tiene efecto dado que la página `/vote` no responde con nada, simplemente hace una redirección a `/vote.jsp`
Para probarlo, primerlo ejecuta la aplicación web, verifica que funciona con un navegador. Luego haz debug (ehecutar con debug en java) con el programa recién creado y observa como funciona.
**Verás que se ha contabilizado el voto**.
## Multiples peticiones
Podemos realizar múltiples peticiones con un bucle. En el caso que veremos ahora, cada petición se resolverá antes de que comience la siguiente, es decir, son secuenciales.
Para ello usaremos una clase nueva llamada `MyRequest_sequential.java` con el código:
```java
package CdistRest;
import kong.unirest.HttpResponse;
import kong.unirest.Unirest;
public class MyRequest_sequential {
public static void main(String args[]) {
System.out.println("Test sending post to http://localhost:8080/vote several times");
for (int i = 0; i < 5; i++) {
System.out.println();
HttpResponse<String> res = Unirest.post("http://localhost:8080/vote").field("vote", "1")
.field("username", "test@example").asString();
System.out.println("Request number " + i + " answered with status " + res.getStatus());
}
}
}
```
Prueba con diferente número de peticiones y observa como los votos se contabilizan.
## Formato JSON
En la prueba anterior hemos realizado peticiones en un formato específico de la aplicación. En la vida real no se hace así, suele usarse JSON.
La información que obtenemos como respuesta a las peticiones que hacemos a nuestra aplicación es HTML, que es bastante complicado de interpretar de forma automática. De hecho, HTML está destinado a presentar información más que a comunicar información estructurada entre máquinas, por eso decimos que nuestra aplicación es rudimentaria (ya la evolucionaremos más adelante).
Uno de los formatos más comunes para intercambiar información es JSON. Aquí tenéis un ejemplo de una información codificada en JSON:
```json
[
{"firstName":"John", "lastName":"Doe"},
{"firstName":"Anna", "lastName":"Smith"},
{"firstName":"Peter", "lastName": "Jones"}
]
```
Para procesar JSON usaremos la librería [GSON de Google](https://github.com/google/gson).
Añadiremos esta dependencia usando maven a un nuevo proyecto, por ejemplo `JsonTest`. Lo convertimos en maven haciendo click derecho sobre el proyecto en `Configure > Convert to Maven Project`.
Añadimos la dependencia de Maven. La porción XML para añadir la puedes encontrar en la página del proyecto (https://github.com/google/gson), haciendo click en maven.
En la página puedes encontrar la porción de XML que sería, para la versión 2.8.6 (puede que haya otra versión, siempre usa la más moderna en tus aplicaciones aunque este código está probado para la versión 2.8.6):
```xml
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.6</version>
</dependency>
```
Quedando el final del fichero pom.xml así:
```xml
...
<build>
<sourceDirectory>src</sourceDirectory>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<release>11</release>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.6</version>
</dependency>
</dependencies>
</project>
```
Guarda el fichero `pom` y continúa. Crea una clase llamada `TestJSON.java`.
Y usa el siguiente código:
```java
package cdistRest;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonParser;
import com.google.gson.reflect.TypeToken;
public class TestJSON {