Goal for this step 🏁: Configure a schema with an entity type with generated TypeScript types for type safe usage of the API.
In order to be able to create content we first need to create a schema. We can do it in backend/server.ts
after creating the server. Using the Dossier client we create a schema with one entity type, which in turn has a string field.
import { FieldType, type DossierClient } from '@dossierhq/core';
async function updateSchema(client: DossierClient) {
const schemaResult = await client.updateSchemaSpecification({
entityTypes: [
{
name: 'Message',
nameField: 'message',
fields: [{ name: 'message', type: FieldType.String, required: true }],
},
],
});
return schemaResult;
}
export async function initialize(logger: Logger) {
const databaseResult = await initializeDatabase(logger);
if (databaseResult.isError()) return databaseResult;
const serverResult = await initializeServer(logger, databaseResult.value);
if (serverResult.isError()) return serverResult;
const server = serverResult.value;
const initSession = server.createSession({
provider: 'sys',
identifier: 'init',
defaultAuthKeys: [],
logger: null,
databasePerformance: null,
});
const client = server.createDossierClient(() => initSession);
const schemaResult = await updateSchema(client);
if (schemaResult.isError()) return schemaResult;
return ok({ server });
}
Next up we generate TypeScript types for the resulting schema to get more feedback from the compiler when interacting with the API.
npm install -D @dossierhq/typescript-generator
Add a new script, generate-typescript.ts
:
#!/usr/bin/env -S npx tsx
import { Schema, createConsoleLogger, type Logger } from '@dossierhq/core';
import { type Server } from '@dossierhq/server';
import { generateTypescriptForSchema } from '@dossierhq/typescript-generator';
import { writeFile } from 'node:fs/promises';
import { initialize } from './backend/server.js';
async function generateTypes(logger: Logger, schema: Schema, filename: string) {
const publishedSchema = schema.toPublishedSchema();
const sourceCode = generateTypescriptForSchema({
schema,
publishedSchema,
authKeyType: "'none' | 'subject'",
});
await writeFile(filename, sourceCode);
logger.info(`Wrote ${filename}`);
}
async function getAdminSchema(server: Server) {
const initSession = server.createSession({
provider: 'sys',
identifier: 'init',
defaultAuthKeys: [],
logger: null,
databasePerformance: null,
});
const client = server.createDossierClient(() => initSession);
const schemaResult = await client.getSchemaSpecification();
return new Schema(schemaResult.valueOrThrow());
}
async function main() {
const logger = createConsoleLogger(console);
const { server } = (await initialize(logger)).valueOrThrow();
const schema = await getAdminSchema(server);
await generateTypes(logger, schema, './src/SchemaTypes.ts');
await server.shutdown();
}
await main();
Add calling the script to package.json
:
{
"scripts": {
"build": "./generate-typescript.ts && tsc && vite build"
}
}
Then running npm run build
, you should have a generated file in src/SchemaTypes.ts
that includes types for the Message entity type (e.g. AdminMessage
and PublishedMessage
).
We can now use the AppDossierClient
(and in the next step AppPublishedDossierClient
) types, from the generated TypeScript file. This helps the compiler to ensure we use the right values for things like entity types and the types of entity fields. In backend/server.ts
:
import type { AppDossierClient } from '../src/SchemaTypes.js';
export async function initialize(logger: Logger) {
const databaseResult = await initializeDatabase(logger);
if (databaseResult.isError()) return databaseResult;
const serverResult = await initializeServer(logger, databaseResult.value);
if (serverResult.isError()) return serverResult;
const server = serverResult.value;
const initSession = server.createSession({
provider: 'sys',
identifier: 'init',
defaultAuthKeys: [],
logger: null,
databasePerformance: null,
});
const client = server.createDossierClient<AppDossierClient>(() => initSession);
const schemaResult = await updateSchema(client);
if (schemaResult.isError()) return schemaResult;
return ok({ server });
}