Blitz: Use context in prefetching

Created on 20 Jul 2020  路  10Comments  路  Source: blitz-js/blitz

What do you want and why?

I am currently writing a Blitz middleware to integrate Prisma-multi-tenant. (See package: https://github.com/Errorname/prisma-multi-tenant/tree/master/packages/blitz)


This is how it works:

  1. You add the middleware to your blitz.config.js file:
const { multiTenantMiddleware } = require('@prisma-multi-tenant/blitz')

module.exports = {
  // ...
  middleware: [
    multiTenantMiddleware((req, res) => {
      // The name can come from anywhere (headers, token, ...)
      return 'my_tenant_A'
    }),
  ],
}
  1. Then, in your queries and mutation, you access the tenant from the context:
export default async function getProjects(args, ctx) {
  const projects = await ctx.db.project.findMany(args)

  return projects
}

This code is currently working, and adds multi-tenancy to a Blitz application. However, it outputs long errors in the console when running blitz start.

Click to see error

(node:12661) UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'project' of undefined
    at getProjects (webpack-internal:///./app/_resolvers/projects/queries/getProjects.ts:11:33)
    at queryFn (/Users/errorname/Documents/Vrac/hello-prisma2/blitz-app/node_modules/@blitzjs/core/dist/core.cjs.development.js:133:14)
    at /Users/errorname/Documents/Vrac/hello-prisma2/blitz-app/node_modules/react-query/dist/react-query.development.js:801:26
    at _catch$1 (/Users/errorname/Documents/Vrac/hello-prisma2/blitz-app/node_modules/react-query/dist/react-query.development.js:373:20)
    at /Users/errorname/Documents/Vrac/hello-prisma2/blitz-app/node_modules/react-query/dist/react-query.development.js:799:14
    at /Users/errorname/Documents/Vrac/hello-prisma2/blitz-app/node_modules/react-query/dist/react-query.development.js:402:34
    at /Users/errorname/Documents/Vrac/hello-prisma2/blitz-app/node_modules/react-query/dist/react-query.development.js:972:40
    at _catch$1 (/Users/errorname/Documents/Vrac/hello-prisma2/blitz-app/node_modules/react-query/dist/react-query.development.js:373:20)
    at /Users/errorname/Documents/Vrac/hello-prisma2/blitz-app/node_modules/react-query/dist/react-query.development.js:966:18
    at /Users/errorname/Documents/Vrac/hello-prisma2/blitz-app/node_modules/react-query/dist/react-query.development.js:402:34
    at Object.<anonymous> (/Users/errorname/Documents/Vrac/hello-prisma2/blitz-app/node_modules/react-query/dist/react-query.development.js:1003:11)
    at Object.fetch (/Users/errorname/Documents/Vrac/hello-prisma2/blitz-app/node_modules/react-query/dist/react-query.development.js:402:34)
    at handleSuspense (/Users/errorname/Documents/Vrac/hello-prisma2/blitz-app/node_modules/react-query/dist/react-query.development.js:1587:31)
    at Object.useQuery (/Users/errorname/Documents/Vrac/hello-prisma2/blitz-app/node_modules/react-query/dist/react-query.development.js:1840:5)
    at useQuery (/Users/errorname/Documents/Vrac/hello-prisma2/blitz-app/node_modules/@blitzjs/core/dist/core.cjs.development.js:130:35)
    at ProjectsList (webpack-internal:///./pages/projects/index.tsx:14:76)
(node:12661) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 7)

This error is thrown because Blitz first try to prefetch the response, but doesn't include the context:

https://github.com/blitz-js/blitz/blob/canary/packages/core/src/use-query.ts#L62

queryFn: (_: string, params) => queryRpcFn(params, {fromQueryHook: true})

The prefetching features comes from this issue and was implemented in this PR

Possible implementation(s)

I tried to look into Blitz code, but I haven't figured out a way to make this possible.

kinbug statudone

All 10 comments

Hey, that sounds awesome!

I can look more into this tomorrow, but the queryFn warm request is an empty HEAD request that doesn't actually call the query function. So that means if getProjects is running, then it's from the main request.

Thanks for your answer! I may be missing something, but when adding some logging:

app/projects/queries/getProjects.ts

export default async function getProjects(
  { where, orderBy, cursor, take, skip }: GetProjectsInput,
  ctx: Record<any, any> = {}
) {

  console.log(Object.keys(ctx)) // Prints the keys of the ctx argument

  const projects = await ctx.db.project.findMany({
    where,
    orderBy,
    cursor,
    take,
    skip,
  })

  return projects
}

Sometime I get ["db"] which looks like the actual request, but sometime I get ["fromQueryHook"] which, if I understand correctly, comes from the prefetching.

Hmm, that's odd! Can you share your code that has the useQuery hook?

useQuery should only ever run on the client, but here's it's running on the server apparently.

I used the generated code from blitz with the following steps:

blitz new context-issue
cd context-issue
blitz generate all project name:string
blitz db migrate

Then, add a console.log(ctx) in the queries/getProjects.ts file

Finally, run blitz start and go to http://localhost:3000/projects

You should now see { fromQueryHooks: true } in the logs

It looks like it's only at the start of blitz start, just after compiled successfully. Maybe the query is executed after the compilation ?

Ok thanks, looking into it right now

Sorry, I got pulled to a higher priority bug, but I should be able to get back to this tomorrow

@Errorname I have a fix this in #775, but in the meantime you can safely ignore the error. The error is from that code running during pre-rendering when it shouldn't. Doesn't affect runtime code.

Thank you for fixing this issue quickly 馃憤
If you are interested on the multi-tenancy with Blitz, I've added a small documentation on how to do it with prisma-multi-tenant 馃檪

@Errorname awesome, good work on that! :)

Was this page helpful?
0 / 5 - 0 ratings