Skip to content
On this page

Service Schemas and Resolvers

The <service>.schemas file contains the schemas and resolvers for this service.

info

The examples on this page are using TypeBox. For more information on plain JSON schema see the JSON schema API documentation.

Patterns

There a four main types of schemas and resolvers. The schemas, resolvers and types are declared as follows:

ts
// The schema definition
export const nameSchema = Type.Object({
  text: Type.String()
})
// The TypeScript type inferred from the schema
export type Name = Static<typeof nameSchema>
// The validator for the schema
export const nameValidator = getValidator(nameSchema, dataValidator)
// The resolver for the schema
export const nameResolver = resolve<Name, HookContext>({})
// The schema definition
export const nameSchema = Type.Object({
  text: Type.String()
})
// The TypeScript type inferred from the schema
export type Name = Static<typeof nameSchema>
// The validator for the schema
export const nameValidator = getValidator(nameSchema, dataValidator)
// The resolver for the schema
export const nameResolver = resolve<Name, HookContext>({})
// The schema definition
export const nameSchema = Type.Object({
  text: Type.String()
})
// The validator for the schema
export const nameValidator = getValidator(nameSchema, dataValidator)
// The resolver for the schema
export const nameResolver = resolve({})
// The schema definition
export const nameSchema = Type.Object({
  text: Type.String()
})
// The validator for the schema
export const nameValidator = getValidator(nameSchema, dataValidator)
// The resolver for the schema
export const nameResolver = resolve({})

Main schema and resolvers

This schema defines the main data model of all properties and is normally the shape of the data that is returned. This includes database properties as well as associations and other computed properties.

ts
// Main data model schema
export const messageSchema = Type.Object(
  {
    id: Type.Number(),
    text: Type.String()
  },
  { $id: 'Message', additionalProperties: false }
)
export type Message = Static<typeof messageSchema>
export const messageValidator = getValidator(messageSchema, dataValidator)
export const messageResolver = resolve<Message, HookContext>({})
// Main data model schema
export const messageSchema = Type.Object(
  {
    id: Type.Number(),
    text: Type.String()
  },
  { $id: 'Message', additionalProperties: false }
)
export type Message = Static<typeof messageSchema>
export const messageValidator = getValidator(messageSchema, dataValidator)
export const messageResolver = resolve<Message, HookContext>({})
// Main data model schema
export const messageSchema = Type.Object(
  {
    id: Type.Number(),
    text: Type.String()
  },
  { $id: 'Message', additionalProperties: false }
)
export const messageValidator = getValidator(messageSchema, dataValidator)
export const messageResolver = resolve({})
// Main data model schema
export const messageSchema = Type.Object(
  {
    id: Type.Number(),
    text: Type.String()
  },
  { $id: 'Message', additionalProperties: false }
)
export const messageValidator = getValidator(messageSchema, dataValidator)
export const messageResolver = resolve({})

External Resolvers

The external resolver defines the data that is sent to a client and is often use to e.g. hide protected properties they should not see:

ts
export const messagesExternalResolver = resolve<Messages, HookContext>({
  someSecretProperty: async () => undefined
})
export const messagesExternalResolver = resolve<Messages, HookContext>({
  someSecretProperty: async () => undefined
})
export const messagesExternalResolver = resolve({
  someSecretProperty: async () => undefined
})
export const messagesExternalResolver = resolve({
  someSecretProperty: async () => undefined
})

Data schema and resolvers

The data schema validates the data when creating a new entry calling service.create. It usually picks its properties from the main schema but can be changed to whatever is needed.

ts
// Schema for creating new entries
export const messageDataSchema = Type.Pick(messageSchema, ['text'], {
  $id: 'MessageData'
})
export type MessageData = Static<typeof messageDataSchema>
export const messageDataValidator = getValidator(messageDataSchema, dataValidator)
export const messageDataResolver = resolve<Message, HookContext>({})
// Schema for creating new entries
export const messageDataSchema = Type.Pick(messageSchema, ['text'], {
  $id: 'MessageData'
})
export type MessageData = Static<typeof messageDataSchema>
export const messageDataValidator = getValidator(messageDataSchema, dataValidator)
export const messageDataResolver = resolve<Message, HookContext>({})
// Schema for creating new entries
export const messageDataSchema = Type.Pick(messageSchema, ['text'], {
  $id: 'MessageData'
})
export const messageDataValidator = getValidator(messageDataSchema, dataValidator)
export const messageDataResolver = resolve({})
// Schema for creating new entries
export const messageDataSchema = Type.Pick(messageSchema, ['text'], {
  $id: 'MessageData'
})
export const messageDataValidator = getValidator(messageDataSchema, dataValidator)
export const messageDataResolver = resolve({})

