deSymfony 2013 Consumiendo APIs REST con Guzzle y Symfony2

Post on 25-May-2015

4.157 views 4 download

Tags:

description

Guzzle es un cliente HTTP que facilita de forma increíble el crear, consumir e interactuar con servicios web, como por ejemplo, la api REST de un servicio web como Twitter, Amazon AWS, Github, entre otros. Nos ofrece completo control del estándar HTTP para la generación de un Request y nos permite de forma organizada manejar el Response y definir modelos sobre las respuestas para actuar mas facilmente sobre ellas. En esta charla se introducirá como configurar la libreria de forma independiente en menos de 10 minutos, y como integrarlo en un proyecto de Symfony2 y Silex, para empezar a atacar APIs, se explicaran sus usos mas comunes, se hablara de proyectos que ya lo tienen incorporado (como Drupal, el Amazon AWS SDK para PHP, y la libreria Goutte, para hacer Webscraping, de Fabien Potencier, entre otras). Se terminara con un ejemplo practico en dos proyectos de Acilia, para atacar a un servicio web (emailvision), para envíos de emails transaccionales y masivos de dos aplicaciones y posterior recopilación de reportes de dichos envíos, todo mediante llamadas y respuestas HTTP a una API REST.

Transcript of deSymfony 2013 Consumiendo APIs REST con Guzzle y Symfony2

Albert Jessurum

Albert Jessurum

acilia.es

Albert Jessurum

acilia.es

chess.com

Albert Jessurum

acilia.es

chess.com

Maracaibo, Venezuela

Albert Jessurum

acilia.es

chess.com

Maracaibo, Venezuela

@ajessu

Albert Jessurum

acilia.es

chess.com

Maracaibo, Venezuela

@ajessu

github.com/ajessu

Albert Jessurum

acilia.es

chess.com

Maracaibo, Venezuela

@ajessu

github.com/ajessu

Fan de Symfony

Albert Jessurum

acilia.es

chess.com

Maracaibo, Venezuela

@ajessu

github.com/ajessu

Fan de Symfony

Albert Jessurum

acilia.es

chess.com

Maracaibo, Venezuela

@ajessu

github.com/ajessu

Fan de Symfony

Guzzle

¿Que es Guzzle?

¿Que es Guzzle?

¿Que es Guzzle?

• Cliente para realizar peticiones http

¿Que es Guzzle?

• Cliente para realizar peticiones http

• cURL

¿Que es Guzzle?

• Cliente para realizar peticiones http

• cURL

• Conexiones persistentes

¿Que es Guzzle?

• Cliente para realizar peticiones http

• cURL

• Conexiones persistentes

• Peticiones paralelas

¿Que es Guzzle?

• Cliente para realizar peticiones http

• cURL

• Conexiones persistentes

• Peticiones paralelas

• Plugins

¿Por que Guzzle?

¿Por que Guzzle?

¿Por que Guzzle?

• Peticiones http en general

¿Por que Guzzle?

• Peticiones http en general

• API

¿Por que Guzzle?

• Peticiones http en general

• API

• Scrapping

¿Por que Guzzle?

• Peticiones http en general

• API

• Scrapping

• Envio de datos/reportes (POST)

Alternativas

Alternativas

Alternativas

• file_get_contents/fopen

Alternativas

• file_get_contents/fopen

• cURL

Alternativas

• file_get_contents/fopen

• cURL

• pecl_http

Alternativas

• file_get_contents/fopen

• cURL

• pecl_http

• Zend_Http

Alternativas

• file_get_contents/fopen

• cURL

• pecl_http

• Zend_Http

• Buzz

Proyectos que usan Guzzle

Proyectos que usan Guzzle

Proyectos que usan Guzzle

• Drupal 8

Proyectos que usan Guzzle

• Drupal 8

• Goutte

Proyectos que usan Guzzle

• Drupal 8

• Goutte

• Amazon AWS

Guzzle en menos de 1 minuto

