Skip to content

Instantly share code, notes, and snippets.

@DmitryMasley
Last active July 6, 2022 15:18
Show Gist options
  • Save DmitryMasley/b6dd921a1d2be9157eac7da0ff82732c to your computer and use it in GitHub Desktop.
Save DmitryMasley/b6dd921a1d2be9157eac7da0ff82732c to your computer and use it in GitHub Desktop.
Graphql Schema
type Locale {
localeId: String!
description: String!
}
type LocalePair {
targetLocaleId: String!
sourceLocaleId: String!
}
type Workflow {
name: String!
workflowUid: ID!
workflowSteps: [WorkflowStep!]!
}
type WorkflowStep {
name: String!
workflowStepUid: ID!
}
type WorkflowAssignment {
accountUid: String!
workflowUid: String!
workflowStepUid: String!
sourceLocaleId: String!
targetLocaleId: String!
}
type User {
firstName: String
lastName: String
email: String!
userUid: ID!
localePairs: [LocalePair]
assignments: [WorkflowAssignment]
}
# this schema contains multiple queries for different types of entities
# entities not linked together in types, so consumer of this schema will have to
# make all these queries, notmalize the data and merge it in order to get full information
type Query {
getUser(userUid: String!): User
# client will have to make this request to get locale descriptions for `localePairs` and `workflowAssignments`
getLocales(localeIds: [String!]): [Locale!]!
# client will have to make this request to get workflow and workflows steps names
getWorkflows(workflowUids: [String!]): [Workflow!]!
}
type Locale {
localeId: String!
description: String!
}
type LocalePair {
targetLocale: Locale
sourceLocale: Locale
}
type Workflow {
name: String!
workflowUid: ID!
workflowSteps: [WorkflowStep!]!
}
type WorkflowStep {
name: String!
workflowStepUid: ID!
}
type WorkflowAssignment {
accountUid: String!
workflow: Workflow!
workflowStep: WorkflowStep!
sourceLocale: Locale!
targetLocale: Locale!
}
type User {
firstName: String
lastName: String
email: String!
userUid: ID!
localePairs: [LocalePair]
assignments: [WorkflowAssignment]
}
type Query {
# client have only one query. client can select which fields are required for particular context
# no additional logic needed in order to get more/less data
# amount of data and performance depends on field selection
# performance optimisations can be done in single place
getUser(userUid: String!): User
}
type LocalePair = any;
type WorkflowAssignment = any;
// all data returned by root resolve
// it seems this is the simplest solution
// but it makes different entities coupled together in one function
// extending User types will require to add more logic to this function
// If you need to return User entity in different query/mutation you'll have to duplicate this logic
// Also all requests will be executed regardless of fields selection on client
export const resolvers = {
Query: {
async getUser(_, { userUid }, { dataSources }) {
const {
firstName,
lastName,
email
} = await dataSources.loadUser(userUid);
// get locale pairs with descriptions for user
const localePairs: LocalePair[] =
await dataSources.getUserLocalePairs(userUid);
// get raw workflow assignments without locale descriptions
const rawWorkflowAssignments = await dataSources.getUserWorkflowAssignments(userUid)
// get locales by localeIds in workflow assignments
const localeIds = getUniqLocaleIds(rawWorkflowAssignments);
const locales = dataSources.getLocaless(localeIds);
// add descriptions to locales in workflow assignments
const workflowAssignments: WorkflowAssignment[] = addLocalesToWorkflowAssignments(
rawWorkflowAssignments,
locales
);
// probably need to query workflow and workflowStep details
return {
firstName,
lastName,
email,
localePairs,
workflowAssignments,
userUid
};
}
}
};
// this implementation ties to do best to avoid overfetching
// also each field is independent and logic is straightforward for each of the resolvers,
// despite, some fields using same datasource requests can be deduplicated and batched using utils like dataLoader
// The User entity can be reused in different queries/mutation without additional work
export const resolvers = {
Query: {
async getUser(_, { userUid }) {
return {
userUid
};
}
},
User: {
async firstName({ userUid }, _, { dataSources }) {
return (await dataSources.loadUser(userUid)).firstName;
},
async lastName({ userUid }, _, { dataSources }) {
return (await dataSources.loadUser(userUid)).lastName;
},
async email({ userUid }, _, { dataSources }) {
return (await dataSources.loadUser(userUid)).email;
},
async localePairs({ userUid }, _, { dataSources }) {
const { assignedLocalePairs } = await dataSources.loadLocalePairs(userUid);
return assignedLocalePairs.map(({ sourceLocaleId, targetLocaleId }) => ({
sourceLocale: {
localeId: sourceLocaleId
},
targetLocale: {
localeId: targetLocaleId
}
}));
},
workflowAssignments({ userUid }, _, { dataSources }) {
dataSources.loadUserWorkflowAssignments(userUid);
}
},
Locale: {
async description({ localeId }, _, { dataSources }) {
return (await dataSources.loadLocale(localeId)).description;
}
},
WorkflowStep: {
async name({ workflowUid }, _, { dataSources }) {
}
},
Workflow: {
async name({ workflowUid }, _, { dataSources }) {
},
async workflowSteps({ workflowUid }, _, { dataSources }) {
}
}
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment