I'm requesting a Salesforce schema data. It has a format
res = {
Id: { name, type, label },
IsDeleted: { type, name, label },
MasterRecordId: { type, name, label },
...and so on
}
So, fields are dynamic.
In queries.js I'm trying to describe it
export const GET_SALESFORCE_FIELDS = gql`
query SalesforceFields {
salesforceFields @rest(endpoint: "schemaservice", type: "SalesforceFields", path: "/fields") {
// What should be here??
}
}
`;
`
How can I describe the dynamic part? I don't have any schema files or resolvers. Only queries.js (for further requests with useQuery) and client.js (where the new ApolloClient is defined)
"@apollo/client": "^3.0.0-rc.10",
"apollo-link-rest": "^0.8.0-beta.0",
@ssuvorov -- Have you verified that the network call is being made successfully?
If it is, then based only on your example response: I would do something like:
export const GET_SALESFORCE_FIELDS = gql`
query SalesforceFields {
salesforceFields @rest(endpoint: "schemaservice", type: "SalesforceFields", path: "/fields") {
Id {
type, name, label
}
IsDeleted {
type, name, label
}
# …remaining fields
}
}
`;
-- Now, this might not work because GraphQL expects every type to have a name, so instead you might need to change this:
export const GET_SALESFORCE_FIELDS = gql`
query SalesforceFields {
salesforceFields @rest(endpoint: "schemaservice", type: "SalesforceFields", path: "/fields") {
- Id {
+ Id @type(name: "FieldDescriptor") {
type, name, label
}
- IsDeleted {
+ IsDeleted @type(name: "FieldDescriptor") {
type, name, label
}
# …remaining fields
}
}
`;
(An alternative way to do this is with a TypePatcher -- documented in the docs)
If every entry is the same object schema, you can even use a Fragment to help you:
export const GET_SALESFORCE_FIELDS = gql`
query SalesforceFields {
salesforceFields @rest(endpoint: "schemaservice", type: "SalesforceFields", path: "/fields") {
Id @type(name: "FieldDescriptor") {
- type, name, label
+ ...FieldFrag
}
IsDeleted @type(name: "FieldDescriptor") {
- type, name, label
+ ...FieldFrag
}
# …remaining fields
}
+ fragment FieldFrag on FieldDescriptor {
+ type
+ name
+ label
+ }
}`;
If you're using Salesforce in a generic way, and you don't know how many columns you're going to have, then it gets a bit more complicated, and you need to use the type-patcher to change the shape of the API.
I don't use Salesforce -- but if it were me, I'd consider asking my Salesforce Representative if they have an official GraphQL Offering, or if they have a blessed 3rd party offering to get it natively.
A quick google search showed this exists: https://appexchange.salesforce.com/appxListingDetail?listingId=a0N3A00000G0l6nUAB -- but it only has one review, so I have no idea if it's any good.
@fbartho Thank you so much for your reply. Unfortunately, it's more than 500 fields. Well, I'd try to clarify with the SF team.
If you need to process a response to make that a little easier, you can use a typenamePatcher, that will give you a hook to completely reshape the response.
A better/more generic schema might virtually look like this:
type MyResponse (
columns: [Column!]!
}
type Column {
name: String!
type: String!
label: String!
}
@fbartho Thanks for your help. This is how I solved it.
// queries.js
export const GET_SALESFORCE_FIELDS = gql`
query SalesforceFields {
salesforceFields @rest(endpoint: "schemaservice", type: "SalesforceFieldsPayload", path: "/fields") {
items @type(name: "Salesforce")
}
}
`;
// client.js
const restLink = new RestLink({
...,
typePatcher: {
SalesforceFieldsPayload: (
data,
outerType,
patchDeeper
) => {
if (data != null) {
data.items = Object.keys(data).map(field => ({ __typename: "Salesforce", ...data[field] }));
}
return data;
}
}
});