Guzzle en menos de 1 minuto

Guzzle en menos de 1 minuto

// Version >= 3.7

Guzzle en menos de 1 minuto

// Version >= 3.7Guzzle\Http\StaticClient::mount();

Guzzle en menos de 1 minuto

// Version >= 3.7Guzzle\Http\StaticClient::mount();$response = Guzzle::get('http://desymfony.com');

Guzzle en menos de 1 minuto

// Version >= 3.7Guzzle\Http\StaticClient::mount();$response = Guzzle::get('http://desymfony.com');

Guzzle en menos de 1 minuto

// Version >= 3.7Guzzle\Http\StaticClient::mount();$response = Guzzle::get('http://desymfony.com');

// Para un poco mas de control

Guzzle en menos de 1 minuto

// Version >= 3.7Guzzle\Http\StaticClient::mount();$response = Guzzle::get('http://desymfony.com');

// Para un poco mas de controluse Guzzle\Http\Client;

Guzzle en menos de 1 minuto

// Version >= 3.7Guzzle\Http\StaticClient::mount();$response = Guzzle::get('http://desymfony.com');

// Para un poco mas de controluse Guzzle\Http\Client;

Guzzle en menos de 1 minuto

// Version >= 3.7Guzzle\Http\StaticClient::mount();$response = Guzzle::get('http://desymfony.com');

// Para un poco mas de controluse Guzzle\Http\Client;

$client = new Client('http://desymfony.com');

Guzzle en menos de 1 minuto

// Version >= 3.7Guzzle\Http\StaticClient::mount();$response = Guzzle::get('http://desymfony.com');

// Para un poco mas de controluse Guzzle\Http\Client;

$client = new Client('http://desymfony.com');$request = $client->get('/');

Guzzle en menos de 1 minuto

// Version >= 3.7Guzzle\Http\StaticClient::mount();$response = Guzzle::get('http://desymfony.com');

// Para un poco mas de controluse Guzzle\Http\Client;

$client = new Client('http://desymfony.com');$request = $client->get('/');$response = $request->send();

Guzzle HTTP Client

Guzzle HTTP Client

Guzzle HTTP Client

• Clientes

Guzzle HTTP Client

• Clientes

• Requests

• Sin body

• Con body

Guzzle HTTP Client

• Clientes

• Requests

• Sin body

• Con body

• Responses

Guzzle HTTP Client

Client Object

Client Object

$client = new Client('https://api.github.com/test');

// Absoluta$request = $client->get('https://api.github.com/test');// https://api.github.com/test

// relativa (con slash)$request = $client->get('/users');// https://api.github.com/users

// relativa (sin slash)$request = $client->get('users');// https://api.github.com/test/users

// Configuración de la petición$client->setUserAgent('Test/123');

Guzzle HTTP Client

Request Object

Request Object

// Crear un método en especifico$client->createRequest('METODO', $uri, array $headers, $body, $options);

// GET$client->get($uri, array $headers, $options);

//HEAD$client->head($uri, array $headers, $options);

//DELETE$client->delete($uri, array $headers, $body, $options);

//POST$client->post($uri, array $headers, $postBody, $options);

//PUT$client->put($uri, array $headers, $body, $options);

//PATCH$client->patch($uri, array $headers, $body, $options);

Request Object

// Una petición simple:

$request = $client->head('/path?id=123&nombre=abc');$response = $request->send();

// Una petición con cuerpo adjunto$request = $client->post('http://test.com/upload') ->addPostFiles(array('file' => '/ruta/a/documento.json'));$response = $request->send();

// Content-Type: application/json

Request Object

$request = $client->createRequest('COPY', 'http://example.com/foo', array( 'Destination' => 'http://test.com/bar', 'Overwrite' => 'T'));$response = $request->send();

Guzzle HTTP Client

Response Object

Response Object

$response = $client->get('http://www.amazon.com')->send();

echo $response->getStatusCode();// 200

