Post files with json data using python requests - python

I have API that accepts multiple files with json data -
curl -X POST \
http://localhost:25965/v1/import \
-H 'Content-Type: application/json' \
-H 'Postman-Token: xxxxxxxx-xxxx-xxxx-xxxx-ba66a9b8d6cb' \
-H 'cache-control: no-cache' \
-H 'content-type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW' \
-F 'files=#C:\Users\user\File1.xlsx' \
-F 'files=#C:\Users\user\File2.xlsx' \
-F 'files=#C:\Users\user\File3.xlsx' \
-F 'values=[
{
"field1": "Value11",
"field2": "Value21",
"field3": "File1.xlsx"
},
{
"field1": "Value21",
"field2": "Value22",
"field3": "File2.xlsx"
},
{
"field1": "Value31",
"field2": "Value32",
"field3": "File3.xlsx"
}
]'
I'm trying to convert this request into python.
With requests, I get error too many values to unpack (expected 2)
def PostFiles(self, apiName, values, files):
url = self.ApiUrl + apiName
params = {}
for file in files:
params.update({'files':file})
response = requests.post(url,
files=params,
data=values,
headers={
'Content-Type':'application/json'},
auth=HTTPKerberosAuth(delegate=True))
return response
I also tried requests_toolbelt but doesn't work.
def PostFiles(self, apiName, values, files):
url = self.ApiUrl + apiName
params = {}
for file in files:
params.update({'files':file})
params.update({'values':json.dumps(values)})
multipart_data = MultipartEncoder(params)
headers = { 'Content-Type':multipart_data.content_type}
response = requests.post(url,
data=multipart_data,
headers=headers,
auth=HTTPKerberosAuth(delegate=True))
return response
this is my function call -
files = [open(join(directory, filename), 'rb')]
#files = [('files',(filename, open(join(directory, filename), 'rb'),'application/vnd.ms-excel'))]
values = [{
'field1': 'value11',
'field2' : 'value21',
'field3' : 'File1.xlsx'
}]
response = PostFiles('import', values, files)
print(response)
there are posts related to this topic but I couldn't find anything with multiple files posting with json.

I modified my code as per Post JSON and file in single request and worked as expected.
def PostFiles(self, apiName, values, files):
url = self.ApiUrl + apiName
params = {
'values': (None, json.dumps(values), 'application/json')
}
for file in files:
params.update({'files':file})
response = requests.post(url,
files=params,
auth=HTTPKerberosAuth(delegate=True))
result = response.json()
if response.status_code != 200 :
raise Exception(result)
return json.dumps(result)

Related

Elasticsearch Search Query using python subprocess: Illegal Argument Exception

