xtablo-source/apps/api/examples/rpc-client-usage.ts

285 lines
8.1 KiB
TypeScript
Raw Normal View History

// /**
// * Example: Using the Type-Safe RPC Client
// *
// * This file demonstrates how to use the Hono RPC client for type-safe API calls
// * from a frontend application or another service.
// *
// * Based on: https://hono.dev/docs/guides/rpc
// */
// import { hc } from "hono/client";
// import type { ApiRoutes } from "../src/client.js";
// // ============================================================================
// // 1. Basic Setup
// // ============================================================================
// // Create a typed client pointing to your API
// const client = hc<ApiRoutes>("https://api.yourdomain.com/api/v1", {
// headers: {
// // Add any default headers here
// "Content-Type": "application/json",
// },
// });
// // ============================================================================
// // 2. Making Authenticated Requests
// // ============================================================================
// async function getUserProfile(token: string) {
// // The client knows all available routes and their types!
// const res = await client.users.me.$get(
// {},
// {
// headers: {
// Authorization: `Bearer ${token}`,
// },
// }
// );
// if (!res.ok) {
// throw new Error(`Failed to fetch user: ${res.status}`);
// }
// // Response is fully typed - TypeScript knows the shape!
// const data = await res.json();
// return data; // TypeScript knows: { user: User }
// }
// // ============================================================================
// // 3. POST Requests with Body
// // ============================================================================
// async function createTablo(token: string, tabloData: { name: string; color: string }) {
// const res = await client.tablos.create.$post(
// {
// json: tabloData, // Typed request body
// },
// {
// headers: {
// Authorization: `Bearer ${token}`,
// },
// }
// );
// if (!res.ok) {
// const error = await res.json();
// throw new Error(`Failed to create tablo: ${error.error}`);
// }
// return await res.json(); // Typed response
// }
// // ============================================================================
// // 4. Route Parameters
// // ============================================================================
// async function getTabloNotes(token: string, tabloId: string) {
// // TypeScript will ensure tabloId is provided and typed correctly
// const res = await client.notes[":tabloId"].$get(
// {
// param: { tabloId }, // Type-checked parameter
// },
// {
// headers: {
// Authorization: `Bearer ${token}`,
// },
// }
// );
// if (!res.ok) {
// throw new Error("Failed to fetch notes");
// }
// const data = await res.json();
// return data.notes; // Fully typed array of notes
// }
// // ============================================================================
// // 5. Query Parameters
// // ============================================================================
// async function searchPublicSlots(shortUserId: string, standardName: string) {
// // Public routes don't need authentication
// const publicClient = hc<ApiRoutes>("https://api.yourdomain.com/api/public");
// const res = await publicClient.slots[":shortUserId"][":standardName"].$get({
// param: {
// shortUserId,
// standardName,
// },
// });
// if (!res.ok) {
// throw new Error("Failed to fetch slots");
// }
// return await res.json();
// }
// // ============================================================================
// // 6. Error Handling with Type Safety
// // ============================================================================
// type ApiError = {
// error: string;
// };
// async function safeApiCall<T>(
// apiCall: () => Promise<Response>
// ): Promise<{ data?: T; error?: string }> {
// try {
// const res = await apiCall();
// if (!res.ok) {
// const errorData = (await res.json()) as ApiError;
// return { error: errorData.error };
// }
// const data = (await res.json()) as T;
// return { data };
// } catch (err) {
// return {
// error: err instanceof Error ? err.message : "Unknown error",
// };
// }
// }
// // Usage
// async function example(token: string) {
// const result = await safeApiCall(() =>
// client.users.me.$get(
// {},
// {
// headers: { Authorization: `Bearer ${token}` },
// }
// )
// );
// if (result.error) {
// console.error("API Error:", result.error);
// return;
// }
// console.log("User data:", result.data);
// }
// // ============================================================================
// // 7. React Hook Example
// // ============================================================================
// /*
// import { useState, useEffect } from 'react';
// function useUser(token: string | null) {
// const [user, setUser] = useState(null);
// const [loading, setLoading] = useState(true);
// const [error, setError] = useState<string | null>(null);
// useEffect(() => {
// if (!token) {
// setLoading(false);
// return;
// }
// getUserProfile(token)
// .then(data => {
// setUser(data.user);
// setError(null);
// })
// .catch(err => {
// setError(err.message);
// })
// .finally(() => {
// setLoading(false);
// });
// }, [token]);
// return { user, loading, error };
// }
// */
// // ============================================================================
// // 8. Advanced: Custom Fetch with Interceptors
// // ============================================================================
// // You can customize the fetch function for things like:
// // - Adding auth tokens automatically
// // - Logging requests
// // - Retry logic
// // - Error handling
// function createAuthenticatedClient(getToken: () => string) {
// return hc<ApiRoutes>("https://api.yourdomain.com/api/v1", {
// fetch: async (input, init) => {
// // Add token to every request
// const token = getToken();
// const headers = new Headers(init?.headers);
// headers.set("Authorization", `Bearer ${token}`);
// // Log requests in development
// if (process.env.NODE_ENV === "development") {
// console.log(`API Request: ${input}`);
// }
// // Make the request
// const response = await fetch(input, { ...init, headers });
// // Log responses in development
// if (process.env.NODE_ENV === "development") {
// console.log(`API Response: ${response.status}`);
// }
// return response;
// },
// });
// }
// // Usage
// const authenticatedClient = createAuthenticatedClient(() => {
// // Get token from your auth system
// return localStorage.getItem("auth_token") || "";
// });
// // Now all requests automatically include the token!
// async function autoAuthExample() {
// const res = await authenticatedClient.users.me.$get({});
// // Token is automatically added
// }
// // ============================================================================
// // 9. Type Exports for Props/State
// // ============================================================================
// // You can extract types from the API responses for use in your components
// type User = Awaited<ReturnType<typeof getUserProfile>>["user"];
// type TabloNotes = Awaited<ReturnType<typeof getTabloNotes>>;
// // Usage in React props
// /*
// interface UserProfileProps {
// user: User;
// }
// function UserProfile({ user }: UserProfileProps) {
// return <div>{user.name}</div>;
// }
// */
// // ============================================================================
// // Export for use in your app
// // ============================================================================
// export {
// client,
// getUserProfile,
// createTablo,
// getTabloNotes,
// searchPublicSlots,
// safeApiCall,
// createAuthenticatedClient,
// };
// export type { User, TabloNotes };