@sigamix/form-server
v0.3.0
Published
Form server — REST API with Prisma, multi-tenant, multi-database
Readme
@sigamix/form-server
REST API server for form management — Prisma ORM, multi-tenant, PostgreSQL + SQLite. Compatible with Express, Fastify, and Next.js API Routes.
Installation
npm install @sigamix/form-server @sigamix/form-core @prisma/client
npm install -D prismaUsage — Next.js API Routes
// app/api/forms/[...path]/route.ts
import { createFormRouter } from '@sigamix/form-server'
import { PrismaClient } from '@prisma/client'
const prisma = new PrismaClient()
const router = createFormRouter({
prisma,
auth: async (req) => {
const token = req.headers.authorization?.replace('Bearer ', '')
const user = await verifyToken(token)
return user ? { userId: user.id, tenantId: user.tenantId } : null
},
})
export async function GET(req: Request) {
const url = new URL(req.url)
const path = url.pathname.replace('/api/forms', '')
const result = await router.handle({
method: 'GET',
path,
params: {},
query: Object.fromEntries(url.searchParams),
body: null,
headers: Object.fromEntries(req.headers),
})
return Response.json(result.body, { status: result.status })
}
export async function POST(req: Request) {
const url = new URL(req.url)
const path = url.pathname.replace('/api/forms', '')
const body = await req.json()
const result = await router.handle({
method: 'POST',
path,
params: {},
query: Object.fromEntries(url.searchParams),
body,
headers: Object.fromEntries(req.headers),
})
return Response.json(result.body, { status: result.status })
}Usage — Express
import express from 'express'
import { createFormRouter } from '@sigamix/form-server'
import { PrismaClient } from '@prisma/client'
const app = express()
const router = createFormRouter({ prisma: new PrismaClient() })
app.use('/api/forms', express.json(), async (req, res) => {
const result = await router.handle({
method: req.method,
path: req.path,
params: {},
query: req.query as Record<string, string>,
body: req.body,
headers: req.headers as Record<string, string>,
})
res.status(result.status).json(result.body)
})Auth Injectable
The package includes no auth logic. Inject your own via the auth option:
import type { AuthMiddleware } from '@sigamix/form-server'
const myAuth: AuthMiddleware = async (req) => {
const token = req.headers.authorization?.replace('Bearer ', '')
if (!token) return null // → 401 Unauthorized
const user = await verifyJWT(token)
return { userId: user.id, tenantId: user.orgId }
}
createFormRouter({ prisma, auth: myAuth })Default: noAuth — allows all requests (for development).
Multi-Tenant
tenantId is an optional field on FormDefinition and FormSubmission:
- Pass
tenantIdwhen creating forms and submissions - Filter by
tenantIdin list queries - Auth middleware can set
tenantIdfrom the authenticated user
Database
| Provider | Use case | URL format |
|----------|----------|------------|
| PostgreSQL | Production | postgresql://user:pass@host:5432/db |
| SQLite | Development / Testing | file:./dev.db |
Copy the Prisma schema from the package and adjust the provider:
datasource db {
provider = "postgresql" // or "sqlite"
url = env("DATABASE_URL")
}Routes (25)
| Method | Path | Description |
|--------|------|-------------|
| GET | /form-types | List all form types |
| GET | /form-types/:id | Get form type |
| POST | /form-types | Create form type |
| PUT | /form-types/:id | Update form type |
| DELETE | /form-types/:id | Delete form type |
| GET | /forms | List forms (paginated, searchable) |
| GET | /forms/:id | Get form with full structure |
| POST | /forms | Create form |
| PUT | /forms/:id | Update form |
| DELETE | /forms/:id | Delete form (cascade) |
| GET | /forms/:id/export | Export form as JSON |
| POST | /forms/import | Import form from JSON |
| POST | /forms/:formId/pages | Create page |
| PUT | /pages/:id | Update page |
| DELETE | /pages/:id | Delete page |
| POST | /pages/:pageId/rosters | Create roster |
| PUT | /rosters/:id | Update roster |
| DELETE | /rosters/:id | Delete roster |
| POST | /pages/:pageId/variables | Create variable on page |
| POST | /rosters/:rosterId/variables | Create variable on roster |
| PUT | /variables/:id | Update variable |
| DELETE | /variables/:id | Delete variable |
| GET | /forms/:formId/submissions | List submissions (paginated) |
| GET | /submissions/:id | Get submission |
| POST | /submissions | Create submission |
| PUT | /submissions/:id | Update submission status |
All inputs validated with Zod. Errors returned as { status, message, data, errors }.
License
Copyright (c) 2026 AFINOV SARL — All rights reserved. Commercial license required. Contact: [email protected]
