Skip to main content

API

Marblism uses tRPC for its API implementation, providing a type-safe and efficient way to handle server-client communication.

tRPC

tRPC Setup

The API uses tRPC, with app/routes/api.trpc.$.tsx serving as the HTTP route that proxies the tRPC client to the tRPC server.

Model Interactions

All model interactions are auto-generated with ZenStack in the app/core/.marblism/zenstack directory. These files should not be modified directly, as the source of truth is the model definition. To generate or update these files, use the following command:

pnpm run crud:sync

tRPC Server and Custom Logic

The tRPC server is exposed in app/core/trpc/server/index.tsx. This file is also where custom functions from plugins are imported. Users can add their own custom backend logic in this file to expose additional functionality through the API.

Classic HTTP Endpoints

While tRPC is the primary method for API interactions, classic HTTP endpoints can still be declared using Remix loaders and actions. Refer to the official Remix documentation for more information on how to implement these endpoints.

Authentication

Core Functions

The main authentication components are exported through index.tsx:

import { createTrpcContext } from './context'
import { getHttpContext, getHttpContextPublic } from './middleware'
import { AuthenticationRouter } from './router'
import { AuthenticationService } from './service'

export const AuthenticationServer = {
createTrpcContext,
getHttpContext,
getHttpContextPublic,
trpcRouter: AuthenticationRouter,
service: AuthenticationService,
}

The tRPC router (AuthenticationRouter) contains essential authentication functions such as login, logout, and register.

Additional functions are available to create and manage user sessions for both tRPC and HTTP calls.

Examples

Here are examples of how to use the authentication functions:

// Get user session if possible (doesn't crash if user is not logged in)
const publicContext = await AuthenticationServer.getHttpContextPublic({
request,
})

// Get user session (crashes if user is not logged in)
const secureContext = await AuthenticationServer.getHttpContext({ request })

Note that getHttpContextPublic will return the user session if available, while getHttpContext will throw an error if the user is not logged in.

createTrpcContext(options) performs a similar function but within a tRPC context, allowing for authentication checks in tRPC procedures.

tRPC Procedures

For tRPC, the app/core/trpc/base/index.tsx file exposes the same notion of public and protected context via tRPC procedures.

export const Trpc = {
createRouter: trpcInstance.router,
mergeRouters: trpcInstance.mergeRouters,
procedurePublic,
procedure,
createContext,
}

Examples

Here are examples of public and protected tRPC procedures:

// Public procedure (no authentication required)
const publicProcedure = Trpc.procedurePublic.query(async () => {
return { message: 'This is a public endpoint' }
})

// Protected procedure (authentication required)
const protectedProcedure = Trpc.procedure.query(async ({ ctx }) => {
// ctx.session.user is guaranteed to exist here
return { message: `Hello, ${ctx.session.user.name}!` }
})

In these examples, publicProcedure can be accessed without authentication, while protectedProcedure requires a valid user session.