I am trying to run a curl command using the run command in the subprocess module in python. But it is failing.
However, the curl command for my elasticsearch search query API is working fine-
curl -k XGET -H "Content-Type: application/json" -H "Authorization: ApiKey Q2txZ2FvSUJ6Nlcwa3pjbnh0NUM6enBidjdNLTdRQVNhc0tuTEk5UEZmZw==" 'https://internal-a02c1b85dade940ef871b0b6d1e65191-1270244841.us-west-2.elb.amazonaws.com:9200/_search?index=.fleet-enrollment-api-keys-7&size=20&pretty' -d '{"query": {"match": {"_id": "c8a537a9-7f98-489b-8f8b-de2450c67ce6"}},"fields" : ["_id", "_index"]}'
This is the code that I am trying to run-
import json
from builtins import int
from pydantic import BaseModel, Field
from typing import List, Dict
from subprocess import PIPE, run
def elasticsearch_search_query(host: str,
port: int,
api_key: str,
path: str,
query: dict,
index: str,
size: int,
fields: List):
es_path = host + ":" + str(port) + path +"?index="+index+"&"+str(size)+"&pretty"
es_header = "Authorization: ApiKey" + " " + api_key
es_dict = {"query": query, "fields": fields}
es_json = json.dumps(es_dict)
es_replaced = " "+"'"+ es_json.replace("'", "\"")+"'"
result = run(["curl", "-k", "-XGET", "-H", "Content-Type: application/json", "-H",
es_header,
es_path,
"-d",
es_replaced]
# ,stdout=PIPE, stderr=PIPE, universal_newlines=True, shell=False
)
print(es_path, es_header, es_replaced)
print(result.stdout)
elasticsearch_search_query(host="https://internal-a02c1b85dade940ef871b0b6d1e65191-1270244841.us-west-2.elb.amazonaws.com:9200/_search", api_key="Q2txZ2FvSUJ6Nlcwa3pjbnh0NUM6enBidjdNLTdRQVNhc0tuTEk5UEZmZw==",
port=9200, size=5, query={"match": {"_id": "c8a537a9-7f98-489b-8f8b-de2450c67ce6"}}, fields=["_id", "_index"], path="/_search",index=".fleet-enrollment-api-keys-7")
Here is the error-
{
"error" : {
"root_cause" : [
{
"type" : "illegal_argument_exception",
"reason" : "request [/_search:9200/_search] contains unrecognized parameter: [5]"
}
],
"type" : "illegal_argument_exception",
"reason" : "request [/_search:9200/_search] contains unrecognized parameter: [5]"
},
"status" : 400
}
https://internal-a02c1b85dade940ef871b0b6d1e65191-1270244841.us-west-2.elb.amazonaws.com:9200/_search:9200/_search?index=.fleet-enrollment-api-keys-7&5&pretty Authorization: ApiKey Q2txZ2FvSUJ6Nlcwa3pjbnh0NUM6enBidjdNLTdRQVNhc0tuTEk5UEZmZw== '{"query": {"match": {"_id": "c8a537a9-7f98-489b-8f8b-de2450c67ce6"}}, "fields": ["_id", "_index"]}'
None
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 350 100 350 0 0 10294 0 --:--:-- --:--:-- --:--:-- 10294
curl: (3) nested brace in URL position 12:
'{"query": {"match": {"_id": "c8a537a9-7f98-489b-8f8b-de2450c67ce6"}}, "fields": ["_id", "_index"]}'
UPDATE
Output of repr(result):
CompletedProcess(args=['curl', '-k', '-XGET', '-H', 'Content-Type: application/json', '-H', 'Authorization: ApiKey Q2txZ2FvSUJ6Nlcwa3pjbnh0NUM6enBidjdNLTdRQVNhc0tuTEk5UEZmZw==', 'https://internal-a02c1b85dade940ef871b0b6d1e65191-1270244841.us-west-2.elb.amazonaws.com:9200:9200/_search?index=.fleet-enrollment-api-keys-7&size=5&pretty', '-d', '{"query": {"match": {"_id": "c8a537a9-7f98-489b-8f8b-de2450c67ce6"}}, "fields": ["_id", "_index"]}'], returncode=3)
Since the error was
contains unrecognized parameter: [5]
The problem is not in the query but in the way you construct es_path. Instead of
&"+str(size)+
it should be
&size="+str(size)+
UPDATE:
Also from what I see your URL now looks like this
https://internal-a02c1b85dade940ef871b0b6d1e65191-1270244841.us-west-2.elb.amazonaws.com:9200:9200/_search?index=.fleet-enrollment-api-keys-7&size=5&pretty
and it's wrong for the following reasons:
the port is specified twice
the index is not at the right location
First, host should just be this (i.e. without port and path)
host="https://internal-a02c1b85dade940ef871b0b6d1e65191-1270244841.us-west-2.elb.amazonaws.com"
Then you can build the URL like this instead:
es_path = host + ":" + str(port) + "/" + index + path +"?size="+str(size)+"&pretty"
i.e. it should look like this instead:
https://internal-a02c1b85dade940ef871b0b6d1e65191-1270244841.us-west-2.elb.amazonaws.com:9200/.fleet-enrollment-api-keys-7/_search?size=5&pretty

Uploading csv file in Golang through API call ( Curl Request & python request provided)

