Skip to Content

TypeSafe Middleware Hooks

Published: October 19, 2021

One of the strengths of WunderGraph is customization. With Hooks, you gain full control over the Request Lifecycle and can manipulate requests easily.

In comparison to other Frameworks, we're giving you the best possible Developer Experience for extensions

You can rewrite an incoming request and manipulate the Inputs of an Operation. Once the request was resolved, you're able to "hook" into the Request Lifecycle again and manipulate the response before sending it back to the client.

WunderGraph Hooks are similar to WebHooks, but TypeSafe, easy to test and easy to integrate into your WunderGraph applications.

So, how are WunderGraph Middleware Hooks different and what do we mean by TypeSafe?

Let's look at an example Operation using the SpaceX API:

query Missions ($find: MissionsFind) {
missions (find: $find) {
id
description
manufacturers
name
}
}

This Operation will generate a JSON RPC Endpoint as well as TypeScript models for both Inputs and the Response.

With Hooks, we're extending this with one addition, we're scaffolding a TypeSafe Hooks Configuration that allows you to write your Hooks using TypeScript. Here's how it looks like for the Operation above:

// all of this is generated
export interface HooksConfig {
queries?: {
Dragons?: {
preResolve?: (ctx: Context) => Promise<void>;
postResolve?: (ctx: Context, response: DragonsResponse) => Promise<void>;
mutatingPostResolve?: (ctx: Context, response: DragonsResponse) => Promise<DragonsResponse>;
};
Missions?: {
preResolve?: (ctx: Context, input: MissionsInput) => Promise<void>;
mutatingPreResolve?: (ctx: Context, input: MissionsInput) => Promise<MissionsInput>;
postResolve?: (ctx: Context, input: MissionsInput, response: MissionsResponse) => Promise<void>;
mutatingPostResolve?: (
ctx: Context,
input: MissionsInput,
response: MissionsResponse
) => Promise<MissionsResponse>;
};
};
mutations?: {};
}

You're able to define 4 distinct hooks, preResolve, mutatingPreResolve, postResolve and mutatingPostResolve. The pre- and postResolve hooks are good for logging or side effects, e.g. sending an E-Mail after a mutation. Mutating Hooks can be used to "mutate" the Request, e.g. change the input variables (preResolve) or modify the response (postResolve).

As you can see from the HooksConfig definition, all hooks are TypeSafe, inputs as well as the response type definitions. We automatically generate all of this from your Operations to give you the ultimate developer experience.

Finally, have a look at an example hook implementation. Hooks need to be implemented in the wundergraph.hooks.ts file.

// generated
const wunderGraphHooks = ConfigureWunderGraphHooks({
// generated
queries: {
// generated
Missions: {
// generated
async mutatingPreResolve (ctx, input) {
// user defined
return {
...input,
find: {
...input.find,
name: "Telstar"
}
}
}
}
}
})

In this case, we're hard-coding the find variable before the execution starts. Other examples would be to use the user object from the Context (ctx) to manipulate the input variables.

Here's another example of how to use a mutatingPostResolve hook to rewrite a response:

// generated
const wunderGraphHooks = ConfigureWunderGraphHooks({
// generated
queries: {
// generated
TowerByKey: {
// generated
async mutatingPostResolve(ctx, input, response){
// user defined
return {
...response,
data: {
...response.data,
TowerDetail: response.data?.TowerDetail?.map(detail => ({
...detail,
conductorSetHooks: detail.conductorSetHooks?.filter(csh=>csh.conductorSetHookId?.id !== "456"),
}))
}
}
}
}
}
});

What's best about all of this? It's TypeScript! It's using Node.JS to execute, you can use any npm package you want, write any code you want, whatever solves the problem best.

How to#

If you're looking for more specific information on how to use Hooks, have a look at the reference.


Product

Subscribe to our newsletter!

Stay informed when great things happen! Get the latest news about APIs, GraphQL and more straight into your mailbox.

© 2021 WunderGraph