Skip to content

bastianplsfix/botc-no-cap-frfr

Repository files navigation

"Backend-on-the-client" no cap frfr

This project demonstrates a pattern for running a “backend on the client,” using in-memory Fakes to simulate real server behavior and a simple business rules engine, all wired up with TanStack Router for navigation.


What does this project contain?

  1. lib/rule-engine A sample rules engine that allows you to evaluate, apply, or chain business rules.

  2. A fakes demo with TanStack Router A working example of how to toggle between fake (in-memory) and real (API-based) repositories using TanStack Router. The fake repositories simulate backend calls, making it easy to develop and test frontend features without relying on an actual backend.


What is Fakes?

Fakes are in-memory or mock implementations of repositories or services that typically would communicate with a real backend (e.g., an HTTP API or a database). In this context:

  • FakeHelloRepository simulates fetching or posting data for “Hello” messages.
  • LoanApplicationRepositoryFake simulates reading and writing loan application data.

Fakes can be used for:

  • Rapid Prototyping: Build out your UI without waiting on a real backend.
  • Testing: Test flows in a controlled environment without network dependencies.
  • Offline Development: Easily develop features while traveling or if your real backend is temporarily unavailable.

How is Fakes implemented?

Inside your code (e.g., main.tsx), you’ll see logic that chooses between fake vs. real repositories based on an environment variable:

// main.tsx

const isFake = import.meta.env.VITE_FAKE === "true";

const helloRepository = isFake
    ? new HelloRepositoryFake()
    : new HelloRepositoryImpl();
  1. Check VITE_FAKE: By default, we rely on import.meta.env.VITE_FAKE (set in your .env file) to decide if the app should use fake or real repositories.

  2. Create the Repositories:

    • Fake: In-memory classes that store data in local variables or arrays.
    • Impl: Classes that communicate with actual APIs or databases.
  3. Pass Repositories into the Router Context: We then pass the chosen repositories to TanStack Router’s context so any route (or component) in the tree can access them.


Configuring your Tanstack Router project to work with Fakes

If you want your TanStack Router project to use in-memory fakes for local development or testing:

  1. Create Your Repositories Define both fake and real implementations. For example:

    // domain/HelloRepository.ts
    
    export interface HelloRepository {
      getGreeting(): Promise<string>;
      // ...
    }
    
    export class FakeHelloRepository implements HelloRepository {
      async getGreeting() {
        return "Hello from Fake!";
      }
    }
    
    export class HelloRepositoryImpl implements HelloRepository {
      async getGreeting() {
        // e.g., fetch from an actual API
        const response = await fetch("/api/hello");
        return response.text();
      }
    }
  2. Use an Environment Variable Create or update your .env file:

    # .env
    VITE_FAKE=true

    If VITE_FAKE is "true", the app will use the fake implementations. Otherwise, it will default to real implementations.

  3. Load Repositories in main.tsx In your main.tsx, detect the environment variable and select the appropriate repository:

    // main.tsx
    
    import { RouterProvider, createRouter } from "@tanstack/react-router";
    import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
    
    import {
      HelloRepositoryFake,
      HelloRepositoryImpl,
    } from "./domain/HelloRepository";
    
    // 1. Check the environment variable
    const isFake = import.meta.env.VITE_FAKE === "true";
    
    // 2. Pick fake or real
    const helloRepository = isFake
      ? new HelloRepositoryFake()
      : new HelloRepositoryImpl();
    
    // 3. Create a QueryClient
    const queryClient = new QueryClient();
    
    // 4. Create and configure your TanStack Router
    const router = createRouter({
      routeTree,
      defaultPreload: "intent",
      context: {
        // Make the chosen repos available to any route or component
        helloRepository,
        queryClient,
      },
    });
    
    // 5. Render your app
    const rootElement = document.getElementById("app")!;
    const root = ReactDOM.createRoot(rootElement);
    
    root.render(
      <QueryClientProvider client={queryClient}>
        <RouterProvider router={router} />
      </QueryClientProvider>,
    );
  4. Configuring TanStack Router with Context

    To get TypeScript support for your context, you need to use createRootRouteWithContext(). For example:

    import {
    ...
      createRootRouteWithContext,
    } from "@tanstack/react-router";
    import { TanStackRouterDevtools } from "@tanstack/router-devtools";
    import { LoanApplicationRepository } from "../domain/LoanApplicationRepository";
    import { HelloRepository } from "../domain/HelloRepository";
    ...
    
    interface RouterContext {
      ...
      helloRepository: HelloRepository;
      ...
    }
    
    export const Route = createRootRouteWithContext<RouterContext>()({
      component: RootComponent,
    });
    ...
    
      );
    }
    

    Why createRootRouteWithContext<RouterContext>?

    It tells TanStack Router the shape of your router context (the custom data you want all routes to have access to).

    It ensures TypeScript picks up the correct types, so you get proper autocompletion and type-checking in your route components when using something like useRouter().context.

  5. Use the Context in Your Routes or Components Within a route component, you can grab the repository from the router context:

    import { useRouter } from "@tanstack/react-router";
    
    function HelloPage() {
      const { helloRepository } = useRouter().context;
    
      const [greeting, setGreeting] = React.useState("");
    
      React.useEffect(() => {
        helloRepository.getGreeting().then(setGreeting);
      }, [helloRepository]);
    
      return <div>{greeting}</div>;
    }
    
    export default HelloPage;

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published