echo $response->isSuccessful();// true

$response->isRedirect();// false

Response Object

// Respuesta de la peticiónecho $response->getBody();

// Si el formato es correcto:

// Devuelve un array de la respuesta json de la peticiónecho $response->json();

// Devuelve un objeto SimpleXMLElement de la peticiónecho $response->xml();

Plugins

Response Object

// Envía una petición si, y otra no con el plugin:// UnaSiOtraNoPlugin

$unaSiOtraNo = new UnaSiOtraNoPlugin();$client->addSubscriber($unaSiOtraNo);

Plugins

• Async plugin

• Backoff retry plugin

• HTTP Cache plugin

• OAuth plugin

• Cookie plugin

• History plugin

• Log plugin

• MD5 validator plugin

• Mock plugin

Plugins

Async plugin

Plugins

Backoff retry plugin

Plugins

HTTP Cache Plugin

HTTP Cache Plugin

HTTP Cache Plugin

HTTP Cache Plugin

• Chequea el HEAD del Request, para verificar el status.

HTTP Cache Plugin

• Chequea el HEAD del Request, para verificar el status.

HTTP Cache Plugin

• Chequea el HEAD del Request, para verificar el status.

• Se puede crear una cache falsa

Plugins

OAuth Plugin

OAuth Plugin

OAuth Plugin

OAuth Plugin

• OAuth 1.0 (Twiiter)

OAuth Plugin

• OAuth 1.0 (Twiiter)

• OAuth 2.0 (Facebook)

OAuth Plugin

• OAuth 1.0 (Twiiter)

• OAuth 2.0 (Facebook)

