Por qué Python mola. Capítulo XXIV
REQUESTS

Pycon, 7-9 de septiembre de 2016

APIs para PERSONAS

«We are constantly reading old code. Making it easy to read makes it easier to write.»
Uncle Bob Martin. Clean Code.

APIs para PERSONAS

HTTP

Sabes cómo funciona.

Haces una petición, recibes una respuesta.

No es tan complicado.

 

¿VERDAD?

APIs para PERSONAS



JAVA

            
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;

public class HttpBasicAuth {
    public static void main(String[] args) {
        try {
            URL url = new URL ("http://2016.es.pycon.org/");
            String encoding = Base64Encoder.encode ("user:password");

            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.setRequestMethod("GET");
            connection.setDoOutput(true);
            connection.setRequestProperty  ("Authorization", "Basic " + encoding);
            InputStream content = (InputStream)connection.getInputStream();
            BufferedReader in = new BufferedReader (new InputStreamReader (content));
            String line;
            while ((line = in.readLine()) != null) {
                System.out.println(line);
            }
        } catch(Exception e) {
            e.printStackTrace();
        }
    }
}
            
          

APIs para PERSONAS



C#

            
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net.Http;
using System.Net;


namespace HTTP_Test
{
    class program
    {
        static void Main()
        {
            HttpClientHandler handler = new HttpClientHandler();
            HttpClient client = new HttpClient(handler);

            var byteArray = Encoding.ASCII.GetBytes("user:password");
            client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Basic", Convert.ToBase64String(byteArray));

            HttpResponseMessage response = await client.GetAsync("http://2016.es.pycon.org/");
            HttpContent content = response.Content;

            string result = await content.ReadAsStringAsync();

            if (result != null)
            {
                Console.WriteLine(result);
            }
        }
    }
}
            
          

APIs para PERSONAS



Python con urllib2

            
import urllib2

url = 'http://2016.es.pycon.org/'

req = urllib2.Request(url)

password_manager = urllib2.HTTPPasswordMgrWithDefaultRealm()
password_manager.add_password(None, url, 'user', 'password')

auth_manager = urllib2.HTTPBasicAuthHandler(password_manager)
opener = urllib2.build_opener(auth_manager)
urllib2.install_opener(opener)

handler = urllib2.urlopen(req)

print handler.read()
            
          

APIs para PERSONAS



Python con Requests

            
import requests

response = requests.get('http://2016.es.pycon.org/', auth=('user', 'password'))

print(response.text)
            
          

APIs para PERSONAS



Toda la información en un único sitio

            
>>> response.status_code
200

>>> response.text
'{"saludo": "hola", "despedida": "adios"}'

>>> response.json()['saludo']
"hola"

>>> r.headers
{
    'content-encoding': 'gzip',
    'transfer-encoding': 'chunked',
    'connection': 'close',
    'server': 'nginx/1.0.4',
    'x-runtime': '148ms',
    'etag': '"e1ca502697e5c9317743dc078f67693f"',
    'content-type': 'application/json'
}
            
          

APIs para PERSONAS



GET

            
r = requests.get('http://www.google.com')
            
          

POST

            
r = requests.post('http://www.google.com/search', data={'campo1': 'valor1', 'campo2': 'valor2'})
            
          

DELETE

            
 r = requests.delete('http://www.mi-api-rest.com/items/45/')
            
          
Etcétera.

APIs para PERSONAS



Parámetros en la URL

            
r = requests.get('http://www.google.com?param1=valor1¶m2=valor2')
            
          

Mejor así:

            
params = {
    'param1': 'valor1'
    'param2': 'valor2'
}
r = requests.get('http://www.google.com', params=params)
            
          

APIs para PERSONAS



Parámetros POST

            
r = requests.post('http://www.google.com/search', data={'campo1': 'valor1', 'campo2': 'valor2'})
            
          

¿Queremos enviar JSON?

            
params = {
    'param1': 'valor1'
    'param2': 'valor2'
}
json_str = json.dumps(params)
r = requests.post('http://www.google.com/api/metodo', data=json_str)
            
          

Mejor así:

            
params = {
    'param1': 'valor1'
    'param2': 'valor2'
}
r = requests.post('http://www.google.com/api/metodo', json=params)
            
          

