Blitz is now in beta! 🎉 1.0 expected this April
Back to Documentation Menu

Server Utilities

Topics

Jump to a Topic

resolver.pipe

This is a functional utility that makes it easier and cleaner to write complex resolvers.

  • It reduces the need for explicit Typescript types
  • Validate input data with a zod schema with resolver.zod()
  • Authorize users with resolver.authorize()
  • Enables functional composition

Example

import {resolver} from "blitz"
import db from "db"
import * as z from "zod"

export const CreateProject = z.object({
  name: z.string(),
  dueDate: z.date().optional(),
  orgId: z.number().optional(),
})

export default resolver.pipe(
  resolver.zod(CreateProject),
  resolver.authorize(),
  // Set default orgId
  (input, {session}) => ({...input, orgId: input.orgId ?? session.orgId}),
  async (input, ctx) => {
    console.log("Creating project...", input.orgId)
    const project = await db.project.create({
      data: input,
    })
    console.log("Created project")
    return project
  },
)
info

The input type of the entire composed resolver function is determined by the input type of the first argument to pipe.

This means you will almost always want resolver.zod() to be the first in the pipe.

API

Arguments

It accepts from 1 to N functions which take input data as first argument and middleware ctx as the second argument.

The output of the first function is the first input argument of the next function. The output of the last function is the final resolver result data that will be sent to the client.

The Typescript types are automatically inferred from one function to the next.

// 1 function
const resolver = resolver.pipe((input: ResolverInput, ctx: Ctx) => ResolverOutput)
// 2 functions
const resolver = resolver.pipe(
  (input: ResolverInput, ctx: Ctx) => A),
  (input: A, ctx: Ctx) => ResolverOutput),
)
// 3 functions
const resolver = resolver.pipe(
  (input: ResolverInput, ctx: Ctx) => A),
  (input: A, ctx: Ctx) => B),
  (input: B, ctx: Ctx) => ResolverOutput),
)
// ... etc

Returns

This returns a composed function of type (input, ctx) => Promise<result> which is the standard resolver type.

resolver.zod

This is a resolver adapter for Zod, an awesome input validation library. It takes a zod schema and runs schema.parse on the input data.

Example

import {resolver} from 'blitz'
import * as z from "zod"

export const CreateProject = z.object({
  name: z.string(),
  dueDate: z.date().optional(),
  orgId: z.number().optional(),
})

export default resolver.pipe(
  resolver.zod(CreateProject), // highlight-line
  async (input, ctx) => {
    // stuff
  },
)

API

const pipeFn = resolver.zod(MyZodSchema)

Arguments

  • ZodSchema: a zod schema
    • Required

Returns

A function to give resolver.pipe of type (rawInput, ctx: Ctx) => validInput

resolver.authorize

Example

import {resolver} from 'blitz'

export default resolver.pipe(
resolver.authorize(), // resolver.authorize('admin'),
async (input, ctx) => { // stuff }, )

API

const pipeFn = resolver.authorize(...isAuthorizedArgs)

Arguments

Returns

A function to give resolver.pipe of type (input, ctx: Ctx) => input

paginate

This is a handy utility for query pagination

Example

import {paginate, Ctx} from "blitz"
import db, {Prisma} from "db"

interface GetProjectSInput
  extends Pick<
    Prisma.ProjectFindManyArgs,
    "where" | "orderBy" | "skip" | "take"
  > {}

export default async function getProjects(
  {where, orderBy, skip = 0, take = 100}: GetProjectsInput,
  ctx: Ctx,
) {
  ctx.session.$authorize()

  const {items: projects, hasMore, nextPage, count} = await paginate({
    count: () => db.project.count({where}),
    query: (paginateArgs) =>
      db.project.findMany({...paginateArgs, where, orderBy}),
    skip,
    take,
  })

  return {
    projects,
    nextPage,
    hasMore,
    count,
  }
}

API

const paginationData = await paginate(paginateArguments))

Arguments

  • count: () => Promise <number>
    • Required
    • A function that returns a promise which resolves to a number
  • query: (payload: { skip: number; take: number }) => Promise<T>
    • Required
    • A function that receives pagination payload and returns anything (type of return will be inherited by the pagination result).
  • skip: number
    • How many rows to skip
  • take: number
    • How many rows to take
  • maxTake: number
    • The maximum value allowed for take. It protects your DB when "take" is sent by the user.
    • Defaults to 250.

Returns

  • paginationData
    • items: T (Data resolver by the query function)
    • nextPage: { skip: number, take: number } | null (Next page pagination payload)
    • hasMore: boolean (True if there are more items to load.)
    • count: number (Total number of items. Resolved by the count function)

invokeWithMiddleware

This is for imperatively invoking queries/mutations on the server. It ensures appropriate middleware is run before/after your resolver.

Example

import {
  invokeWithMiddleware,
  GetServerSideProps,
  Link,
  BlitzPage,
  PromiseReturnType,
} from "blitz"
import getProducts from "app/products/queries/getProducts"

type PageProps = {
  products: PromiseReturnType<typeof getProducts>
}

export const getServerSideProps: GetServerSideProps<PageProps> = async ({
  req,
  res,
}) => {
  const products = await invokeWithMiddleware(
    getProducts,
    {orderBy: {id: "desc"}},
    {req, res},
  )

  return {
    props: {products},
  }
}

const Page: BlitzPage<PageProps> = function ({products}) {
  return (
    <div>
      <h1>Products</h1>
      <div id="products">
        {products.map((product) => (
          <p key={product.id}>
            <Link
              href="/products/[handle]"
              as={`/products/${product.handle}`}
            >
              <a>{product.name}</a>
            </Link>
          </p>
        ))}
      </div>
    </div>
  )
}
export default Page

API

const results = await invokeWithMiddleware(resolver, resolverInputArguments, {req, res}))

Arguments

  • resolver: A Blitz query resolver or mutation resolver
    • Required
  • resolverInputArguments
    • Required
    • The arguments that will be passed to resolver
  • Other
    • req
      • Required
      • The BlitzApiRequest object
    • res
      • Required
      • The BlitzApiResponse object
    • middleware
      • Optional
      • Array of middleware that will be ran in addition to global middleware and any local middleware defined on the query/mutation.

Returns

  • results
    • The exact results returned from the resolver

Idea for improving this page? Edit it on Github.