Skip to content

Commit

Permalink
fix: async/await in getLatest procedure, reduce dev delay and add f…
Browse files Browse the repository at this point in the history
…uzz (#1950)
  • Loading branch information
juliusmarminge authored Jul 22, 2024
1 parent 831dd56 commit 2e3d02e
Show file tree
Hide file tree
Showing 14 changed files with 265 additions and 80 deletions.
26 changes: 17 additions & 9 deletions cli/template/extras/src/server/api/routers/post/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,17 @@ import { z } from "zod";

import { createTRPCRouter, publicProcedure } from "~/server/api/trpc";

let post = {
id: 1,
name: "Hello World",
};
// Mocked DB
interface Post {
id: number;
name: string;
}
const posts: Post[] = [
{
id: 1,
name: "Hello World",
},
];

export const postRouter = createTRPCRouter({
hello: publicProcedure
Expand All @@ -19,14 +26,15 @@ export const postRouter = createTRPCRouter({
create: publicProcedure
.input(z.object({ name: z.string().min(1) }))
.mutation(async ({ input }) => {
// simulate a slow db call
await new Promise((resolve) => setTimeout(resolve, 1000));

post = { id: post.id + 1, name: input.name };
const post: Post = {
id: posts.length + 1,
name: input.name,
};
posts.push(post);
return post;
}),

getLatest: publicProcedure.query(() => {
return post;
return posts.at(-1) ?? null;
}),
});
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,14 @@ export const postRouter = createTRPCRouter({
create: protectedProcedure
.input(z.object({ name: z.string().min(1) }))
.mutation(async ({ ctx, input }) => {
// simulate a slow db call
await new Promise((resolve) => setTimeout(resolve, 1000));

await ctx.db.insert(posts).values({
name: input.name,
createdById: ctx.session.user.id,
});
}),

getLatest: publicProcedure.query(({ ctx }) => {
const post = ctx.db.query.posts.findFirst({
getLatest: publicProcedure.query(async ({ ctx }) => {
const post = await ctx.db.query.posts.findFirst({
orderBy: (posts, { desc }) => [desc(posts.createdAt)],
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,6 @@ export const postRouter = createTRPCRouter({
create: protectedProcedure
.input(z.object({ name: z.string().min(1) }))
.mutation(async ({ ctx, input }) => {
// simulate a slow db call
await new Promise((resolve) => setTimeout(resolve, 1000));

return ctx.db.post.create({
data: {
name: input.name,
Expand All @@ -29,8 +26,8 @@ export const postRouter = createTRPCRouter({
});
}),

getLatest: protectedProcedure.query(({ ctx }) => {
const post = ctx.db.post.findFirst({
getLatest: protectedProcedure.query(async ({ ctx }) => {
const post = await ctx.db.post.findFirst({
orderBy: { createdAt: "desc" },
where: { createdBy: { id: ctx.session.user.id } },
});
Expand Down
3 changes: 0 additions & 3 deletions cli/template/extras/src/server/api/routers/post/with-auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,6 @@ export const postRouter = createTRPCRouter({
create: protectedProcedure
.input(z.object({ name: z.string().min(1) }))
.mutation(async ({ input }) => {
// simulate a slow db call
await new Promise((resolve) => setTimeout(resolve, 1000));

post = { id: post.id + 1, name: input.name };
return post;
}),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,13 @@ export const postRouter = createTRPCRouter({
create: publicProcedure
.input(z.object({ name: z.string().min(1) }))
.mutation(async ({ ctx, input }) => {
// simulate a slow db call
await new Promise((resolve) => setTimeout(resolve, 1000));

await ctx.db.insert(posts).values({
name: input.name,
});
}),

getLatest: publicProcedure.query(({ ctx }) => {
const post = ctx.db.query.posts.findFirst({
getLatest: publicProcedure.query(async ({ ctx }) => {
const post = await ctx.db.query.posts.findFirst({
orderBy: (posts, { desc }) => [desc(posts.createdAt)],
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,15 @@ export const postRouter = createTRPCRouter({
create: publicProcedure
.input(z.object({ name: z.string().min(1) }))
.mutation(async ({ ctx, input }) => {
// simulate a slow db call
await new Promise((resolve) => setTimeout(resolve, 1000));

return ctx.db.post.create({
data: {
name: input.name,
},
});
}),

getLatest: publicProcedure.query(({ ctx }) => {
const post = ctx.db.post.findFirst({
getLatest: publicProcedure.query(async ({ ctx }) => {
const post = await ctx.db.post.findFirst({
orderBy: { createdAt: "desc" },
});

Expand Down
25 changes: 24 additions & 1 deletion cli/template/extras/src/server/api/trpc-app/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,11 +70,34 @@ export const createCallerFactory = t.createCallerFactory;
*/
export const createTRPCRouter = t.router;

/**
* Middleware for timing procedure execution and adding an articifial delay in development.
*
* You can remove this if you don't like it, but it can help catch unwanted waterfalls by simulating
* network latency that would occur in production but not in local development.
*/
const timingMiddleware = t.middleware(async ({ next, path }) => {
const start = Date.now();

if (t._config.isDev) {
// artificial delay in dev
const waitMs = Math.floor(Math.random() * 400) + 100;
await new Promise((resolve) => setTimeout(resolve, waitMs));
}

const result = await next();

const end = Date.now();
console.log(`[TRPC] ${path} took ${end - start}ms to execute`);

return result;
});

/**
* Public (unauthenticated) procedure
*
* This is the base piece you use to build new queries and mutations on your tRPC API. It does not
* guarantee that a user querying is authorized, but you can still access user session data if they
* are logged in.
*/
export const publicProcedure = t.procedure;
export const publicProcedure = t.procedure.use(timingMiddleware);
47 changes: 36 additions & 11 deletions cli/template/extras/src/server/api/trpc-app/with-auth-db.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,14 +78,37 @@ export const createCallerFactory = t.createCallerFactory;
*/
export const createTRPCRouter = t.router;

/**
* Middleware for timing procedure execution and adding an articifial delay in development.
*
* You can remove this if you don't like it, but it can help catch unwanted waterfalls by simulating
* network latency that would occur in production but not in local development.
*/
const timingMiddleware = t.middleware(async ({ next, path }) => {
const start = Date.now();

if (t._config.isDev) {
// artificial delay in dev
const waitMs = Math.floor(Math.random() * 400) + 100;
await new Promise((resolve) => setTimeout(resolve, waitMs));
}

const result = await next();

const end = Date.now();
console.log(`[TRPC] ${path} took ${end - start}ms to execute`);

return result;
});

/**
* Public (unauthenticated) procedure
*
* This is the base piece you use to build new queries and mutations on your tRPC API. It does not
* guarantee that a user querying is authorized, but you can still access user session data if they
* are logged in.
*/
export const publicProcedure = t.procedure;
export const publicProcedure = t.procedure.use(timingMiddleware);

/**
* Protected (authenticated) procedure
Expand All @@ -95,14 +118,16 @@ export const publicProcedure = t.procedure;
*
* @see https://trpc.io/docs/procedures
*/
export const protectedProcedure = t.procedure.use(({ ctx, next }) => {
if (!ctx.session || !ctx.session.user) {
throw new TRPCError({ code: "UNAUTHORIZED" });
}
return next({
ctx: {
// infers the `session` as non-nullable
session: { ...ctx.session, user: ctx.session.user },
},
export const protectedProcedure = t.procedure
.use(timingMiddleware)
.use(({ ctx, next }) => {
if (!ctx.session || !ctx.session.user) {
throw new TRPCError({ code: "UNAUTHORIZED" });
}
return next({
ctx: {
// infers the `session` as non-nullable
session: { ...ctx.session, user: ctx.session.user },
},
});
});
});
47 changes: 36 additions & 11 deletions cli/template/extras/src/server/api/trpc-app/with-auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,14 +75,37 @@ export const createCallerFactory = t.createCallerFactory;
*/
export const createTRPCRouter = t.router;

/**
* Middleware for timing procedure execution and adding an articifial delay in development.
*
* You can remove this if you don't like it, but it can help catch unwanted waterfalls by simulating
* network latency that would occur in production but not in local development.
*/
const timingMiddleware = t.middleware(async ({ next, path }) => {
const start = Date.now();

if (t._config.isDev) {
// artificial delay in dev
const waitMs = Math.floor(Math.random() * 400) + 100;
await new Promise((resolve) => setTimeout(resolve, waitMs));
}

const result = await next();

const end = Date.now();
console.log(`[TRPC] ${path} took ${end - start}ms to execute`);

return result;
});

/**
* Public (unauthenticated) procedure
*
* This is the base piece you use to build new queries and mutations on your tRPC API. It does not
* guarantee that a user querying is authorized, but you can still access user session data if they
* are logged in.
*/
export const publicProcedure = t.procedure;
export const publicProcedure = t.procedure.use(timingMiddleware);

/**
* Protected (authenticated) procedure
Expand All @@ -92,14 +115,16 @@ export const publicProcedure = t.procedure;
*
* @see https://trpc.io/docs/procedures
*/
export const protectedProcedure = t.procedure.use(({ ctx, next }) => {
if (!ctx.session || !ctx.session.user) {
throw new TRPCError({ code: "UNAUTHORIZED" });
}
return next({
ctx: {
// infers the `session` as non-nullable
session: { ...ctx.session, user: ctx.session.user },
},
export const protectedProcedure = t.procedure
.use(timingMiddleware)
.use(({ ctx, next }) => {
if (!ctx.session || !ctx.session.user) {
throw new TRPCError({ code: "UNAUTHORIZED" });
}
return next({
ctx: {
// infers the `session` as non-nullable
session: { ...ctx.session, user: ctx.session.user },
},
});
});
});
25 changes: 24 additions & 1 deletion cli/template/extras/src/server/api/trpc-app/with-db.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,11 +73,34 @@ export const createCallerFactory = t.createCallerFactory;
*/
export const createTRPCRouter = t.router;

/**
* Middleware for timing procedure execution and adding an articifial delay in development.
*
* You can remove this if you don't like it, but it can help catch unwanted waterfalls by simulating
* network latency that would occur in production but not in local development.
*/
const timingMiddleware = t.middleware(async ({ next, path }) => {
const start = Date.now();

if (t._config.isDev) {
// artificial delay in dev
const waitMs = Math.floor(Math.random() * 400) + 100;
await new Promise((resolve) => setTimeout(resolve, waitMs));
}

const result = await next();

const end = Date.now();
console.log(`[TRPC] ${path} took ${end - start}ms to execute`);

return result;
});

/**
* Public (unauthenticated) procedure
*
* This is the base piece you use to build new queries and mutations on your tRPC API. It does not
* guarantee that a user querying is authorized, but you can still access user session data if they
* are logged in.
*/
export const publicProcedure = t.procedure;
export const publicProcedure = t.procedure.use(timingMiddleware);
25 changes: 24 additions & 1 deletion cli/template/extras/src/server/api/trpc-pages/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,11 +89,34 @@ export const createCallerFactory = t.createCallerFactory;
*/
export const createTRPCRouter = t.router;

/**
* Middleware for timing procedure execution and adding an articifial delay in development.
*
* You can remove this if you don't like it, but it can help catch unwanted waterfalls by simulating
* network latency that would occur in production but not in local development.
*/
const timingMiddleware = t.middleware(async ({ next, path }) => {
const start = Date.now();

if (t._config.isDev) {
// artificial delay in dev
const waitMs = Math.floor(Math.random() * 400) + 100;
await new Promise((resolve) => setTimeout(resolve, waitMs));
}

const result = await next();

const end = Date.now();
console.log(`[TRPC] ${path} took ${end - start}ms to execute`);

return result;
});

/**
* Public (unauthenticated) procedure
*
* This is the base piece you use to build new queries and mutations on your tRPC API. It does not
* guarantee that a user querying is authorized, but you can still access user session data if they
* are logged in.
*/
export const publicProcedure = t.procedure;
export const publicProcedure = t.procedure.use(timingMiddleware);
Loading

0 comments on commit 2e3d02e

Please sign in to comment.