APIs para PERSONAS



Redirecciones

            
>>> r = requests.get('http://www.google.com')

>>> r.url
'http://www.google.com/'

>>> r.status_code
200

>>> r.history
[<Response [301]>]
            

            
>>> r = requests.get('http://www.google.com', allow_redirects=False)

>>> r.url
'http://www.google.com'

>>> r.status_code
301

>>> r.history
[]
            
          

APIs para PERSONAS



Subir un fichero
            
files = {'file': open('mi_fichero.pdf', 'rb')}
r = requests.post('http://www.google.com/search', files=files)
            
          
Subir una cadena (o cualquier otra cosa) como si fuera un fichero
            
files = {'file': ('mi_fichero.xml', 'helloworld')}
r = requests.post('http://www.google.com/search', files=files)
            
          
Subir muchos ficheros
            
files = [
    ('imagenes', ('foto1.png', open('foto1.png', 'rb'), 'image/png')),
    ('imagenes', ('foto2.png', open('foto2.png', 'rb'), 'image/png')),
]
r = requests.post('http://www.google.com/upload', files=files)
            
          

APIs para PERSONAS



Cookies
(Sí, las aceptamos TODAS)
            
>>> r = requests.get('http://www.google.com/')
>>> r.cookies['foo']
'bar'
            
          
Enviarlas
            
r = requests.get('http://www.google.com', cookies={'foo': 'bar'})
            
          

APIs para PERSONAS



Sesiones
            
>>> s = requests.Session()
>>> s.post('http://www.google.com/login', auth=('user', 'password'))
>>> r = s.get('http://www.google.com/url-privada')
            
          
Dar valores por defecto a todas las peticiones
            
>>> s = requests.Session()
>>> s.auth = ('user', 'password')
>>> s.headers.update({'cabecera1': 'valor'})

>>> s.get('http://www.google.com/url-privada')
>>> s.get('http://www.google.com/otra-url-privada')
            
          
Mejor aún:
            
with requests.Session() as s:
    s.auth = ('user', 'password')
    s.headers.update({'cabecera1': 'valor'})
    s.get('http://www.google.com/url-privada')
    s.get('http://www.google.com/otra-url-privada')
            
          

APIs para PERSONAS



Streaming (para ficheros grandes)

De bajada

            
r = requests.get('http://www.google.com/fichero-grande.tgz')
for chunk in r.iter_content(1024):
    print(chunk)
            

            
for line in r.iter_lines():
    print(line)
            
          

APIs para PERSONAS



Streaming (para ficheros grandes)

De subida

            
with open('fichero-inmenso.iso', 'rb') as f:
    requests.post('http://www.google.com/upload', data=f)
            
          

APIs para PERSONAS



Callbacks de eventos
            
def on_response(r):
    print(r.status_code)

requests.get('http://www.google.com', hooks={response: on_response})
            
          
También para modificar la respuesta
            
def on_response(r):
    r.status_code = 404
    return r

requests.get('http://www.google.com', hooks={response: on_response})
            
          

APIs para PERSONAS



Proxies
            
proxies = {
  'http': 'http://10.10.1.10:3128',
  'https': 'http://10.10.1.10:1080',
  'http://10.20.1.128': 'http://user:password@10.10.1.10:5323'
}

requests.get('http://google.com', proxies=proxies)
            
          
¡Automático con variables de entorno!
            
$ export HTTP_PROXY="http://10.10.1.10:3128"
$ export HTTPS_PROXY="http://10.10.1.10:1080"

$ python
>>> import requests
>>> requests.get('http://www.google.com')
            
          

APIs para PERSONAS



Autenticación personalizada
            
from requests.auth import AuthBase

class PyConAuth(AuthBase):
    def __init__(self, secreto):
        self.secreto = secreto

    def __call__(self, r):
        r.headers['X-PyConEs'] = self.secreto
        return r

>>> r = requests.get('http://2016.es.pycon.org', auth=PyConAuth('Almeria'))

>>> r.status_code
200

>>> r.request.headers
{
    ....
    'X-PyConEs': 'Almeria'
    ....
}
            
          

APIs para PERSONAS












GRACIAS

tapia@openshine.com
@cesargtapia


www.openshine.com