I'm trying to post a pdf file to an api.
Here is what my code looks like :
procedure AttachDocument(pathFile : String);
var
RESTClient : TRESTClient;
RESTRequest : TCustomRESTRequest;
Response : TCustomRESTResponse;
begin
RESTClient := TRESTClient.Create('');
try
RESTRequest := TCustomRESTRequest.Create(nil);
try
RESTClient.BaseURL('api_url');
RESTRequest.Client := RESTClient;
RESTRequest.Accept := 'application/json';
RESTRequest.Params.AddHeader('j_token','mytoken').Options := 1; //This is adding poDoNotEncode
RESTRequest.Method := rmPOST
RESTRequest.AddParameter('file',pathFile,pkFILE,1); // Same as above 1 = poDoNotEncode
//RESTRequest.AddFile(pathFile, ctAPPLICATION_PDF);
RESTRequest.Execute;
Response := RESTRequest.Response;
ShowMessage(Response.Content);
finally
RESTRequest.Free;
end;
finally
RESTClient.Free;
end;
end;
For some reason, i can only use the procedure AddFile(const AFileName: string; AContentType: TRESTContentType = TRESTContentType.ctNone);
and because it seems I need to post the file as 'file' to the api, I've decided to use the TCustomRESTRequest.AddParameter
method instead (Although, for the sake of my project i also tested with the commented method).
Currently, when i'm trying to reach the api with this code i receive this :
{"errors":"no files found"}
I then asked the api owner what kind of data I was supposed to post for the api to accept my file, he responded with the C# code he uses to post files to his api :
var client = new RestClient("api_url");
client.Timeout = -1;
var request = new RestRequest(Method.POST);
request.AddHeader("Content-Type", "multipart/form-data");
request.AddHeader("v", "4.2");
request.AddHeader("j_token", "histoken");
request.AddFile("file", "/C:/Users/olivm/Documents/QA API Swagger/smartpacte2.pdf", "application/.pdf");
IRestResponse response = client.Execute(request);
Console.WriteLine(response.Content);
To this point I don't see any major differences between our codes so I decided to test my code on my local python api which looks like that :
from flask import Flask, jsonify, abort, request
app = Flask(__name__)
@app.route('/', methods=['GET', 'POST'])
def home():
print("POST / ENDPOINT")
headers = request.headers
file = request.files
print(headers)
print(file)
return "Request headers:\n" str(headers) str(file)
if __name__ == "__main__":
app.run(port=5000, host="0.0.0.0")
And this is what I recieve when i test my code with RESTClient.BaseURL('127.0.0.1:5000');
Request headers :
Connection : Keep-Alive
Content-Type: multipart/form-data; boundary=-------Embt-Boundary--15DE48857EEC829D
Accept: application/json
Accept-Charset: utf-8, *;q=0.8
User-Agent: Embarcadero RESTClient/1.0
J-Token: mytoken
Content-Length: 836323
Host: 127.0.0.1:5000
--
ImmutableMultiDict([('file', <FileStorage: 'contract.pdf' ('application/pdf')>)])
I'm not really familiar with ImmutableMultiDict
but when I tested the api with Postman by sending the same file I got the same result with some minor changes inside the request headers so I assumed i was posting a file to my api.
My last test was posting the file to a webhook. With Postman, it worked just fine. With my code, no file seemed to be posted as you can see here :
In the end, I'm completely lost : was I right to assume that my python api received a file ? If so then why don't the webhook receive it as well ?
CodePudding user response:
request.files is a dictionnary that contains the different "parts" of the multipart request that is being sent by the client.
It may contain multiple files, so you have to scan the dictionnary
I have modified your example, in order to save the file so you can inspect it:
@app.route('/', methods=['GET', 'POST'])
def home():
print("POST / ENDPOINT")
headers = request.headers
for key, file in request.files.items():
if file.filename != '':
dest = os.path.join(os.path.dirname(__file__), file.filename)
file.save(dest)
print(f'saved into {dest}.')
return "Request headers:\n" str(headers) str(file)