Files
freno-dev/docs/trpc-implementation.md
Michael Freno 8fb748f401 init
2025-12-16 22:42:05 -05:00

258 lines
6.9 KiB
Markdown

# tRPC Implementation Documentation
## Overview
This project implements a [tRPC](https://trpc.io/) API layer to provide type-safe communication between the frontend and backend. The implementation follows SolidStart's server-side rendering architecture with a clear separation of concerns.
## Architecture
The tRPC setup is organized in the following structure:
```
src/
├── server/
│ └── api/
│ ├── root.ts # Main router that combines all sub-routers
│ ├── utils.ts # tRPC utility functions and initialization
│ └── routers/ # Individual API route groups
│ ├── auth.ts # Authentication procedures
│ ├── database.ts # Database operations
│ ├── example.ts # Example procedures
│ ├── lineage.ts # Lineage-related APIs
│ └── misc.ts # Miscellaneous endpoints
└── routes/
└── api/
└── trpc/
└── [trpc].ts # API endpoint handler
```
## How to Use tRPC Procedures from the Frontend
The `api` client is pre-configured and available for use in components:
```typescript
import { api } from "~/lib/api";
// Example usage in a component
export function MyComponent() {
const [result, setResult] = useState<string | null>(null);
const handleClick = async () => {
try {
// Call a tRPC procedure
const data = await api.example.hello.query("World");
setResult(data);
} catch (error) {
console.error("Error calling tRPC procedure:", error);
}
};
return (
<div>
<p>{result}</p>
<button onClick={handleClick}>Call API</button>
</div>
);
}
```
## API Route Structure
### Root Router (`src/server/api/root.ts`)
The main router combines all individual routers:
```typescript
export const appRouter = createTRPCRouter({
example: exampleRouter,
auth: authRouter,
database: databaseRouter,
lineage: lineageRouter,
misc: miscRouter
});
```
### Procedure Types
tRPC provides two main procedure types:
- **Query**: For read-only operations (GET requests)
- **Mutation**: For write operations (POST, PUT, DELETE requests)
Example:
```typescript
// Query procedure - read-only
publicProcedure
.input(z.string())
.query(({ input }) => {
return `Hello ${input}!`;
})
// Mutation procedure - write operation
publicProcedure
.input(z.object({ name: z.string() }))
.mutation(({ input }) => {
// Logic for creating/updating data
return { success: true, name: input.name };
})
```
## Adding New Endpoints
### 1. Create a new router file
Create a new file in `src/server/api/routers/`:
```typescript
import { createTRPCRouter, publicProcedure } from "../utils";
import { z } from "zod";
export const myRouter = createTRPCRouter({
// Add your procedures here
hello: publicProcedure
.input(z.string())
.query(({ input }) => {
return `Hello ${input}!`;
}),
});
```
### 2. Register the router in the root
Add your new router to `src/server/api/root.ts`:
```typescript
import { exampleRouter } from "./routers/example";
import { authRouter } from "./routers/auth";
import { databaseRouter } from "./routers/database";
import { lineageRouter } from "./routers/lineage";
import { miscRouter } from "./routers/misc";
import { myRouter } from "./routers/myRouter"; // Add this import
import { createTRPCRouter } from "./utils";
export const appRouter = createTRPCRouter({
example: exampleRouter,
auth: authRouter,
database: databaseRouter,
lineage: lineageRouter,
misc: miscRouter,
myRouter: myRouter, // Add this line
});
```
### 3. Use in frontend
```typescript
// In your frontend component
const data = await api.myRouter.hello.query("World");
```
## Best Practices
1. **Type Safety**: Always use Zod schemas to validate input data and return types.
2. **Error Handling**: Implement proper error handling with try/catch blocks in async procedures.
3. **Procedure Organization**: Group related procedures into logical routers.
4. **Consistent Naming**: Use clear, descriptive names for your procedures and routers.
5. **Documentation**: Document each procedure with clear descriptions of what it does.
## Example Usage Patterns
### Query Procedure (GET)
```typescript
// In your router file
getPosts: publicProcedure
.input(z.object({
limit: z.number().optional(),
offset: z.number().optional()
}))
.query(({ input }) => {
// Return data from database or external service
return { posts: [], total: 0 };
})
```
```typescript
// In frontend component
const { data, isLoading } = api.database.getPosts.useQuery({ limit: 10 });
```
### Mutation Procedure (POST/PUT/DELETE)
```typescript
// In your router file
createPost: publicProcedure
.input(z.object({
title: z.string(),
content: z.string()
}))
.mutation(({ input }) => {
// Create post in database
return { success: true, post: { id: "1", ...input } };
})
```
```typescript
// In frontend component
const { mutateAsync } = api.database.createPost.useMutation();
const handleClick = async () => {
try {
const result = await mutateAsync({
title: "New Post",
content: "Post content"
});
console.log("Created post:", result);
} catch (error) {
console.error("Error creating post:", error);
}
};
```
## Available Endpoints
### Auth
- `auth.githubCallback` - GitHub OAuth callback
- `auth.googleCallback` - Google OAuth callback
- `auth.emailLogin` - Email login
- `auth.emailVerification` - Email verification
### Database
- `database.getCommentReactions` - Get comment reactions
- `database.postCommentReaction` - Add comment reaction
- `database.deleteCommentReaction` - Remove comment reaction
- `database.getComments` - Get comments for a post
- `database.getPosts` - Get posts with pagination
- `database.createPost` - Create new post
- `database.updatePost` - Update existing post
- `database.deletePost` - Delete post
- `database.getPostLikes` - Get likes for a post
- `database.likePost` - Like a post
- `database.unlikePost` - Unlike a post
### Lineage
- `lineage.databaseManagement` - Database management operations
- `lineage.analytics` - Analytics endpoints
- `lineage.appleAuth` - Apple authentication
- `lineage.emailLogin` - Email login
- `lineage.emailRegister` - Email registration
- `lineage.emailVerify` - Email verification
- `lineage.googleRegister` - Google registration
- `lineage.attacks` - Attack data
- `lineage.conditions` - Condition data
- `lineage.dungeons` - Dungeon data
- `lineage.enemies` - Enemy data
- `lineage.items` - Item data
- `lineage.misc` - Miscellaneous data
- `lineage.offlineSecret` - Offline secret endpoint
- `lineage.pvpGet` - PvP GET operations
- `lineage.pvpPost` - PvP POST operations
- `lineage.tokens` - Token operations
### Misc
- `misc.downloads` - Downloads endpoint
- `misc.s3Delete` - Delete S3 object
- `misc.s3Get` - Get S3 object
- `misc.hashPassword` - Hash password