CIPs
CIPs copied to clipboard
DocID json-schema definition
cip: 82
title: DocID json-schema definition
author: Paul Le Cam (@PaulLeCam)
status: Draft
category: Standards
type: RFC
created: 2021-02-15
edited: 2021-02-22
Simple Summary
Provide a static way to define a string in a JSON schema represents a Ceramic DocID, optionally with static references to the schema(s) that must be used by the referenced document.
Abstract
This CIP defines a standard way to add a reference to an existing Ceramic document in a JSON schema and references to existing JSON schemas, so it is possible to access this information about Ceramic documents at build time rather than only at runtime on created documents.
Motivation
It is sometimes necessary to reference Ceramic documents from other documents, such as a list containing the docIDs of individual Ceramic documents.
Currently, we are sometimes using definitions that can be referenced in a schema using "$ref": "#/definitions/CeramicDocId"
for example, but this has not be defined as a standard.
Using local definitions to a schema also has the downside of providing no guaranty of being unique or having the definition matching any standard.
Furthermore, IDX definitions contain a schema
property that references an existing schema, guarantying the IDX record associated to the definition matches this schema.
This CIP provides a way to implement similar logic for any schema independently of IDX.
Using this CIP, a NotesList
schema could explicitly reference a Note
schema with the following example:
{
$schema: 'http://json-schema.org/draft-07/schema#',
title: 'Notes',
type: 'object',
properties: {
notes: {
type: 'array',
title: 'list',
items: {
type: 'object',
title: 'item',
properties: {
note: { $ref: '#/definitions/NoteDocID' },
title: {
type: 'string',
maxLength: 100,
},
},
required: ['note'],
},
},
},
definitions: {
NoteDocID: {
type: 'string',
$id: 'ceramic://doc',
$ceramicSchema: '<Note schema docID>' ,
maxLength: 150,
},
},
}
This way, by loading the Notes
schema, it is possible by a tool/library to discover the Note
schema the same way loading a IDX definition allows the discovery of the record's schema.
Specification
References to Ceramic schema should use a string
with the $id
field of ceramic://doc
, and optionally with a $ceramicSchema
property containing either a string or array of strings containing the DocID (implicit reference to latest version) or CommitID (specific version) of the supported schema(s):
{
type: 'string',
$id: 'ceramic://doc',
$ceramicSchema: '<schema docID or commitID>' ,
maxLength: 150,
}
Rationale
Using the $id
field on the object gives a unique namespace (ceramic://
) and identifier (doc
) so it creates a convention that can be used in similar CIPs.
Having this static way of identifying if a document references another document allows to simplify the associated logic, rather than relying on checking all string fields for the ceramic://
prefix, or relying on "$ref": "#/definitions/CeramicDocId"
matching the expected constraints.
This spec also allows to either define a single schema (using a string) or multiple ones (array of strings).
The use case would be to support different schemas for a single reference, for example a "media" schema could reference an "image" schema, but also the "audio" and "video" ones as acceptable document schemas: $ceramicSchema: ['<image schema docID>', '<audio schema docID>', '<video schema docID>']
.
Backwards Compatibility
Ideally we should replace the use of the CeramicDocId
definition in IDX schemas we provide, as well as examples and tutorials.
Implementation
None yet.
Security Considerations
None I'm aware of.
Copyright
Copyright and related rights waived via CC0.
This seems pretty great!
A few questions:
Maybe naming the CIP DocID json-schema definition or something similar that inlcudes json-schmea would be more clear?
Why would we want to include multiple schemas in one reference? Would it not be better to have multiple definitions for each schema to decrease ambiguity?
I think the example would be more clear if you used a named definition!
This seems pretty great!
Thanks!
Maybe naming the CIP DocID json-schema definition or something similar that inlcudes json-schmea would be more clear?
Yes good idea 👍
Why would we want to include multiple schemas in one reference? Would it not be better to have multiple definitions for each schema to decrease ambiguity?
At build time it's used to identify possible schemas the document could use, but it's not necessarily restricted to a single one. For example we can have a media feed document that has items that can be of different types (image, audio or video) so at built time we can discover that we need to be aware of the image, audio and video schemas, but at runtime the loaded document will specify its schema anyways so we can have the runtime logic work accordingly. The main use case here is similar to the GraphQL union type.
I think the example would be more clear if you used a named definition!
Sorry I'm not sure what you mean by named definition here?
Like so:
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"title": "IDXKeychain",
"properties": {
"notes": {
"type": "array",
"items": { "$ref": "#/definitions/DocID" }
}
},
"additionalProperties": false,
"required": [ "notes" ],
"definitions": {
"DocID": {
"type": "string",
"$id": "ceramic://doc",
"$ceramicSchema": "<schema docID>",
"maxLength": 150,
}
}
}
I think this makes it a bit clearer for someone who is trying to understand what this is :)
Also would be helpful to have an example with an actual Schema DocID!
I don't think it makes much sense to use the definitions
here because using $ceramicSchema
makes the field specific to a given schema rather than generic to any document, so in this case this would be simpler:
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"properties": {
"notes": {
"type": "array",
"items": {
"type": "string",
"$id": "ceramic://doc",
"$ceramicSchema": "<schema docID>",
"maxLength": 150
}
}
},
"additionalProperties": false,
"required": ["notes"]
}
Yeah, that's simpler. I more meant that it would be easier to understand for someone reading this CIP because it clearly separates what is part of the DocID reference.
I see, thanks! I updated the example.
'<Note schema docID>'
should be '<Note schema commitID>'
right?
I should accept either, maybe we can name it docRef
then as per Sergey's PR?
Schemas always have to be a CommitID afaik.
edit: disregard my misunderstanding :)
@PaulLeCam Any blockers for making a PR for this CIP?
No blocker, I opened a PR for it that references this issue for discussions: https://github.com/ceramicnetwork/CIP/pull/86
I'm seeing an issue if I have multiple docids in the same schema:
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"title": "ConvictionState",
"properties": {
"context": {
"type": "string"
},
"supply": {
"type": "number"
},
"participants": {
"type": "array",
"items": {
"$ref": "#/definitions/participants"
}
},
"proposals": {
"type": "array",
"items": {
"$ref": "#/definitions/proposals"
}
}
},
"additionalProperties": false,
"required": [
"context",
"supply",
"participants",
"proposals"
],
"definitions": {
"participants": {
"type": "object",
"properties": {
"account": {
"type": "string"
},
"balance": {
"type": "number"
},
"convictions": {
"type": "string",
"$id": "ceramic://doc",
"$ceramicSchema": "<Convictions commitid>",
"maxLength": 150
}
},
"required": [
"account",
"balance",
"convictions"
]
},
"proposals": {
"type": "object",
"properties": {
"proposal": {
"type": "string",
"$id": "ceramic://doc",
"$ceramicSchema": "<Proposal docid>",
"maxLength": 150
},
"totalConviction": {
"type": "number"
},
"triggered": {
"type": "boolean"
}
},
"required": [
"proposal",
"totalConviction",
"triggered"
]
}
}
}
At https://www.jsonschemavalidator.net/ I see this error:

Seems like we can't use $id
as I intended then, thanks for reporting this, I'll look for alternative options.
@oed I created https://github.com/ceramicnetwork/CIP/issues/88 and opened a PR to update CIP-82 with these changes in https://github.com/ceramicnetwork/CIP/pull/89, I think that would nicely work around this issue.