First Steps
JSandy makes it easy to build performant, reliable Next.js applications. You can start a new project in one of two ways:
- Using the CLI (recommended)
- Manual Setup
Especially if you use the CLI (which does all the setup automatically), this guide will help you understand key components of your new (and hopefully favorite 🤞) Next.js & TypeScript tech stack.
Quickstart
The quickest way to get started is with the CLI:
npx create-jsandy-app@latestThat's it! 🎉 The CLI creates a brand-new project following best practices and modern Next.js patterns. I recommend reading on to understand each part of JSandy.
1. File Structure
Let's explore the main building blocks of JSandy. I recommend the following file structure for your Next.js application:
app/
└── server/
├── jsandy.ts # Initialize JSandy
├── index.ts # Main appRouter
└── routers/ # Router directory
├── user-router.ts
├── post-router.ts
└── ...2. Initialize JSandy
This file is the point where we initialize JSandy. Optionally, you can specify your environment variable type here, which makes it type-safe across your application.
import { jsandy } from "@jsandy/rpc"
interface Env {
Bindings: { DATABASE_URL: string }
}
export const j = jsandy.init<Env>()
/**
* Public (unauthenticated) procedures
* This is the base part you use to create new procedures.
*/
export const publicProcedure = j.procedureThis file is where we create Procedures and Middleware.
3. The App Router 🧠
The core of JSandy is the appRouter - it's the entry point to your Next.js backend and manages all your API routes:
import { j } from "./jsandy"
/**
* This is your base API.
* Here, you can handle errors, not-found responses, cors and more.
*/
const api = j
.router()
.basePath("/api")
.use(j.defaults.cors)
.onError(j.defaults.errorHandler)
/**
* This is the main router for your server.
* All routers in /server/routers should be added here manually.
*/
const appRouter = j.mergeRouters(api, {
// ...
})
export type AppRouter = typeof appRouter
export default appRouterWhen a new HTTP request comes in to your server, the appRouter knows where to route the request.
→ Read more about the appRouter
4. Routers
Routers help you group related features. For example, you might have:
userRouterfor user related operationspaymentRouterfor all payment related operationspostRouterfor blog post operations
This is what a basic router looks like:
import { j, publicProcedure } from "../jsandy"
export const postRouter = j.router({
recent: publicProcedure.get(({ c }) => {
return c.json({ title: "first post" })
}),
})In this example:
postRouteris the name of your routerrecentis the name of your procedure- The function gets a context object (
c) with helpful utilities - We return a mocked post using
c.json()
5. Connecting a Router
Let's connect our new router to make it available for API requests:
import { j } from "./jsandy"
import { postRouter } from "./routers/post-router"
const api = j
.router()
.basePath("/api")
.use(j.defaults.cors)
.onError(j.defaults.errorHandler)
const appRouter = j.mergeRouters(api, {
post: postRouter,
})
export type AppRouter = typeof appRouter
export default appRouter6. API Setup
To handle all incoming requests with our appRouter, create a catch-all API route:
import appRouter from "@/server"
import { handle } from "hono/vercel"
export const GET = handle(appRouter.handler)
export const POST = handle(appRouter.handler)That's it! 🎉
You can now send API requests to http://localhost:3000/api/post/recent. This path is made up of three different parts:
- base path (
/api) - Router name (
post) - Procedure name (
recent)
