Exemples de code Python avec l'API REST Salesforce

python, api
Publié le 2017-12-26 | Jérémy Grèze

L’API REST Salesforce.com peut être difficile à prendre en main. Je partage ici une liste de snippets que j’ai écrit et qui seront utiles, je l’espère. Lisez en premier le snippet sur l’authentification avec l’API REST Salesforce. Le Object Reference for Salesforce décrit les objets disponibles via l’API.

Fonction d’aide

import requests
import base64

def sf_api_call(action, parameters = {}, method = 'get', data = {}):
    """
    Helper function to make calls to Salesforce REST API.
    Parameters: action (the URL), URL params, method (get, post or patch), data for POST/PATCH.
    """
    headers = {
        'Content-type': 'application/json',
        'Accept-Encoding': 'gzip',
        'Authorization': 'Bearer %s' % access_token
    }
    if method == 'get':
        r = requests.request(method, instance_url+action, headers=headers, params=parameters, timeout=30)
    elif method in ['post', 'patch']:
        r = requests.request(method, instance_url+action, headers=headers, json=data, params=parameters, timeout=10)
    else:
        # other methods not implemented in this example
        raise ValueError('Method should be get or post or patch.')
    print('Debug: API %s call: %s' % (method, r.url) )
    if r.status_code < 300:
        if method=='patch':
            return None
        else:
            return r.json()
    else:
        raise Exception('API error when calling %s : %s' % (r.url, r.content))

Rechercher les leads, contacts, opportunités et accounts contenant un texte spécifique

search = 'air france'
call = sf_api_call('/services/data/v40.0/search/', parameters={
        'q': "FIND {%s} IN ALL FIELDS RETURNING Account (Id, Name), Contact (Id, Name), Opportunity (Id, Name), Lead (Id, Name) WITH METADATA='LABELS' " % search
    })
print json.dumps(call, indent=2)

Créer une opportunité

call = sf_api_call('/services/data/v40.0/sobjects/Opportunity/', method="post", data={
    'CloseDate': '2018-03-01',
    'Name': 'My big deal',
    'StageName': 'Sales Accepted Lead',
    'Type': 'Initial Subscription',
    'AccountId': '0019E000009WTBVQA4',
})
opportunity_id = call.get('id')

Attacher un Google Doc à une opportunité

# 1) Create a ContentVersion
ContentVersion = sf_api_call('/services/data/v40.0/sobjects/ContentVersion', method="post", data={
    'Title': 'Important attached document',
    'ContentUrl': 'https://drive.google.com/drive/folders/0B60dm9TFrvQrTDVVYnp3QldvWFE'
})
ContentVersion_id = ContentVersion.get('id')

# 2) Get the ContentDocument id
ContentVersion = sf_api_call('/services/data/v40.0/sobjects/ContentVersion/%s' % ContentVersion_id)
ContentDocument_id = ContentVersion.get('ContentDocumentId')


# 3) Create a ContentDocumentLink
Opportunity_id = "0069E000003o92TQAQ"
ContentDocumentLink = sf_api_call('/services/data/v40.0/sobjects/ContentDocumentLink', method = 'post', data={
        'ContentDocumentId': ContentDocument_id,
        'LinkedEntityId': Opportunity_id,
        'ShareType': 'V'
    })

Uploader un document sur une opportunité

C’est très similaire au code ci-dessus. Seulement la première partie est modifiée.

# 1) Create a ContentVersion
path = "test.png"
with open(path, "rb") as f:
    encoded_string = base64.b64encode(f.read())

ContentVersion = sf_api_call('/services/data/v40.0/sobjects/ContentVersion', method="post", data={
    'Title': 'An image',
    'PathOnClient': path,
    'VersionData': encoded_string,
})
ContentVersion_id = ContentVersion.get('id')

# 2) Get the ContentDocument id (see above)

# 3) Create a ContentDocumentLink (see above)

Ajouter un événement à une opportunité

AddEvent = sf_api_call('/services/data/v40.0/sobjects/Event', method = 'post', data={
    #'Type': 'Meeting', # seems not required
    'Subject': 'Qualification meeting',
    'OwnerId': "0050Y000000PIONQA4",
    'ActivityDate': '2017-07-24T00:00:00.000Z',
    'IsAllDayEvent': True,
    'WhoId': "0030Y00000KAABsQAP", #from doc: "represents a human such as a lead or a contact"
    'WhatId': "0060Y0000077iDGQAY", #from doc: "represents nonhuman objects such as accounts, opportunities, campaigns, cases, or custom objects"
    'Description': 'blablabla'
})

Ajouter un membre à l’OpportunityTeam d’une opportunité

sf_api_call('/services/data/v40.0/sobjects/OpportunityTeamMember', method = 'post', {
    'UserId': user_id,
    'OpportunityId': opportunity_id,
    'OpportunityAccessLevel': 'Edit',
    'TeamMemberRole': 'SDR'
})

Exporter tous les enregistrements d’un objet

Par exemple, exporter toutes les opportunités avec tous les champs. On obtient une liste de dictionnaires. On peut ensuite facilement exporter cette liste dans un CSV ou dataframe Pandas.

object_to_export = "Opportunity"
limit = 10000

describe = sf_api_call('/services/data/v40.0/sobjects/%s/describe' % object_to_export)

if not describe.get('queryable', False):
    raise Exception("This object is not queryable")

fields = [f['name'] for f in describe.get('fields')]

query = "SELECT %s FROM %s LIMIT %i" % (
    ", ".join(fields),
    object_to_export,
    limit
)

call = sf_api_call('/services/data/v40.0/queryAll/', {'q': query})

rows = call.get('records', [])
# for obj in call.get('records', []):
#     print(obj)

next = call.get('nextRecordsUrl', None)

while next:
    call = sf_api_call(next)
    rows.extend(call.get('records', []))
    # for obj in call.get('records', []):
    #     print(obj)
    next = call.get('nextRecordsUrl', None)

# print(rows)