Skip to content

Commit 24c13cc

Browse files
author
Rajat Saxena
committed
perf: optimize GraphQL route and add domain caching
- Wrap data-fetching functions (getPage, getSiteInfo, getFullSiteSetup) with React.cache() to deduplicate SSR calls - Add in-memory domain cache with 60s TTL (domain-cache.ts) - Use getCachedDomain in verify-domain route and GraphQL route handler - Parallelize domain lookup, session check, and body parsing with Promise.all in GraphQL route - Store plain objects in domain cache, hydrate fresh Mongoose docs per request to prevent cross-request mutation
1 parent 2af4a53 commit 24c13cc

File tree

4 files changed

+38
-30
lines changed

4 files changed

+38
-30
lines changed

apps/web/app/api/graph/route.ts

Lines changed: 11 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@ import schema from "@/graphql";
33
import { graphql } from "graphql";
44
import { getAddress } from "@/lib/utils";
55
import User from "@models/User";
6-
import DomainModel, { Domain } from "@models/Domain";
76
import { auth } from "@/auth";
87
import { als } from "@/async-local-storage";
8+
import { getCachedDomain } from "@/lib/domain-cache";
99

1010
async function updateLastActive(user: any) {
1111
const dateNow = new Date();
@@ -20,26 +20,25 @@ async function updateLastActive(user: any) {
2020
}
2121

2222
export async function POST(req: NextRequest) {
23-
const domain = await DomainModel.findOne<Domain>({
24-
name: req.headers.get("domain"),
25-
});
23+
const [domain, session, body] = await Promise.all([
24+
getCachedDomain(req.headers.get("domain")!),
25+
auth.api.getSession({ headers: req.headers }),
26+
req.json(),
27+
]);
28+
2629
if (!domain) {
2730
return Response.json({ message: "Domain not found" }, { status: 404 });
2831
}
2932

33+
if (!body.hasOwnProperty("query")) {
34+
return Response.json({ error: "Query is missing" }, { status: 400 });
35+
}
36+
3037
const map = new Map();
3138
map.set("domain", req.headers.get("domain"));
3239
map.set("domainId", req.headers.get("domainId"));
3340
als.enterWith(map);
3441

35-
const session = await auth.api.getSession({
36-
headers: req.headers,
37-
});
38-
const body = await req.json();
39-
if (!body.hasOwnProperty("query")) {
40-
return Response.json({ error: "Query is missing" }, { status: 400 });
41-
}
42-
4342
let user;
4443
if (session) {
4544
user = await User.findOne({
@@ -53,11 +52,6 @@ export async function POST(req: NextRequest) {
5352
}
5453
}
5554

56-
// const body = await req.json();
57-
// if (!body.hasOwnProperty("query")) {
58-
// return Response.json({ error: "Query is missing" }, { status: 400 });
59-
// }
60-
6155
let query, variables;
6256
if (typeof body.query === "string") {
6357
query = body.query;

apps/web/graphql/pages/logic.ts

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { responses } from "../../config/strings";
2+
import DomainModel from "@models/Domain";
23
import { checkIfAuthenticated } from "../../lib/graphql";
34
import GQLContext from "../../models/GQLContext";
45
import PageModel, { Page } from "../../models/Page";
@@ -280,15 +281,19 @@ export const publish = async (
280281
}
281282
page.socialImage = page.draftSocialImage;
282283

283-
ctx.subdomain.typefaces = ctx.subdomain.draftTypefaces;
284-
ctx.subdomain.sharedWidgets = ctx.subdomain.draftSharedWidgets;
285-
// ctx.subdomain.draftSharedWidgets = {};
286-
287284
if (ctx.subdomain.themeId) {
288285
await publishTheme(ctx.subdomain.themeId, ctx);
289286
}
290287

291-
await (ctx.subdomain as any).save();
288+
await DomainModel.findOneAndUpdate(
289+
{ _id: ctx.subdomain._id },
290+
{
291+
$set: {
292+
typefaces: ctx.subdomain.draftTypefaces,
293+
sharedWidgets: ctx.subdomain.draftSharedWidgets,
294+
},
295+
},
296+
);
292297
for (const mediaId of mediaToDelete) {
293298
await deleteMedia(mediaId);
294299
}

apps/web/graphql/themes/logic.ts

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { checkIfAuthenticated } from "../../lib/graphql";
2+
import DomainModel from "@models/Domain";
23
import { responses } from "../../config/strings";
34
import constants from "../../config/constants";
45
import GQLContext from "../../models/GQLContext";
@@ -140,8 +141,10 @@ export const updateDraftTheme = async (
140141
}
141142

142143
await theme.save();
143-
ctx.subdomain.lastEditedThemeId = theme.themeId;
144-
await (ctx.subdomain as any).save();
144+
await DomainModel.findOneAndUpdate(
145+
{ _id: ctx.subdomain._id },
146+
{ $set: { lastEditedThemeId: theme.themeId } },
147+
);
145148

146149
return formatTheme(theme);
147150
};
@@ -216,9 +219,10 @@ export const switchTheme = async (themeId: string, ctx: GQLContext) => {
216219
theme = await publishTheme(themeId, ctx);
217220
}
218221

219-
ctx.subdomain.themeId = themeId;
220-
ctx.subdomain.lastEditedThemeId = themeId;
221-
await (ctx.subdomain as any).save();
222+
await DomainModel.findOneAndUpdate(
223+
{ _id: ctx.subdomain._id },
224+
{ $set: { themeId, lastEditedThemeId: themeId } },
225+
);
222226

223227
return formatTheme(theme);
224228
};

apps/web/lib/domain-cache.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import DomainModel, { Domain } from "../models/Domain";
22

33
const domainCache = new Map<
44
string,
5-
{ data: Domain | null; expiresAt: number }
5+
{ data: Record<string, any>; expiresAt: number }
66
>();
77
const TTL = 60_000; // 60 seconds
88

@@ -35,11 +35,16 @@ export async function getCachedDomain(
3535
): Promise<Domain | null> {
3636
const cached = domainCache.get(hostName);
3737
if (cached && cached.expiresAt > Date.now()) {
38-
return cached.data;
38+
return DomainModel.hydrate(cached.data) as unknown as Domain;
3939
}
4040

4141
const domain = await getDomain(hostName);
42-
domainCache.set(hostName, { data: domain, expiresAt: Date.now() + TTL });
42+
if (domain) {
43+
domainCache.set(hostName, {
44+
data: (domain as any).toObject(),
45+
expiresAt: Date.now() + TTL,
46+
});
47+
}
4348
return domain;
4449
}
4550

0 commit comments

Comments
 (0)