RIchiesta HTTP multipart con Python
Giusto un breve promemoria su come effettuare una richiesta HTTP multipart con Python, visto che ci ho messo mezz'ora a trovare il modo :-)
Per prima cosa importiamo un pò di librerie (l'ultima ci servirà solo per costruire l'authentication se vogliamo chiamare una API protetta da basic auth):
from urllib3 import encode_multipart_formdata
from requests import post
from base64 import b64encode
Poi dobbiamo costruire le parti della richiesta. Le parti possono essere qualsiasi cosa, ad esempio testo o il contenuto di un file:
register_document_request = f'''
<register_document_request>
</register_document_request>
'''
document = open(filename, "rb").read()
metadata = "<metadata></metadata>"
Adesso possiamo costruire il multipart, usando il metodo encode_multipart_formdata. Il metodo accetta un oggetto chiave-valore (i valori sono quelli che abbiamo costruito prima) e restituisce due stringhe: il body che contiene gli oggetti e la stringa da utilizzare come header "content-type". Il content type, infatti, oltre a specificare che si tratta di un multipart, deve specificare il "boundary", cioè la stringa random utilizzata nel body per separare le diverse parti.
fields = {
"register_document_request": register_document_request,
"document": document,
"metadata": metadata,
}
body, header = encode_multipart_formdata(fields)
Giusto per curiosità, questo è un possibile aspetto del campo "content-type":
multipart/form-data; boundary=22f8f7d3ad9ba2736a7d6c89afce1ca2
A questo punto possiamo effettuare la richiesta. In questo esempio riporto anche come viene costruito l'header "Authorization", chiaramente come questo è costruito dipende dallo specifico servizio che si va a chiamare e potrebbe non essere necessario.
authAsString = f"{user}:{pwd}"
authAsBytes = authAsString.encode("utf-8")
authAsB64 = b64encode(authAsBytes).decode("ascii")
headers = {
"content-type": header,
"Authorization": f"Basic {authAsB64}"
}
A questo punto possiamo effettuare la chiamata vera e propria. Il parametro "verify" a False specifica che debbono essere ignorati i problemi relativi a certificati SSL nella comunicazione HTTPS. Non si dovrebbe usare, ma può essere necessario se si lavora su sistemi di test con certificati errati o autofirmati.
response = post(
"https://url:porta/servizio",
headers=headers,
data=body,
verify=False # ignora problemi SSL
)
Per verificare che tutto abbia funzionato, possiamo stampare lo stato e il testo della risposta:
print(f"Response status: {response.status_code}")
print(f"Response reason: {response.reason}")
print("")
print(response.text)
Fatto!