I'm new to Golang and would like to upload a csv file to a website with a client_api_key, bucket and folder. Is there a Golang solution for this? I'm creating the csv file via Golang.
This is the curl request
curl --location -- request POST 'https://drivex-service.sample.com/report/api/upload' \
-- hearder 'Cookie: '89825f9123456fa0' \
-- form 'Client_api_key=vfBM-zrfumyh9WUTKGbQ=' \
-- form 'bucket=bucket1' \
-- form 'folder=ROLE/YES/FOLDER' \
-- form 'files[]=#/D:/User/example.csv'
Here's the python post request
def drivex_upload(file_obj):
data = {
"folder": 'ROLE/YES/FOLDER',
"client_api_key": 'vfBM-zrfumyh9WUTKGbQ=',
"bucket": 'bucket1'
}
headers = {
"Accept": "application/json",
"ContentType": "multipart/form-data"
}
files = {
"files[]": file_obj
}
r = requests.post(
self.upload_url,
data=data,
files=files,
headers=headers,
verify=False,
)
if r.status_code == 200:
json_data = r.json()
return r, None
else:
return r, "error while uploading"
I tried the following in Golang (not using multiparse) but am unsure of where to put the Client_api_key, bucket and folder
file, err := os.Create(fileName)
if err != nil {
log.Fatal(err)
}
defer file.Close()
writer := csv.NewWriter(file)
defer writer.Flush()
// define column headers
// write column headers
writer.Write(headers)
for key := range m {
r := make([]string, 0, 1+len(headers))
r = append(r, m.field1,m.field2,m.field3)
writer.Write(r)
}
req, err := http.NewRequest("POST", "https://drivex-service.sample.com/report/api/upload", file)
if err != nil {
log.Fatal(err)
}
req.Header.Set("Accept", "application/json")
Will appreciate help in constructing a working Golang POST request for this!
I think this does it:
package main
import (
"net/http"
"net/url"
"os"
)
func main() {
r, e := http.NewRequest(
"POST", "https://drivex-service.sample.com/report/api/upload", nil,
)
if e != nil {
panic(e)
}
f, e := os.ReadFile("file.csv")
if e != nil {
panic(e)
}
v := url.Values{
"Client_api_key": {"=vfBM-zrfumyh9WUTKGbQ="},
"bucket": {"bucket1"},
"files[]": {string(f)},
"folder": {"ROLE/YES/FOLDER"},
}
r.URL.RawQuery = v.Encode()
r.Header.Set("Cookie", "89825f9123456fa0")
new(http.Client).Do(r)
}
You should also be able to send the query string as the body, in case this doesn't
work.
https://golang.org/pkg/net/http#NewRequest

How to upload a file in Autentique API using Python?

Autentique API is Graphql. Documentation: https://docs.autentique.com.br/api/integracao/criando-um-documento
You must create an account on Autentique and an API key first.
Uploading the file in sandbox and sending it to an email for signing. It returns document's id and name.
Using curl
curl -H "Authorization: Bearer <TOKEN>" https://api.autentique.com.br/v2/graphql \
-F operations='{"query": "mutation CreateDocumentMutation($document: DocumentInput! $signers: [SignerInput!]! $file: Upload!) {createDocument(sandbox: true, document: $document, signers: $signers, file: $file) {id name }}", "variables": { "document": {"name": "<DOCUMENT_NAME>"}, "signers": [{"email": "<FROM_EMAIL>","action": "SIGN"}], "file": null } }' \
-F map='{ "0": ["variables.file"] }' \
-F 0=#<FULL_PATH_FILE>
Using aiogqlc
https://github.com/DoctorJohn/aiogqlc
import asyncio
from aiogqlc import GraphQLClient
endpoint = "https://api.autentique.com.br/v2/graphql"
headers = {
"Authorization": "Bearer <TOKEN>"
}
client = GraphQLClient(endpoint, headers=headers)
async def create_document():
query = """
mutation CreateDocumentMutation(
$document: DocumentInput!
$signers: [SignerInput!]!
$file: Upload!
) {
createDocument(
sandbox: true,
document: $document,
signers: $signers,
file: $file)
{
id
name
}
}"""
variables = {
"document": {
"name": "<DOCUMENT_NAME>"
},
"signers": [{
"email": "<FROM_EMAIL>",
"action": "SIGN"
}],
"file": open('<FULL_PATH_FILE>', 'rb'),
}
response = await client.execute(query, variables=variables)
print(await response.json())
if __name__ == '__main__':
asyncio.get_event_loop().run_until_complete(create_document())
For more languages implementations: https://github.com/jaydenseric/graphql-multipart-request-spec#implementations

Rewriting Curl request in Python: Result Invalid Json