• OAuth2 en los planes pero sin fecha: ( https://github.com/guzzle/guzzle/issues/319 )

OAuth Plugin

• OAuth 1.0 (Twiiter)

• OAuth 2.0 (Facebook)

• OAuth2 en los planes pero sin fecha: ( https://github.com/guzzle/guzzle/issues/319 )

OAuth Plugin

• OAuth 1.0 (Twiiter)

• OAuth 2.0 (Facebook)

• OAuth2 en los planes pero sin fecha: ( https://github.com/guzzle/guzzle/issues/319 )

// Cargando el plugin OAuth

$client = new Client('http://api.twitter.com/1.1');$oauth = new OauthPlugin(array( 'consumer_key' => 'mi_key', 'consumer_secret' => 'mi_string_secreto', 'token' => 'mi_token', 'token_secret' => 'mi_token_secreto'));$client->addSubscriber($oauth);

$request = $client->get('statuses/public_timeline.json');

$response = $request->send();

Service Builder

Service Builder

// Create cliente de twitter$client = TwitterClient::factory(array( 'consumer_key' => '****', 'consumer_secret' => '****', 'token' => '****', 'token_secret' => '****'));

Service Builder

// Crear un cliente desde un factory

$builder = ServiceBuilder::factory('/ruta/a/config.json');$twitter = $builder->get('twitter');

Service Builder

{ "services": { "twitter_ajessu": { "class": "ajessu\TwitterClient", "params": { "consumer_key": "****", "consumer_secret": "****", "token": "****", "token_secret": "****" } }, "twitter_desymfony": { "class": "ajessu\TwitterClient", "params": { "consumer_key": "****", "consumer_secret": "****", "token": "****", "token_secret": "****" } } }}

$twitter_ajessu = $builder->get('twitter_ajessu');$twitter_desymfony = $builder->get('twitter_desymfony');

Service Definition

Service Builder

{ "name": "string", "apiVersion": "string|number", "baseUrl": "string", "description": "string", "operations": {}, "models": {}, "includes": ["string.php", "string.json"]}

Service Builder

{ "includes":[ "connection.json" ], "name": "IndividualMember", "apiVersion": "0.1", "description": "Individual Member Api for Emailvision", "baseUrl": "{schema}://{server}/apimember/services/rest", "operations": { "InsertOrUpdateMember": { "httpMethod": "POST", "uri": "member/insertOrUpdateMember/{token}", "summary": "Updates a user if it exists, otherwise it updates it", "responseClass": "InsertOrUpdateMember", "parameters": { "token": { "location": "uri", "description": "Connection token", "required": true }, "user": { "location": "body", "description": "User values in xml", "required": true }, "Content-Type": { "location": "header", "default": "application/xml" } } } }}

Service Builder

{ "name": "Connection", "apiVersion": "0.1", "description": "Connection Api for Emailvision", "operations": { "OpenConnection": { "httpMethod": "GET", "uri": "connect/open/{apiLogin}/{apiPassword}/{apiKey}", "summary": "Opens the connection", "responseClass": "OpenConnection", "parameters": { "apiLogin": { "location": "uri", "description": "API username", "required": true }, "apiPassword": { "location": "uri", "description": "API password", "required": true }, "apiKey": { "location": "uri", "description": "API secret key", "required": true } } }, ... }, "models": { "OpenConnection": { "type": "object", "properties": { "token": { "location": "xml", "type": "string", "sentAs": "result" }, "status": { "type": "int", "location": "statusCode" } } }, ... }}

Service Builder

$memberClient = DataIndividualClient::factory();

// Get the token $openConnectionCommand = $memberClient->getCommand( 'OpenConnection', array( 'apiLogin' => '*****', 'apiPassword' => '****', 'apiKey' => ‘*********’ ) );

$openConnectionResponse = $memberClient->execute($openConnectionCommand);

$token = $openConnectionResponse['token']; $body = EntityBody::factory(‘/foo/user.xml’);

$updateUserCommand = $memberClient->getCommand( 'InsertOrUpdateMember', array( 'token' => $token, 'user' => $body ) );

$memberClient->execute($updateUserCommand);

// Close connection $closeConnectionCommand = $memberClient->getCommand( 'CloseConnection', array('token' => $token) ); $memberClient->execute($closeConnectionCommand);

Guzzle en silex

Guzzle en silex

$app = new Application();

$app->register(new GuzzleServiceProvider(), array( 'guzzle.services' => '/ruta/a/servicios.json',));

Guzzle en Symfony2

Guzzle en Symfony2

Guzzle en Symfony2

• Varios bundles

Guzzle en Symfony2

• Varios bundles

• Mejor opción hoy: MisdGuzzleBundle( https://github.com/misd-service-development/guzzle-bundle )

Guzzle en Symfony2

• Varios bundles

• Mejor opción hoy: MisdGuzzleBundle( https://github.com/misd-service-development/guzzle-bundle )

• Discusion (hace tres dias) = Vamos a unirlos!( https://github.com/misd-service-development/guzzle-bundle/issues/28 )k

Guzzle en Symfony2

// app/AppKernel.php

class AppKernel extends Kernel{ // ... public function registerBundles() { $bundles = array( // ... new Misd\GuzzleBundle\MisdGuzzleBundle() ); }}

Guzzle en Symfony2

// MyBundle/Resources/config/services.xml

<service id="example.client" class="%guzzle.client.class%"> <tag name="guzzle.client"/> <argument>http://api.example.com/</argument> <argument type="collection"> <argument key="setting1">true</argument> <argument key="setting2">false</argument> </argument> <call method="addSubscriber"> <argument type="service" id="some_guzzle_plugin"/> </call> <call method="setUserAgent"> <argument>My Guzzle client</argument> <argument>true</argument> </call> <call method="setDescription"> <argument type="service" id="example.client.service_description"/> </call></service>

Guzzle en Symfony2

$client = $this->get('example.client');

// Service description:<service id="example.client.service_description" class="%guzzle.service_description.class%" factory-class="%guzzle.service_description.class%" factory-method="factory"> <argument>%path.to.my.service_description.file%</argument></service>

Gracias!

Feedback: https://joind.in/8840

Albert Jessurum@ajessugithub.com/ajessu