Skip to content

Commit

Permalink
fix: sitemap.xml should fetch directly (#939)
Browse files Browse the repository at this point in the history
abvthecity authored May 29, 2024
1 parent 76db63c commit dab9748
Showing 6 changed files with 69 additions and 67 deletions.
2 changes: 2 additions & 0 deletions packages/ui/docs-bundle/next.config.js
Original file line number Diff line number Diff line change
@@ -45,6 +45,8 @@ const nextConfig = {
*/
{ source: "/:prefix*/_next/:path*", destination: "/_next/:path*" },
{ source: "/:prefix*/api/fern-docs/:path*", destination: "/api/fern-docs/:path*" },
{ source: "/:prefix*/robots.txt", destination: "/api/fern-docs/robots.txt" },
{ source: "/:prefix*/sitemap.xml", destination: "/api/fern-docs/sitemap.xml" },
/**
* Since we use cookie rewrites to determine if the path should be rewritten to /static or /dynamic, prefetch requests
* do not have access to these cookies, and will always be matched to /static. This rewrite rule will ensure that
17 changes: 3 additions & 14 deletions packages/ui/docs-bundle/src/pages/api/fern-docs/resolve-api.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { buildUrl, resolveSidebarNodesRoot, visitSidebarNodeRaw } from "@fern-ui/fdr-utils";
import { resolveSidebarNodesRoot, visitSidebarNodeRaw } from "@fern-ui/fdr-utils";
import { ApiDefinitionResolver, REGISTRY_SERVICE, type ResolvedRootPackage } from "@fern-ui/ui";
import { NextApiHandler, NextApiResponse } from "next";
import { toValidPathname } from "../../../utils/toValidPathname";
import { buildUrlFromApiNode } from "../../../utils/buildUrlFromApi";
import { getXFernHostNode } from "../../../utils/xFernHost";
import { getFeatureFlags } from "./feature-flags";

@@ -20,18 +20,7 @@ const resolveApiHandler: NextApiHandler = async (
const xFernHost = getXFernHostNode(req);
res.setHeader("host", xFernHost);

const fullUrl = req.url;

if (fullUrl == null) {
res.status(400).json(null);
return;
}

const maybePathName = fullUrl.split("/api/fern-docs/resolve-api")[0] ?? "";
const url = buildUrl({
host: xFernHost,
pathname: toValidPathname(maybePathName),
});
const url = buildUrlFromApiNode(xFernHost, req);
// eslint-disable-next-line no-console
console.log("[resolve-api] Loading docs for", url);
const docsResponse = await REGISTRY_SERVICE.docs.v2.read.getDocsForUrl({
41 changes: 16 additions & 25 deletions packages/ui/docs-bundle/src/pages/api/fern-docs/sitemap.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { buildUrl, getAllUrlsFromDocsConfig } from "@fern-ui/fdr-utils";
import { getAllUrlsFromDocsConfig } from "@fern-ui/fdr-utils";
import { NextRequest, NextResponse } from "next/server";
import { buildUrlFromApiEdge } from "../../../utils/buildUrlFromApi";
import { loadWithUrl } from "../../../utils/loadWithUrl";
import { jsonResponse } from "../../../utils/serverResponse";
import { toValidPathname } from "../../../utils/toValidPathname";
import { getXFernHostEdge } from "../../../utils/xFernHost";

export const runtime = "edge";
@@ -13,31 +13,22 @@ export default async function GET(req: NextRequest): Promise<NextResponse> {
}

const xFernHost = getXFernHostEdge(req);
const headers: Record<string, string> = {
"x-fern-host": xFernHost,
};
const headers = new Headers();
headers.set("x-fern-host", xFernHost);

try {
const url = buildUrl({ host: xFernHost, pathname: toValidPathname(req.nextUrl.searchParams.get("basePath")) });
// eslint-disable-next-line no-console
console.log("[sitemap] Loading docs for", url);
const docs = await loadWithUrl(url);
const url = buildUrlFromApiEdge(xFernHost, req);
const docs = await loadWithUrl(url);

if (docs == null) {
return jsonResponse(404, [], headers);
}
if (docs == null) {
return jsonResponse(404, [], { headers });
}

const urls = getAllUrlsFromDocsConfig(
xFernHost,
docs.baseUrl.basePath,
docs.definition.config.navigation,
docs.definition.apis,
);
const urls = getAllUrlsFromDocsConfig(
xFernHost,
docs.baseUrl.basePath,
docs.definition.config.navigation,
docs.definition.apis,
);

return jsonResponse(200, urls, headers);
} catch (err) {
// eslint-disable-next-line no-console
console.error(err);
return jsonResponse(500, [], headers);
}
return jsonResponse(200, urls, { headers });
}
42 changes: 22 additions & 20 deletions packages/ui/docs-bundle/src/pages/api/fern-docs/sitemap.xml.ts
Original file line number Diff line number Diff line change
@@ -1,38 +1,40 @@
import { getAllUrlsFromDocsConfig } from "@fern-ui/fdr-utils";
import { NextRequest, NextResponse } from "next/server";
import { notFoundResponse } from "../../../utils/serverResponse";
import { buildUrlFromApiEdge } from "../../../utils/buildUrlFromApi";
import { loadWithUrl } from "../../../utils/loadWithUrl";
import { getXFernHostEdge } from "../../../utils/xFernHost";

export const runtime = "edge";
export const revalidate = 60 * 60 * 24;

export default async function GET(req: NextRequest): Promise<NextResponse> {
const xFernHost = getXFernHostEdge(req);

const hostWithoutTrailingSlash = xFernHost.endsWith("/") ? xFernHost.slice(0, -1) : xFernHost;
if (req.method !== "GET") {
return new NextResponse(null, { status: 405 });
}

const hostnameAndProtocol = req.nextUrl.host.includes("localhost")
? "http://localhost:3000"
: `https://${hostWithoutTrailingSlash}`;
const xFernHost = getXFernHostEdge(req);
const headers = new Headers();
headers.set("x-fern-host", xFernHost);

const sitemapResponse = await fetch(`${hostnameAndProtocol}/api/fern-docs/sitemap`, {
headers: { "x-fern-host": xFernHost },
});
const url = buildUrlFromApiEdge(xFernHost, req);
const docs = await loadWithUrl(url);

if (sitemapResponse.status !== 200) {
// eslint-disable-next-line no-console
console.error("Failed to fetch docs", sitemapResponse.status, sitemapResponse.statusText);
return notFoundResponse();
if (docs == null) {
return new NextResponse(null, { status: 404 });
}

const urls: string[] = await sitemapResponse.json();
const urls = getAllUrlsFromDocsConfig(
xFernHost,
docs.baseUrl.basePath,
docs.definition.config.navigation,
docs.definition.apis,
);

const sitemap = getSitemapXml(urls.map((url) => `https://${url}`));

return new NextResponse(sitemap, {
headers: {
"Content-Type": "text/xml",
},
});
headers.set("Content-Type", "text/xml");

return new NextResponse(sitemap, { headers });
}

function getSitemapXml(urls: string[]): string {
20 changes: 20 additions & 0 deletions packages/ui/docs-bundle/src/utils/buildUrlFromApi.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { buildUrl } from "@fern-ui/fdr-utils";
import type { NextRequest } from "next/server";
import type { NextApiRequest } from "next/types";
import { toValidPathname } from "./toValidPathname";

export function buildUrlFromApiEdge(xFernHost: string, req: NextRequest): string {
const maybePathName = req.nextUrl.pathname.split("/api/fern-docs")[0] ?? "";
return buildUrl({
host: xFernHost,
pathname: toValidPathname(maybePathName),
});
}

export function buildUrlFromApiNode(xFernHost: string, req: NextApiRequest): string {
const maybePathName = req.url?.split("/api/fern-docs")[0] ?? "";
return buildUrl({
host: xFernHost,
pathname: toValidPathname(maybePathName),
});
}
14 changes: 6 additions & 8 deletions packages/ui/docs-bundle/src/utils/serverResponse.ts
Original file line number Diff line number Diff line change
@@ -4,24 +4,22 @@ import { NextResponse } from "next/server";
* Returns a Response object with a JSON body
*/
export function jsonResponse<Data = unknown>(status: number, data: Data, init?: ResponseInit): NextResponse<string> {
const headers = new Headers(init?.headers);
headers.set("Content-Type", "application/json");
return new NextResponse(JSON.stringify(data), {
...init,
status,
headers: {
...init?.headers,
"Content-Type": "application/json",
},
headers,
});
}

export function redirectResponse(location: string, init?: ResponseInit): NextResponse {
const headers = new Headers(init?.headers);
headers.set("Location", location);
return new NextResponse(undefined, {
...init,
status: 302,
headers: {
...init?.headers,
Location: location,
},
headers,
});
}

0 comments on commit dab9748

Please sign in to comment.