Hacer una solicitud a una API RESTful usando python

221

Tengo una API RESTful que he expuesto utilizando una implementación de Elasticsearch en una instancia EC2 para indexar un corpus de contenido. Puedo consultar la búsqueda ejecutando lo siguiente desde mi terminal (MacOSX):

curl -XGET 'http://ES_search_demo.com/document/record/_search?pretty=true' -d '{
  "query": {
    "bool": {
      "must": [
        {
          "text": {
            "record.document": "SOME_JOURNAL"
          }
        },
        {
          "text": {
            "record.articleTitle": "farmers"
          }
        }
      ],
      "must_not": [],
      "should": []
    }
  },
  "from": 0,
  "size": 50,
  "sort": [],
  "facets": {}
}'

¿Cómo me convierto en una solicitud de API usando python/requestso python/urllib2(no estoy seguro de cuál elegir, he estado usando urllib2, pero escucho que las solicitudes son mejores ...)? ¿Paso como encabezado o de otra manera?

usuario7289
fuente

Respuestas:

340

Usando solicitudes :

import requests
url = 'http://ES_search_demo.com/document/record/_search?pretty=true'
data = '''{
  "query": {
    "bool": {
      "must": [
        {
          "text": {
            "record.document": "SOME_JOURNAL"
          }
        },
        {
          "text": {
            "record.articleTitle": "farmers"
          }
        }
      ],
      "must_not": [],
      "should": []
    }
  },
  "from": 0,
  "size": 50,
  "sort": [],
  "facets": {}
}'''
response = requests.post(url, data=data)

Dependiendo del tipo de respuesta que devuelva su API, es probable que desee ver response.texto response.json()(o posiblemente inspeccionar response.status_codeprimero). Vea los documentos de inicio rápido aquí , especialmente esta sección .

andersschuller
fuente
3
Creo que debería ser: respuesta =
request.post
8
"request.get" no toma el parámetro "data". Podría tomar el parámetro opcional "params", que generalmente es un dict que lleva una cadena de consulta. Si es necesaria una carga útil para obtener datos (como el ejemplo publicado en cuestión), entonces se debe usar "request.post". Además, el uso de la biblioteca "json" facilita el análisis de la respuesta json.
HVS
44
@ParveenShukhala "Las solicitudes admiten oficialmente Python 2.6–2.7 y 3.3–3.5, y funcionan muy bien en PyPy". - pypi.python.org/pypi/requests
danio
2
Como está enviando JSON, puede usar el parámetro json en lugar de datos como este: respuesta = solicitudes.post (url, json = datos)
Mark Chorley
101

Usar peticiones y json lo hace simple.

  1. Llamar a la API
  2. Suponiendo que la API devuelve un JSON, analiza el objeto JSON en un dict Python usando la json.loadsfunción
  3. Recorra el dict para extraer información.

El módulo de solicitudes le proporciona una función útil para bucle para el éxito y el fracaso.

if(Response.ok): le ayudará a determinar si su llamada API es exitosa (Código de respuesta - 200)

Response.raise_for_status() le ayudará a recuperar el código http que devuelve la API.

A continuación se muestra un código de muestra para realizar tales llamadas API. También se puede encontrar en github . El código supone que la API hace uso de la autenticación de resumen. Puede omitir esto o utilizar otros módulos de autenticación apropiados para autenticar al cliente que invoca la API.

#Python 2.7.6
#RestfulClient.py

import requests
from requests.auth import HTTPDigestAuth
import json

# Replace with the correct URL
url = "http://api_url"

# It is a good practice not to hardcode the credentials. So ask the user to enter credentials at runtime
myResponse = requests.get(url,auth=HTTPDigestAuth(raw_input("username: "), raw_input("Password: ")), verify=True)
#print (myResponse.status_code)

# For successful API call, response code will be 200 (OK)
if(myResponse.ok):

    # Loading the response data into a dict variable
    # json.loads takes in only binary or string variables so using content to fetch binary content
    # Loads (Load String) takes a Json file and converts into python data structure (dict or list, depending on JSON)
    jData = json.loads(myResponse.content)

    print("The response contains {0} properties".format(len(jData)))
    print("\n")
    for key in jData:
        print key + " : " + jData[key]
else:
  # If response code is not ok (200), print the resulting http error code with description
    myResponse.raise_for_status()
HVS
fuente
2
La última porción con iteración sobre las teclas no siempre funcionará porque el documento JSON puede tener una matriz como elemento de nivel superior. Por lo tanto, sería un error intentar conseguirlojData[key]
Denis The Menace
@DenisTheMenace si es una matriz, ¿cómo podría recorrerla?
qasimalbaqali
@qasimalbaqali de la misma manera que recorre el diccionario. Pero los elementos de la matriz serán simples jData, nojData[key]
Denis The Menace
Nota al margen: si su API devuelve una gran respuesta JSON, puede imprimirla así: print(json.dumps(jData, indent=4, sort_keys=True))
Marco
2
Bajo python3, lo siguiente fue escupido 'JSON debe ser str no bytes'. Esto se soluciona decodificando la salida, es decir, json.loads (myResponse.content.decode ('utf-8')). También debe ajustar la clave y la clave jData con str () para que cuando la API RESTful devuelva enteros, no se queje.
Mirkules
11

Por lo tanto, si desea pasar datos en el cuerpo de una solicitud GET, lo mejor sería hacerlo en una llamada POST. Puede lograr esto utilizando ambas solicitudes.

Solicitud sin procesar

GET http://ES_search_demo.com/document/record/_search?pretty=true HTTP/1.1
Host: ES_search_demo.com
Content-Length: 183
User-Agent: python-requests/2.9.0
Connection: keep-alive
Accept: */*
Accept-Encoding: gzip, deflate

{
  "query": {
    "bool": {
      "must": [
        {
          "text": {
            "record.document": "SOME_JOURNAL"
          }
        },
        {
          "text": {
            "record.articleTitle": "farmers"
          }
        }
      ],
      "must_not": [],
      "should": []
    }
  },
  "from": 0,
  "size": 50,
  "sort": [],
  "facets": {}
}

Llamada de muestra con solicitudes

import requests

def consumeGETRequestSync():
data = '{
  "query": {
    "bool": {
      "must": [
        {
          "text": {
            "record.document": "SOME_JOURNAL"
          }
        },
        {
          "text": {
            "record.articleTitle": "farmers"
          }
        }
      ],
      "must_not": [],
      "should": []
    }
  },
  "from": 0,
  "size": 50,
  "sort": [],
  "facets": {}
}'
url = 'http://ES_search_demo.com/document/record/_search?pretty=true'
headers = {"Accept": "application/json"}
# call get service with headers and params
response = requests.get(url,data = data)
print "code:"+ str(response.status_code)
print "******************"
print "headers:"+ str(response.headers)
print "******************"
print "content:"+ str(response.text)

consumeGETRequestSync()
gvir
fuente
tiene un enlace muerto allí
usuario3157940
44
se debe usar la variable de encabezados: request.get (... headers = headers, ....)
Markus Meyer
9

A continuación se muestra el programa para ejecutar la API de resto en python-

import requests
url = 'https://url'
data = '{  "platform": {    "login": {      "userName": "name",      "password": "pwd"    }  } }'
response = requests.post(url, data=data,headers={"Content-Type": "application/json"})
print(response)
sid=response.json()['platform']['login']['sessionId']   //to extract the detail from response
print(response.text)
print(sid)
Shashank G
fuente