Manual Setup
Adding Fumastudio to existing Nextjs project.
Getting started
Install the necessary dependencies, asssuming you are using Shadcn with Nextjs.
npm i @trythis/js-schema @trythis/nextjsLoader configuration
The loader function reads the Bruno collection converting each request to appropriate documentation.
import { httpCodes } from "@/lib/http-codes";
import { loader, snippet, toBrunoDocs } from "@trythis/nextjs";
import { join } from "node:path";
const cwd = process.cwd();
const docsDir = join(cwd, "collections");
export const source = loader({
baseURL: "/api-reference",
source: await toBrunoDocs({ cwd: docsDir }),
languages: [
snippet.curl({ target: "shell", syntax: "bash", label: "cURL" }),
snippet.axios({ target: "node", syntax: "typescript" }),
snippet.fetch({ target: "node", syntax: "typescript" }),
],
variables: {
// your variables go here (it respects the same hierarchy as the Bruno Desktop/CLI app)
},
httpCodes,
});Server-only
This file is supposed to run on the server, so do not place client code in here.
MDX components
Configure the MDX components which would render the Bruno collection requests. At the root of your Nextjs project.
import { APIPage } from "@/components/fumastudio/api-page";
import * as AllLucideIcons from "lucide-react";
type MDXComponents = any;
export const useIcons = (): any => {
return AllLucideIcons;
};
const components: MDXComponents = {
ApiPage: APIPage,
};
// Override or add your mdx components here
export function useMDXComponents(
defaultComponents?: MDXComponents,
): MDXComponents {
return {
...defaultComponents,
...components,
};
}API Page configuration
Assuming your docs are accessible at /api-reference, in your nextjs app router.
Create a corresponding page.tsx file.
import { ConfigProvider } from "@/components/fumastudio/config-provider";
import { PageTree } from "@/components/fumastudio/page-tree";
import { SearchDialog } from "@/components/fumastudio/search-dialog";
import { ThemeSelector } from "@/components/fumastudio/theme-selector";
import { Separator } from "@/components/ui/separator";
import {
SidebarInset,
SidebarProvider,
SidebarTrigger,
} from "@/components/ui/sidebar";
import { source } from "@/lib/source";
import { useMDXComponents } from "@/mdx-components";
import { config } from "@/source.config";
import { notFound } from "next/navigation";
type PageParams = { slug: string[] };
type PageProps = {
params: Promise<PageParams>;
};
export default async function Page(props: PageProps) {
const params = await props.params;
const request = source.request(params.slug);
if (!request) {
return notFound();
}
const pageTree = source.getPageTree();
const schemes = await source.getSchemes(params.slug);
const MDX = await source.getPage(params.slug, {
schemes,
components: useMDXComponents(),
});
if (!MDX) {
return notFound();
}
return (
<SidebarProvider>
<PageTree tree={pageTree} />
<SidebarInset>
<div className="flex items-center h-14 gap-2 px-4 border-b shrink-0">
<div className="flex items-center">
<SidebarTrigger className="ml-1.5" />
<Separator
orientation="vertical"
className="mr-2 data-[orientation=vertical]:h-4"
/>
</div>
<div className="flex items-center ml-auto">
<SearchDialog />
<ThemeSelector />
</div>
</div>
<ConfigProvider config={config}>
<div className="flex flex-col flex-1 gap-4 pt-24 mx-auto w-full max-w-[70rem] px-16 md:max-w-[60rem] md:px-24">
{MDX}
</div>
</ConfigProvider>
</SidebarInset>
</SidebarProvider>
);
}
export async function generateStaticParams() {
return source.generateParams();
}
export async function generateMetadata(props: PageProps) {
const params = await props.params;
const entry = await source.getFrontmatter(params.slug);
return entry;
}API Proxy configuration
When mocking external APIs in the browser, you may run into CORS errors. To avoid this, requests are proxied through your Next.js server so they are executed server-side and forwarded to the intended endpoint. This utility automatically creates route handlers for all standard HTTP methods.
import { createProxy } from "@trythis/nextjs/proxy";
export const { GET, HEAD, PUT, POST, PATCH, DELETE } = createProxy();ORPC configuration
ORPC provides a type-safe REST API layer built on top of your router definitions. This setup connects your ORPC router to a Next.js route handler using the Fetch API.
import { router } from "@/orpc-setup/index";
import { onError } from "@orpc/server";
import { RPCHandler } from "@orpc/server/fetch";
const handler = new RPCHandler(router, {
interceptors: [
onError((error) => {
console.error(error);
}),
],
});
async function handleRequest(request: Request) {
const { response } = await handler.handle(request, {
prefix: "/api/orpc",
context: {},
});
return response ?? new Response("Not found", { status: 404 });
}
export const HEAD = handleRequest;
export const GET = handleRequest;
export const POST = handleRequest;
export const PUT = handleRequest;
export const PATCH = handleRequest;
export const DELETE = handleRequest;Install UI components
Fumastudio ships shadcn compatible components which can easily be installed via the shadcn cli.
npx shadcn@latest add https://fumastudio.com/r/api-page https://fumastudio.com/r/http-codesSee the components docs for more info.