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.