Skip to content

Commit

Permalink
feat: update trpc to v10 (@next) (#203)
Browse files Browse the repository at this point in the history
* feat: modify installer and bp

* feat: update frontend

* fix: update import

* fix: add protectedprocedure
  • Loading branch information
juliusmarminge authored Jul 16, 2022
1 parent cef7027 commit bc15ece
Show file tree
Hide file tree
Showing 21 changed files with 234 additions and 285 deletions.
33 changes: 21 additions & 12 deletions src/installers/trpc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ export const trpcInstaller: Installer = async ({
packages: [
"react-query",
"superjson",
"@trpc/server",
"@trpc/client",
"@trpc/next",
"@trpc/react",
"@trpc/server@experimental",
"@trpc/client@experimental",
"@trpc/next@experimental",
"@trpc/react@experimental",
],
devMode: false,
noInstallMode: noInstall,
Expand All @@ -35,6 +35,10 @@ export const trpcInstaller: Installer = async ({
const utilsSrc = path.join(trpcAssetDir, "utils.ts");
const utilsDest = path.join(projectDir, "src/utils/trpc.ts");

const serverUtilFile = usingAuth ? "auth-server-utils.ts" : "server-utils.ts";
const serverUtilSrc = path.join(trpcAssetDir, serverUtilFile);
const serverUtilDest = path.join(projectDir, "src/server/trpc/utils.ts");

const contextFile =
usingAuth && usingPrisma
? "auth-prisma-context.ts"
Expand All @@ -44,34 +48,39 @@ export const trpcInstaller: Installer = async ({
? "prisma-context.ts"
: "base-context.ts";
const contextSrc = path.join(trpcAssetDir, contextFile);
const contextDest = path.join(projectDir, "src/server/router/context.ts");
const contextDest = path.join(projectDir, "src/server/trpc/context.ts");

if (usingAuth) {
const authRouterSrc = path.join(trpcAssetDir, "auth-router.ts");
const authRouterDest = path.join(projectDir, "src/server/router/auth.ts");
await fs.copy(authRouterSrc, authRouterDest);
}
const authRouterSrc = path.join(trpcAssetDir, "auth-router.ts");
const authRouterDest = path.join(
projectDir,
"src/server/trpc/router/auth.ts",
);

const indexRouterFile = usingAuth
? "auth-index-router.ts"
: "index-router.ts";
const indexRouterSrc = path.join(trpcAssetDir, indexRouterFile);
const indexRouterDest = path.join(projectDir, "src/server/router/index.ts");
const indexRouterDest = path.join(
projectDir,
"src/server/trpc/router/index.ts",
);

const exampleRouterFile = usingPrisma
? "example-prisma-router.ts"
: "example-router.ts";
const exampleRouterSrc = path.join(trpcAssetDir, exampleRouterFile);
const exampleRouterDest = path.join(
projectDir,
"src/server/router/example.ts",
"src/server/trpc/router/example.ts",
);

await Promise.all([
fs.copy(apiHandlerSrc, apiHandlerDest),
fs.copy(utilsSrc, utilsDest),
fs.copy(serverUtilSrc, serverUtilDest),
fs.copy(contextSrc, contextDest),
fs.copy(indexRouterSrc, indexRouterDest),
fs.copy(exampleRouterSrc, exampleRouterDest),
...(usingAuth ? [fs.copy(authRouterSrc, authRouterDest)] : []),
]);
};
4 changes: 2 additions & 2 deletions template/addons/trpc/api-handler.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// src/pages/api/trpc/[trpc].ts
import { createNextApiHandler } from "@trpc/server/adapters/next";
import { appRouter } from "../../../server/router";
import { createContext } from "../../../server/router/context";
import { appRouter } from "../../../server/trpc/router";
import { createContext } from "../../../server/trpc/context";

// export API handler
export default createNextApiHandler({
Expand Down
16 changes: 4 additions & 12 deletions template/addons/trpc/auth-context.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,18 @@
// src/server/router/context.ts
// src/server/trpc/context.ts
import * as trpc from "@trpc/server";
import * as trpcNext from "@trpc/server/adapters/next";
import { unstable_getServerSession as getServerSession } from "next-auth";

import { authOptions as nextAuthOptions } from "../../pages/api/auth/[...nextauth]";

export const createContext = async (
opts?: trpcNext.CreateNextContextOptions,
opts: trpcNext.CreateNextContextOptions,
) => {
const req = opts?.req;
const res = opts?.res;

const session =
req && res && (await getServerSession(req, res, nextAuthOptions));
const session = await getServerSession(opts.req, opts.res, nextAuthOptions);

return {
req,
res,
session,
};
};

type Context = trpc.inferAsyncReturnType<typeof createContext>;

export const createRouter = () => trpc.router<Context>();
export type Context = trpc.inferAsyncReturnType<typeof createContext>;
14 changes: 6 additions & 8 deletions template/addons/trpc/auth-index-router.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
// src/server/router/index.ts
import { createRouter } from "./context";
import superjson from "superjson";

// src/server/trpc/router/index.ts
import { t } from "../utils";
import { exampleRouter } from "./example";
import { authRouter } from "./auth";

export const appRouter = createRouter()
.transformer(superjson)
.merge("example.", exampleRouter)
.merge("auth.", authRouter);
export const appRouter = t.router({
example: exampleRouter,
auth: authRouter,
});

// export type definition of API
export type AppRouter = typeof appRouter;
16 changes: 4 additions & 12 deletions template/addons/trpc/auth-prisma-context.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// src/server/router/context.ts
// src/server/trpc/context.ts
import * as trpc from "@trpc/server";
import * as trpcNext from "@trpc/server/adapters/next";
import { unstable_getServerSession as getServerSession } from "next-auth";
Expand All @@ -7,22 +7,14 @@ import { authOptions as nextAuthOptions } from "../../pages/api/auth/[...nextaut
import { prisma } from "../db/client";

export const createContext = async (
opts?: trpcNext.CreateNextContextOptions,
opts: trpcNext.CreateNextContextOptions,
) => {
const req = opts?.req;
const res = opts?.res;

const session =
req && res && (await getServerSession(req, res, nextAuthOptions));
const session = await getServerSession(opts.req, opts.res, nextAuthOptions);

return {
req,
res,
session,
prisma,
};
};

type Context = trpc.inferAsyncReturnType<typeof createContext>;

export const createRouter = () => trpc.router<Context>();
export type Context = trpc.inferAsyncReturnType<typeof createContext>;
30 changes: 9 additions & 21 deletions template/addons/trpc/auth-router.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,10 @@
import { TRPCError } from "@trpc/server";
import { createRouter } from "./context";
import { t, authedProcedure } from "../utils";

export const authRouter = createRouter()
.query("getSession", {
resolve({ ctx }) {
return ctx.session;
},
})
.middleware(async ({ ctx, next }) => {
// Any queries or mutations after this middleware will
// raise an error unless there is a current session
if (!ctx.session) {
throw new TRPCError({ code: "UNAUTHORIZED" });
}
return next();
})
.query("getSecretMessage", {
async resolve({ ctx }) {
return "You are logged in and can see this secret message!";
},
});
export const authRouter = t.router({
getSession: t.procedure.query(({ ctx }) => {
return ctx.session;
}),
getSecretMessage: authedProcedure.query(() => {
return "You are logged in and can see this secret message!";
}),
});
23 changes: 23 additions & 0 deletions template/addons/trpc/auth-server-utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { initTRPC, TRPCError } from "@trpc/server";
import type { Context } from "./context";
import superjson from "superjson";

export const t = initTRPC<{ ctx: Context }>()({
transformer: superjson,
errorFormatter({ shape }) {
return shape;
},
});

export const authedProcedure = t.procedure.use(({ ctx, next }) => {
if (!ctx.session || !ctx.session.user) {
throw new TRPCError({ code: "UNAUTHORIZED" });
}
return next({
ctx: {
...ctx,
// infers that `session` is non-nullable to downstream resolvers
session: { ...ctx.session, user: ctx.session.user },
},
});
});
14 changes: 3 additions & 11 deletions template/addons/trpc/base-context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,8 @@
import * as trpc from "@trpc/server";
import * as trpcNext from "@trpc/server/adapters/next";

export const createContext = (opts?: trpcNext.CreateNextContextOptions) => {
const req = opts?.req;
const res = opts?.res;

return {
req,
res,
};
export const createContext = (opts: trpcNext.CreateNextContextOptions) => {
return {};
};

type Context = trpc.inferAsyncReturnType<typeof createContext>;

export const createRouter = () => trpc.router<Context>();
export type Context = trpc.inferAsyncReturnType<typeof createContext>;
26 changes: 10 additions & 16 deletions template/addons/trpc/example-prisma-router.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,15 @@
import { createRouter } from "./context";
import { t } from "../utils";
import { z } from "zod";

export const exampleRouter = createRouter()
.query("hello", {
input: z
.object({
text: z.string().nullish(),
})
.nullish(),
resolve({ input }) {
export const exampleRouter = t.router({
hello: t.procedure
.input(z.object({ text: z.string().nullish() }).nullish())
.query(({ input }) => {
return {
greeting: `Hello ${input?.text ?? "world"}`,
};
},
})
.query("getAll", {
async resolve({ ctx }) {
return await ctx.prisma.example.findMany();
},
});
}),
getAll: t.procedure.query(({ ctx }) => {
return ctx.prisma.example.findMany();
}),
});
21 changes: 9 additions & 12 deletions template/addons/trpc/example-router.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
import { createRouter } from "./context";
import { t } from "../utils";
import { z } from "zod";

export const exampleRouter = createRouter().query("hello", {
input: z
.object({
text: z.string().nullish(),
})
.nullish(),
resolve({ input }) {
return {
greeting: `Hello ${input?.text ?? "world"}`,
};
},
export const exampleRouter = t.router({
hello: t.procedure
.input(z.object({ text: z.string().nullish() }).nullish())
.query(({ input }) => {
return {
greeting: `Hello ${input?.text ?? "world"}`,
};
}),
});
9 changes: 4 additions & 5 deletions template/addons/trpc/index-router.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
// src/server/router/index.ts
import { createRouter } from "./context";
import superjson from "superjson";
import { t } from "../utils";

import { exampleRouter } from "./example";

export const appRouter = createRouter()
.transformer(superjson)
.merge("example.", exampleRouter);
export const appRouter = t.router({
example: exampleRouter,
});

// export type definition of API
export type AppRouter = typeof appRouter;
11 changes: 2 additions & 9 deletions template/addons/trpc/prisma-context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,10 @@ import * as trpc from "@trpc/server";
import * as trpcNext from "@trpc/server/adapters/next";
import { prisma } from "../db/client";

export const createContext = (opts?: trpcNext.CreateNextContextOptions) => {
const req = opts?.req;
const res = opts?.res;

export const createContext = (opts: trpcNext.CreateNextContextOptions) => {
return {
req,
res,
prisma,
};
};

type Context = trpc.inferAsyncReturnType<typeof createContext>;

export const createRouter = () => trpc.router<Context>();
export type Context = trpc.inferAsyncReturnType<typeof createContext>;
10 changes: 10 additions & 0 deletions template/addons/trpc/server-utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { initTRPC } from "@trpc/server";
import type { Context } from "./context";
import superjson from "superjson";

export const t = initTRPC<{ ctx: Context }>()({
transformer: superjson,
errorFormatter({ shape }) {
return shape;
},
});
42 changes: 37 additions & 5 deletions template/addons/trpc/utils.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,42 @@
// src/utils/trpc.ts
import type { AppRouter } from "../server/router";
import { createReactQueryHooks } from "@trpc/react";
import { setupTRPC } from "@trpc/next";
import type { inferProcedureInput, inferProcedureOutput } from "@trpc/server";
import type { AppRouter } from "../server/trpc/router";
import superjson from "superjson";

export const trpc = createReactQueryHooks<AppRouter>();
const getBaseUrl = () => {
if (typeof window !== "undefined") return ""; // browser should use relative url
if (process.env.VERCEL_URL) return `https://${process.env.VERCEL_URL}`; // SSR should use vercel url

return `http://localhost:${process.env.PORT ?? 3000}`; // dev SSR should use localhost
};

export const trpc = setupTRPC<AppRouter>({
config() {
return {
url: `${getBaseUrl()}/api/trpc`,
transformer: superjson,
};
},
ssr: false,
});

/**
* Check out tRPC docs for Inference Helpers
* https://trpc.io/docs/infer-types#inference-helpers
* This is a helper method to infer the output of a query resolver
* @example type HelloOutput = inferQueryOutput<'hello'>
*/
export type inferQueryOutput<
TRouteKey extends keyof AppRouter["_def"]["queries"],
> = inferProcedureOutput<AppRouter["_def"]["queries"][TRouteKey]>;

export type inferQueryInput<
TRouteKey extends keyof AppRouter["_def"]["queries"],
> = inferProcedureInput<AppRouter["_def"]["queries"][TRouteKey]>;

export type inferMutationOutput<
TRouteKey extends keyof AppRouter["_def"]["mutations"],
> = inferProcedureOutput<AppRouter["_def"]["mutations"][TRouteKey]>;

export type inferMutationInput<
TRouteKey extends keyof AppRouter["_def"]["mutations"],
> = inferProcedureInput<AppRouter["_def"]["mutations"][TRouteKey]>;
Loading

0 comments on commit bc15ece

Please sign in to comment.