Home > Enterprise >  How do I POST a PDF File to a REST-based API?
How do I POST a PDF File to a REST-based API?

Time:10-26

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.AddParametermethod 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 : my code request

postman request

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)
  • Related