Upgrade to Pro — share decks privately, control downloads, hide ads and more …

deSymfony 2013 Consumiendo APIs REST con Guzzle...

deSymfony 2013 Consumiendo APIs REST con Guzzle y Symfony2

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.

Avatar for Albert Jessurum

Albert Jessurum

June 24, 2013

More Decks by Albert Jessurum

Other Decks in Programming

Transcript

  1. ¿Que es Guzzle? • Cliente para realizar peticiones http •

    cURL • Conexiones persistentes • Peticiones paralelas
  2. ¿Que es Guzzle? • Cliente para realizar peticiones http •

    cURL • Conexiones persistentes • Peticiones paralelas • Plugins
  3. ¿Por que Guzzle? • Peticiones http en general • API

    • Scrapping • Envio de datos/reportes (POST)
  4. Guzzle en menos de 1 minuto // Version >= 3.7

    Guzzle\Http\StaticClient::mount();
  5. Guzzle en menos de 1 minuto // Version >= 3.7

    Guzzle\Http\StaticClient::mount(); $response = Guzzle::get('http://desymfony.com');
  6. Guzzle en menos de 1 minuto // Version >= 3.7

    Guzzle\Http\StaticClient::mount(); $response = Guzzle::get('http://desymfony.com');
  7. Guzzle en menos de 1 minuto // Version >= 3.7

    Guzzle\Http\StaticClient::mount(); $response = Guzzle::get('http://desymfony.com'); // Para un poco mas de control
  8. Guzzle en menos de 1 minuto // Version >= 3.7

    Guzzle\Http\StaticClient::mount(); $response = Guzzle::get('http://desymfony.com'); // Para un poco mas de control use Guzzle\Http\Client;
  9. Guzzle en menos de 1 minuto // Version >= 3.7

    Guzzle\Http\StaticClient::mount(); $response = Guzzle::get('http://desymfony.com'); // Para un poco mas de control use Guzzle\Http\Client;
  10. Guzzle en menos de 1 minuto // Version >= 3.7

    Guzzle\Http\StaticClient::mount(); $response = Guzzle::get('http://desymfony.com'); // Para un poco mas de control use Guzzle\Http\Client; $client = new Client('http://desymfony.com');
  11. Guzzle en menos de 1 minuto // Version >= 3.7

    Guzzle\Http\StaticClient::mount(); $response = Guzzle::get('http://desymfony.com'); // Para un poco mas de control use Guzzle\Http\Client; $client = new Client('http://desymfony.com'); $request = $client->get('/');
  12. Guzzle en menos de 1 minuto // Version >= 3.7

    Guzzle\Http\StaticClient::mount(); $response = Guzzle::get('http://desymfony.com'); // Para un poco mas de control use Guzzle\Http\Client; $client = new Client('http://desymfony.com'); $request = $client->get('/'); $response = $request->send();
  13. 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');
  14. 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);
  15. 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
  16. Request Object $request = $client->createRequest('COPY', 'http:// example.com/foo', array( 'Destination' =>

    'http://test.com/bar', 'Overwrite' => 'T' )); $response = $request->send();
  17. Response Object // Respuesta de la petición echo $response->getBody(); //

    Si el formato es correcto: // Devuelve un array de la respuesta json de la petición echo $response->json(); // Devuelve un objeto SimpleXMLElement de la petición echo $response->xml();
  18. Response Object // Envía una petición si, y otra no

    con el plugin: // UnaSiOtraNoPlugin $unaSiOtraNo = new UnaSiOtraNoPlugin(); $client->addSubscriber($unaSiOtraNo);
  19. Plugins • Async plugin • Backoff retry plugin • HTTP

    Cache plugin • OAuth plugin • Cookie plugin • History plugin • Log plugin • MD5 validator plugin • Mock plugin
  20. HTTP Cache Plugin • Chequea el HEAD del Request, para

    verificar el status. • Se puede crear una cache falsa
  21. OAuth Plugin • OAuth 1.0 (Twiiter) • OAuth 2.0 (Facebook)

    • OAuth2 en los planes pero sin fecha: ( https://github.com/guzzle/guzzle/issues/319 )
  22. OAuth Plugin • OAuth 1.0 (Twiiter) • OAuth 2.0 (Facebook)

    • OAuth2 en los planes pero sin fecha: ( https://github.com/guzzle/guzzle/issues/319 )
  23. OAuth Plugin • OAuth 1.0 (Twiiter) • OAuth 2.0 (Facebook)

    • OAuth2 en los planes pero sin fecha: ( https://github.com/guzzle/guzzle/issues/319 )
  24. // 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();
  25. Service Builder // Create cliente de twitter $client = TwitterClient::factory(array(

    'consumer_key' => '****', 'consumer_secret' => '****', 'token' => '****', 'token_secret' => '****' ));
  26. Service Builder // Crear un cliente desde un factory $builder

    = ServiceBuilder::factory('/ruta/a/config.json'); $twitter = $builder->get('twitter');
  27. 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');
  28. Service Builder { "name": "string", "apiVersion": "string|number", "baseUrl": "string", "description":

    "string", "operations": {}, "models": {}, "includes": ["string.php", "string.json"] }
  29. 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" } } } } }
  30. 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" } } }, ... } }
  31. 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);
  32. Guzzle en Symfony2 • Varios bundles • Mejor opción hoy:

    MisdGuzzleBundle ( https://github.com/misd-service-development/guzzle-bundle )
  33. 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
  34. Guzzle en Symfony2 // app/AppKernel.php class AppKernel extends Kernel {

    // ... public function registerBundles() { $bundles = array( // ... new Misd\GuzzleBundle\MisdGuzzleBundle() ); } }
  35. 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>
  36. 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>