Minka Ledger Docs
Explanations

About Schemas

DateResponsibleChanges
May 25, 2023@Omar MonterreyInitial version

Ledger database provides multiple record types with strict (built-in) schemas for all root fields except the custom field which can contain anything. On different scenarios, users of the ledger may need to extend those schemas to match their use cases.

What is a Schema

A schema, in the ledger context, is just another record that can be created by using the API. The schema record defines a set of rules and constraints that will be used to validate the record that schema is intended for. All schemas have a record property which refers to the type of record that schema will be used on, that record property can be one of symbol, signer, wallet, intent, effect, bridge or circle.

Custom schemas extend the built-in schemas of the ledger, but they don't replace them. This mean that incoming records are validated first against built-in schemas and then again custom schemas.

How are schemas structured

The only supported schema format, for now, is json-schema. Json Schema is a declarative language that allows to specify different rules, types and constraints that will be used to validate the input JSON. You can read more about it on it's oficial webpage. Please notice that ledger uses the Draft-07 from the JSON Schema specifications in order to have a better performance.

  • Example of Schema with this Draft

    const schema = {
      definitions: {
        IssueClaim: {
          type: "object",
          required: ["action", "target", "symbol", "amount"],
          properties: {
            action: {
              type: "string",
              const: "issue",
            },
            target: {
              type: "string",
            },
            symbol: {
              type: "string",
            },
            amount: {
              type: "integer",
            },
          },
        },
        TransferClaim: {
          type: "object",
          required: ["action", "source", "target", "symbol", "amount"],
          properties: {
            action: {
              type: "string",
              const: "transfer",
            },
            source: {
              type: "string",
            },
            target: {
              type: "string",
            },
            symbol: {
              type: "string",
            },
            amount: {
              type: "integer",
            },
          },
        },
        DestroyClaim: {
          type: "object",
          required: ["action", "source", "symbol", "amount"],
          properties: {
            action: {
              type: "string",
              const: "destroy",
            },
            source: {
              type: "string",
            },
            symbol: {
              type: "string",
            },
            amount: {
              type: "integer",
            },
          },
        },
      },
      type: "object",
      required: ["data"],
      properties: {
        data: {
          type: "object",
          required: ["handle", "claims"],
          properties: {
            handle: {
              type: "string",
            },
            claims: {
              type: "array",
              items: {
                type: "object",
                discriminator: { propertyName: "action" },
                oneOf: [
                  {
                    $ref: "#/definitions/IssueClaim",
                  },
                  {
                    $ref: "#/definitions/TransferClaim",
                  },
                  {
                    $ref: "#/definitions/DestroyClaim",
                  },
                ],
              },
            },
          },
        },
      },
    };
  • Example of Data that can be validated against previous schema

    const intent = {
      data: {
        // If no handle is provided, it will return error
        // handle: 'x12345',
        claims: [
          // Valid transfer claim
          {
            action: "transfer",
            source: "acc1",
            target: "acc2",
            symbol: "usd",
            amount: 10,
          },
          // Valid issue claim
          {
            action: "issue",
            target: "acc2",
            symbol: "usd",
            amount: 10,
          },
          // Valid destroy claim
          {
            action: "destroy",
            source: "acc1",
            symbol: "usd",
            amount: 10,
          },
          // missing symbol
          {
            action: "transfer",
            source: "acc1",
            target: "acc2",
            amount: 10,
          },
          // invalid action
          {
            action: "fake",
            source: "acc1",
            target: "acc2",
            amount: 10,
          },
          // missing amount
          {
            action: "issue",
            target: "acc1",
            symbol: "usd",
          },
          // missing symbol
          {
            action: "destroy",
            source: "acc1",
            amount: 10,
          },
        ],
      },
    };

All errors are thrown, if you have 3 errors in your schema they will be thrown and separated by comma. Example for provided schema and data:

data.data.claims.3 must have required property 'symbol', data.data.claims.4 value of tag "action" must be in oneOf, data.data.claims.5 must have required property 'amount', data.data.claims.6 must have required property 'symbol’

When are schemas validated

Schemas are validated at the moment of attempting to create or update a new record. The <record>.data property is validated against the specified schema. If that validation fails, error will be thrown and the intended operation will not be completed.

💡 Schemas for records are specified by passing schema's handle in <record>.data.schema property.

Schemas are optional, but…

Custom schema validation is an optional feature of the ledger, however, if there is at least one schema created for any record type, then the schema property is required for all subsequent records being updated or created under said type.

On this page