The Graphweaver Salesforce integration is an enterprise solution. The package exists in the private Graphweaver enterprise repo. Please get in contact with us if you wish to use the packages in this repo.
Prerequisites
To connect Graphweaver to a Salesforce GraphQL API, you must have a Salesforce environment to connect to. Sign up for a developer account at https://developer.salesforce.com/signup
Once you have created a Salesforce environment, you will need your Salesforce Instance URL and your Salesforce Access Token.
You will have your URL from the sign up flow and it will look like this:
https://exogee-dev-ed.develop.my.salesforce.com/services/data/v59.0/graphql
To generate a token follow the quickstart guide. (This is the REST quickstart but this is where you’re directed to from the GraphQL API guide)
Once you’ve done this once you can run
sfdx auth:web:login
and
sfdx force:org:display --targetusername <your-user-name>
to generate a new toke as needed. Place these in a .env file next to the env.example file
SALESFORCE_TOKEN=XXXXXXXXX
SALESFORCE_INSTANCE_URL=XXXXXXXXX
Requesting a Salesforce entity
The salesforce package only requests a Salesforce account currently. This follows the pattern of a folder containing the entity, resolver, and index of the Account.
src/backend/schema/account/entity.ts
@Entity("SalesforceAccount", {
provider: new SalesforceBackendProvider("Account"),
})
export class SalesforceAccount extends GraphQLEntity<DataAccount> {
@Field(() => ID)
id!: string;
@Field(() => String)
name!: string;
}
Extending the Salesforce integration
The Salesforce Provider supports find and findOne for accounts. This provider must be extended to support the rest of the base provider methods packages/salesforce/src/graphweaver/provider.ts
export class SalesforceBackendProvider<
D extends BaseDataEntity,
G extends GraphQLEntity<D>
> extends Provider<D, G> {
//@todo - pass in the data entity into the constructor
public async findOne(filter: Filter<G>): Promise<D | null> {
const salesforce = new Salesforce();
return salesforce.getAccount(String(filter.id)) as unknown as D; // @todo fix type once we make this generic
}
// find
public async find(filter: Filter<G>): Promise<D[]> {
const salesforce = new Salesforce();
return salesforce.getAccounts(filter) as unknown as D[]; // @todo fix type once we make this generic
}
}
A new entity file must be created for the entity being requested.
packages/salesforce/src/salesforce/entities/account.ts
export class Account implements BaseDataEntity {
id!: string;
name!: string;
constructor(data: AccountData) {
this.id = data.id;
this.name = data.name;
}
public isCollection(fieldName: string, dataField: any) {
return false;
}
public isReference(fieldName: string, dataField: any) {
return false;
}
}
And the Salesforce class must be extended to implement requesting the new entity from Salesforce.
packages/salesforce/src/salesforce/salesforce.ts
export class Salesforce {
public async getAccounts(filter: SalesforceFilter<Account>) {
// Get the accounts
const query = `query Accounts{
uiapi {
query {
Account${filter ? constructFilter(filter) : ""} {
edges {
node {
Id
Name { value }
}
}
}
}
}
}`;
const response = await fetch(process.env.SALESFORCE_INSTANCE_URL, {
method: "POST",
headers: {
"Content-Type": "application/json",
Accept: "application/json",
Authorization: `Bearer ${process.env.SALESFORCE_TOKEN}`,
},
body: JSON.stringify({
query: query,
}),
});
const data = await response.json();
const flattened = flattenResponse(data as SalesforceAccountGraphQLResponse);
// Map new Accounts from the data
return flattened.map((account) => {
return new Account({ id: account.id, name: account.name });
});
}
public async getAccount(id: string) {
// Make a graphql query to salesforce
const query = `query Account{
uiapi {
query {
Account(where: { Id: { eq: "${id}" } }) {
edges {
node {
Id
Name {
value
}
}
}
}
}
}
}`;
const response = await fetch(process.env.SALESFORCE_INSTANCE_URL, {
method: "POST",
headers: {
"Content-Type": "application/json",
Accept: "application/json",
Authorization: `Bearer ${process.env.SALESFORCE_TOKEN}`,
},
body: JSON.stringify({
query: query,
}),
});
// Flatten the response's edges and nodes
const data = await response.json();
const flattened = flattenResponse(data as SalesforceAccountGraphQLResponse);
// Return a new account object
return new Account({ id: flattened[0].id, name: flattened[0].name });
}
}