I have this curl that works, it returns this
curl -X POST \
https://login.smoobu.com/booking/checkApartmentAvailability \
-H 'Api-Key: xxxxx' \
-H 'cache-control: no-cache' \
-d '{
"arrivalDate" : "2018-04-01",
"departureDate": "2019-12-03",
"apartments": [126936, 127858, 126937],
"customerId": 38484
}'
it returns this
{
"availableApartments": [
127858
],
"prices": [],
"errorMessages": {
"126936": {
"errorCode": 405,
"message": "The chosen day of departure is not available.",
"departureDays": [
"Sa"
]
},
"126937": {
"errorCode": 405,
"message": "The chosen day of departure is not available.",
"departureDays": [
"Sa"
]
}
}
}
I rewrote it in python like so
In [1]: import requests
In [2]: headers = {'Api-Key': 'xxxx', 'cache-control': 'no-cache'}
In [8]: payload = {
...: "arrivalDate" : "2018-04-01",
...: "departureDate": "2019-12-03",
...: "apartments": [126936, 127858, 126937],
...: "customerId": 38484
...: }
In [4]: r = requests.post("https://login.smoobu.com/booking/checkApartmentAvailability", data=payload, headers=headers)
In [5]: r
Out[5]: <Response [400]>
In [13]: r.content
Out[13]: b'{"title":"Error occurred","detail":"json is invalid"}'
I got back a response of invalid json, I'm not sure why though since the way I know it works is it takes a dict and turns it into a json request.
For sending JSON, you should use the json parameter:
r = requests.post("https://login.smoobu.com/booking/checkApartmentAvailability", json=payload, headers=headers)
As explained in the docs:
r = requests.post(url, data=json.dumps(payload))
r = requests.post(url, json=payload)
Instead of encoding the dict yourself, you can also pass it directly using the json parameter (added in version 2.4.2) and it will be encoded automatically

How to use cURL in python

I want to use this cURL command in (python with pycurl):
curl -X POST --header "Authorization: key=AAAAWuduLSU:APA91bEStixxx" --header "Content-Type: application/json" https://fcm.googleapis.com/fcm/send -d '{"to" : "fC6xEWZwcu0:APA91xxx", "priority" : "high", "notification" : { "body" : "Background Message", "title" : "BG Title", "sound" : "default"}, "data" : { "title" : "FG Title", "message" : "Foreground Message" }}'
My source code is like this
import pycurl
import re
import io
import json
import requests
data = {"to" : "fC6xEWZwcu0:APA91xxx", "priority" : "high", "notification" : { "body" : "Background Message", "title" : "BG Title", "sound" : "sound.mp3"}, "data" : { "title" : "FG Title", "message" : "Foreground Message" }}
buffer = io.BytesIO()
c = pycurl.Curl()
c.setopt(c.URL, 'https://fcm.googleapis.com/fcm/send')
c.setopt(c.POST, True)
c.setopt(c.SSL_VERIFYPEER, False)
c.setopt(pycurl.HTTPHEADER, [
'Content-type:application/json charset=utf-8',
'Content-Length:0'
'Authorization: Basic key=AAAAWuduLSU:APA91bEStixxx'
])
c.setopt(c.WRITEDATA, buffer)
'''
c.setopt(pycurl.HTTPBODY, [
'test:test'
])
'''
print(buffer)
# c.setopt(c.HEADERFUNCTION, header_function)
c.perform()
print('\n\nStatus: %d' % c.getinfo(c.RESPONSE_CODE))
print('TOTAL_TIME: %f' % c.getinfo(c.TOTAL_TIME))
c.close()
body = buffer.getvalue()
print(body)
No need to use curl in Python when you have requests!
import requests
import json
post_data = {"to" : "fC6xEWZwcu0:APA91xxx",
"priority" : "high",
"notification": {"body": "Background Message",
"title": "BG Title",
"sound": "sound.mp3"},
"data": {"title": "FG Title",
"message": "Foreground Message"}}
header_data = {'Authorization': 'key=AAAAWuduLSU:APA91bEStixxx',
'Content-Length': '0',
'Content-type': 'application/json'}
r = requests.post('https://fcm.googleapis.com/fcm/send',
data = json.dumps(post_data),
headers=header_data)
print('\n\nStatus: %d'.format(r.status_code))
print('TOTAL_TIME: %f'.format(r.elapsed.total_seconds()))
print(r.text)
Haven't tested this, but it should set you on the right track.
I'd also recommend checking out the Requests module docs for more information :-)

Categories

Resources