- Overview
- Overview of Graphweaver Customisation
- How to Add a Custom Query or Mutation
- Disabling generated queries and mutations
- Important Things To Include In Your Custom Code
- Conclusion
Overview
Graphweaver provides powerful capabilities for automatically generating GraphQL schemas and types at runtime.
Yet, there may be situations where you need to customise the behaviour of Graphweaver to suit your specific application requirements.
Overview of Graphweaver Customisation
Graphweaver is designed to be extensible, allowing you to add custom queries, mutations, and other functionality to your GraphQL API.
Customisation in Graphweaver typically involves adding additional queries or mutations or modifying the entities exposed by the API.
Here are some common scenarios where you might need to customise Graphweaver:
- Implementing custom business logic: You may need to define custom queries or mutations to perform specific operations that are not covered by the automatically generated CRUD operations.
- Modifying the generated schema: You might want to tweak the generated GraphQL schema to add additional fields, modify field behaviour, or introduce custom types. This is especially true for modifying the input types.
- Enhancing error handling and validation: You can customise the error handling and validation logic in Graphweaver to align with your application's requirements and error response formats.
Next, let’s look at how you can add a custom query or mutation.
How to Add a Custom Query or Mutation
Custom queries and mutations can be defined anywhere in your project.
In this example, let's say we want to implement a custom query to fetch users based on their age.
We can define a custom query named usersByAge
:
// User.js
import { graphweaverMetadata, Source } from '@exogee/graphweaver';
import { fetchUsersByAge } from './user-provider';
import { User } from './entity';
graphweaverMetadata.addQuery({
name: 'usersByAge',
getType: () => [User],
resolver: (_: Source, { age }: { age: number }) {
// Custom logic to fetch drivers by age
// Implement your own code here
return await fetchUsersByAge(age);
},
});
In this example, we define the usersByAge
query that takes an age
argument. Inside the resolver method, you can implement your own logic to fetch users based on the provided age.
To use the custom query in your GraphQL API, you can include it in your GraphQL schema and make a request to it:
query {
usersByAge(age: 30) {
id
firstName
lastName
age
}
}
In this query, we're using the custom usersByAge
query to fetch users with an age of 30. The response will include the ID, first name, last name, and age of the matching users.
Similarly, you can define custom mutations in the same way using the graphweaverMetadata.addMutation
function.
@InputType('CreateThumbnailInput')
class CreateThumbnailInput {
@Field(() => ID)
submissionId: number;
@Field(() => Number)
width: number;
@Field(() => Number)
height: number;
}
graphweaverMetadata.addMutation({
name: 'createThumbnail',
getType: () => Submission,
args: { input: () => CreateThumbnailInput },
resolver: async ({
args
}: ResolverOptions<{ input: CreateThumbnailInput }>) => {
const database = ConnectionManager.database(pgConnection.connectionManagerId);
const submission = await database.em.findOneOrFail(Submission, {
id: args.input.submissionId.toString(),
});
// Custom mutation logic here
...
// create the new submission in the database
const result = await database.em.create(Submission, {
image: {
filename: upload.filename,
type: upload.type,
url: upload.url,
},
});
await database.em.persistAndFlush(result);
// Call fromBackendEntity to ensure the client can access nested fields
return fromBackendEntity(Submission, result);
}
})
Disabling generated queries and mutations
If you’re taking the time to implement custom logic for querying and modifying an entity, it’s likely you might also need to disable the default queries and mutations that Graphweaver generates for you. To achieve this, you need to set excludeFromBuiltInOperations
on the entity’s schema definition:
@Entity('Genre', {
provider: new MikroBackendProvider(OrmGenre, connection),
apiOptions: { excludeFromBuiltInOperations: true },
})
export class Genre {
@Field(() => ID, { primaryKeyField: true })
genreId!: number;
@Field(() => String, { nullable: true, adminUIOptions: { summaryField: true } })
name?: string;
@RelationshipField<Track>(() => [Track], { relatedField: 'genre' })
tracks!: Track[];
}
Important Things To Include In Your Custom Code
Firstly, note that no access rights checks are enforced by Graphweaver when you add a custom query or mutation. It’s up to you to implement those checks within the body of the resolver you supply. You probably want the access rights to be consistent with the rules you’ve laid out with decorators on your other entities using generated queries and mutations.
Next, if you want a caller to be able to select nested entities below the result directly returned by your resolver method, you need to wrap that returned value with fromBackendEntity
. For example, let’s say you add a custom mutation createBlogPost
. The final step might be to insert a record into the posts
table of the database. If you simply return the newly inserted record, you can select fields on the new Post
entity on the result, but not the associated nested Author
entity. By calling fromBackendEntity
it enhances the result so it can run through additional resolvers to fill in all of the requested nested fields.
Conclusion
Customising Graphweaver allows you to tailor the behaviour of your GraphQL API to meet your specific application requirements.
By following the steps outlined in this guide and adhering to best practices, you can effectively customise Graphweaver and extend its functionality.
Remember that while customisation offers flexibility, it's essential to strike a balance between customisation and maintainability.
Excessive modifications or deviations from the core functionality of Graphweaver may make it harder to integrate future updates and maintain your codebase.
With the ability to customise Graphweaver, you can unlock the full potential of your Graphweaver API and tailor it to suit your unique application needs.