function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
Caleb Kuester 44Caleb Kuester 44 

Creating a Bulk v2 Data Load Job via REST & Python

Greetings!

I'm able to authenticate with code that goes something like this:

request.request("POST", "/services/oauth2/token", urllib.parse.urlencode(body), headers)
response = request.getresponse()
print("status and reason: ", response.status, response.reason)
if(response.status == 200):
    response_string = str(response.read())
    formatted_for_json_string = response_string[-(len(response_string)-2):-1]
    json_response = json.loads(formatted_for_json_string)
    for value in json_response:
        if(value == "access_token"):
            access_token = json_response[value]
        if(value == "instance_url"):
            _endpoint = json_response[value]
        if(value == "token_type"):
            token_type = json_response[value]


That part works and sets up some of the required data for the Bulk Load Job creation.
 

headers = {
    "Authorization" : token_type + " " + access_token,
    "Content-Type": "application/json",
    "Accept": "*/*",
    "Cache-Control": "no-cache",
    "Host": host,
    "Accept-Encoding": "gzip, deflate, br",
    "Connection": "keep-alive"
}

body = {
    "object":"Account",
    "contentType":"CSV",
    "operation":"update"
}

request = client.HTTPSConnection(host, timeout=10)
request.request("POST", "/", urllib.parse.urlencode(body), headers)
response = request.getresponse()
 

The reponse is 200, but the gzip decompression of the response is:
b''

This is an indication that the response was empty. This makes sense considering a Bulk Data Load job was not created as a result of the transaction.

This all works in Postman and I've been attempting to mirror as much of the Postman behavior as possible except for adding the Postman-specific header bits and cookie info. The Authorization part has "Bearer key" in it, though the behavior is no different if I don't have a key.

If I use the key obtained in Postman, that also doesn't change the behavior.

Curious what I'm missing.

Best Answer chosen by Caleb Kuester 44
SwethaSwetha (Salesforce Developers) 
HI Caleb,
As suggested in https://salesforce.stackexchange.com/a/214425/80089 try 
RestContext.response.responseBody = Blob.valueOf(gen.getAsString());
RestContext.response.addHeader('Content-Type', 'application/json');

Also see https://salesforce.stackexchange.com/questions/122861/rest-api-working-well-from-postman-doesnt-work-from-salesforce

If this information helps, please mark the answer as best. Thank you

All Answers

SwethaSwetha (Salesforce Developers) 
HI Caleb,
As suggested in https://salesforce.stackexchange.com/a/214425/80089 try 
RestContext.response.responseBody = Blob.valueOf(gen.getAsString());
RestContext.response.addHeader('Content-Type', 'application/json');

Also see https://salesforce.stackexchange.com/questions/122861/rest-api-working-well-from-postman-doesnt-work-from-salesforce

If this information helps, please mark the answer as best. Thank you
This was selected as the best answer
Caleb Kuester 44Caleb Kuester 44
Thanks Swetha!

It actually wasn't the solution to the problem for python, but your recommendation narrowed the location of the problem down to the encoding of the body in the request. For Python, all I needed to do was:
request.request("POST", "/services/data/v"+str(version)+".0/jobs/ingest", json.dumps(body), header)
instead of:
request.request("POST", "/services/data/v"+str(version)+".0/jobs/ingest", urllib.parse.urlencode(body), header)

urlencode was needed for the authentication part because the authentication header had "Content-Type" : "application/x-www-form-urlencoded"

This was due to my lack of experience and understanding of system integration.