Patch schema and Resolvers

The patch schema is used for updating existing entries calling service.patch. This is often different then the data schema for new entries and by default is a partial of the main schema.

ts
// Schema for updating existing entries
export const messagePatchSchema = Type.Partial(messageSchema, {
  $id: 'MessagePatch'
})
export type MessagePatch = Static<typeof messagePatchSchema>
export const messagePatchValidator = getValidator(messagePatchSchema, dataValidator)
export const messagePatchResolver = resolve<Message, HookContext>({})
// Schema for updating existing entries
export const messagePatchSchema = Type.Partial(messageSchema, {
  $id: 'MessagePatch'
})
export type MessagePatch = Static<typeof messagePatchSchema>
export const messagePatchValidator = getValidator(messagePatchSchema, dataValidator)
export const messagePatchResolver = resolve<Message, HookContext>({})
// Schema for updating existing entries
export const messagePatchSchema = Type.Partial(messageSchema, {
  $id: 'MessagePatch'
})
export const messagePatchValidator = getValidator(messagePatchSchema, dataValidator)
export const messagePatchResolver = resolve({})
// Schema for updating existing entries
export const messagePatchSchema = Type.Partial(messageSchema, {
  $id: 'MessagePatch'
})
export const messagePatchValidator = getValidator(messagePatchSchema, dataValidator)
export const messagePatchResolver = resolve({})

Query Schema and Resolvers

The query schema defines what can be sent in queries in params.query and also converts strings to the correct type.

ts
// Schema for allowed query properties
export const messageQueryProperties = Type.Pick(messageSchema, [
  'id',
  'text',
  'createdAt',
  'userId'
])
export const messageQuerySchema = Type.Intersect(
  [
    querySyntax(messageQueryProperties),
    // Add additional query properties here
    Type.Object({}, { additionalProperties: false })
  ],
  { additionalProperties: false }
)
export type MessageQuery = Static<typeof messageQuerySchema>
export const messageQueryValidator = getValidator(messageQuerySchema, queryValidator)
export const messageQueryResolver = resolve<MessageQuery, HookContext>({})
// Schema for allowed query properties
export const messageQueryProperties = Type.Pick(messageSchema, [
  'id',
  'text',
  'createdAt',
  'userId'
])
export const messageQuerySchema = Type.Intersect(
  [
    querySyntax(messageQueryProperties),
    // Add additional query properties here
    Type.Object({}, { additionalProperties: false })
  ],
  { additionalProperties: false }
)
export type MessageQuery = Static<typeof messageQuerySchema>
export const messageQueryValidator = getValidator(messageQuerySchema, queryValidator)
export const messageQueryResolver = resolve<MessageQuery, HookContext>({})
// Schema for allowed query properties
export const messageQueryProperties = Type.Pick(messageSchema, [
  'id',
  'text',
  'createdAt',
  'userId'
])
export const messageQuerySchema = Type.Intersect(
  [
    querySyntax(messageQueryProperties),
    // Add additional query properties here
    Type.Object({}, { additionalProperties: false })
  ],
  { additionalProperties: false }
)
export const messageQueryValidator = getValidator(messageQuerySchema, queryValidator)
export const messageQueryResolver = resolve({})
// Schema for allowed query properties
export const messageQueryProperties = Type.Pick(messageSchema, [
  'id',
  'text',
  'createdAt',
  'userId'
])
export const messageQuerySchema = Type.Intersect(
  [
    querySyntax(messageQueryProperties),
    // Add additional query properties here
    Type.Object({}, { additionalProperties: false })
  ],
  { additionalProperties: false }
)
export const messageQueryValidator = getValidator(messageQuerySchema, queryValidator)
export const messageQueryResolver = resolve({})

To add additional operators like $like see the querySyntax documentation. You can also add your own query parameters in the Type.Object({}, { additionalProperties: false }) definition.

Important

Note that references (Type.Ref) can not be used in a query schema. Association querying is usually done by dot separated properties which have to be added manually in MongoDB and SQL.

Released under the MIT License.