Apollo server in Next.js API route

Dead-simple Apollo server using Next.js

API route

// /api/graphql.ts
import {ApolloServer} from 'apollo-server-micro';
import {getSession} from 'next-auth/client';

import {schema} from '@/backend/graphql/schema';
import prisma from '@/utils/prisma';

const apolloServer = new ApolloServer({
  schema,
  context: async ({req}) => {
    const session = await getSession({req});

    const userEmail = session?.user?.email;

    // Throw if invalid
    if (!userEmail) {
      throw new Error('Not authenticated');
    }

    return {prisma, currentUserEmail: userEmail};
  },
  tracing: process.env.NODE_ENV === 'development',
});

export const config = {
  api: {bodyParser: false},
};

export default apolloServer.createHandler({
  path: '/api/graphql',
});

Schema

// context
import {PrismaClient} from '@prisma/client';

export type Context = {prisma: PrismaClient; currentUserEmail: string};
// schema
import {GraphQLDateTime} from 'graphql-iso-date';
import {
  asNexusMethod,
  list,
  makeSchema,
  nonNull,
  nullable,
  objectType,
  queryType,
} from 'nexus';

export const DateTime = asNexusMethod(GraphQLDateTime, 'date');

const User = objectType({
  name: 'User',
  definition(t) {
    t.nonNull.int('id');
    t.string('name');
    t.nonNull.string('email');
    t.field('emailVerified', {type: DateTime});
    t.field('createdAt', {type: nonNull(DateTime)});
    t.field('updatedAt', {type: nonNull(DateTime)});
    t.field('membership', {
      type: Membership,
      resolve: (parent, _, ctx) => {
        return ctx.prisma.user
          .findUnique({where: {id: parent.id}})
          .membership();
      },
    });
  },
});

const Membership = objectType({
  name: 'Membership',
  definition(t) {
    t.nonNull.int('id');
    t.nonNull.int('userId');
    t.field('user', {
      type: nonNull(User),
      resolve: (parent, _, ctx) => {
        return ctx.prisma.membership
          .findUnique({where: {id: parent.id}})
          .user();
      },
    });
    t.nonNull.int('orgId');
    t.field('org', {
      type: nonNull(Org),
      resolve: (parent, _, ctx) => {
        return ctx.prisma.membership.findUnique({where: {id: parent.id}}).org();
      },
    });
    t.nonNull.string('roleName');
    t.field('role', {
      type: nonNull(Role),
      resolve: (parent, _, ctx) => {
        return ctx.prisma.membership
          .findUnique({where: {id: parent.id}})
          .role();
      },
    });
  },
});

// ... more fields

const Query = objectType({
  name: 'Query',
  definition(t) {
    t.field('currentUser', {
      type: User,
      resolve: (root, args, ctx) => {
        return ctx.prisma.user.findUnique({
          where: {email: ctx.currentUserEmail},
        });
      },
    });
  },
});

export const schema = makeSchema({
  types: [User, Membership, Query, DateTime],
});