Deploy a Data Model to Ceramic

What is Ceramic?

The website describes it as: “Ceramic is a decentralized data network that brings unlimited data composability to Web3 applications.” but what does that mean exactly, and why should you care.

Ceramic acts as a platform to store your user’s data and create standardized data models that, once adopted and reused by the industry, will allow the next layer of composability within Web3 and Defi. It uniquely allows the user to own their data using their DID(persistent decentralized identifier) that can be generated in many ways, but in this case, using the user’s crypto wallet.

It works by creating streams for data models that are then available for users using their DID. You can think of it as a data table, your DID is the row, and each stream created is a column. An example might look like the one below:

Motivation for this Article

I set out to learn ceramic and how to integrate it into an application after two things happened. Firstly, I heard Kyle Samani(investor at MultiCoin Capital) mention the platform on Epicenter and secondly, I saw there was a bounty to connect a ceramic data model into the Superfluid Console for Eth Shanghai hackathon.

I started with the best intentions, but apart from the documentation available via the Ceramic website, there were not many tutorials from contributors. I found it hard to navigate the documentation to see what I wanted to do. The team is currently reworking some of the documentation. This is by no means a criticism of the team and the work done; they are big brains and have made fantastic docs to match their state-of-the-art protocol. This tutorial was created for people like myself who are 1x engineers and the kind that grasps concepts in a few days/weeks, not seconds. If you are a big brain or a 10x engineer, STOP READING, this will be no good for you.

Create and Deploy

To use a Ceramic data model within an application, you will need to either use a standardized model from the Data Model Registry(there are currently only a few available) or deploy the data model to one of the networks(testnet or mainnet) and use the JSON file to link the data models in your application.

Example JSON Aliases

{
  "definitions": {
    "myAddressBook": "kjzl6cwe1jw1487esfmzik6u8hd9swrut7i73a1b7e8m0gqza0xxuhd61l952hs",
    "DIDToAddressBook": "kjzl6cwe1jw145wbun7wd2507nf00thucutl5wgrl5gtbq8mh852ux33z5si6j6"
  },
  "schemas": {
    "AddressBook": "ceramic://k3y52l7qbv1frxxzi0b8ecysa2rlbtrzwt78blhu9grb9ywdnwda918psqxtc7xts",
    "DIDToAddressBook": "ceramic://k3y52l7qbv1frydo84ulca4ps700j88id1roidw6j4vfnpln8mjo63694x0trtji8"
  },
  "tiles": {}
}   

Today, we will learn how to deploy and create a pull request to add your brand spankin new data model to the registry and make sure others can use your incredible work.

Get the Glaze CLI

The team at Ceramic has built an array of great software to help you interact and develop on the platform. Glaze suite is a middleware that will help you interact with data models and nodes.

  • Install Glaze CLI

npm install --global @glazed/cli

  • Create a local DID to work with

glaze did:create

Make sure you save the output as you will need to use the seed later in the tutorial with the --key flag

Flags

You will need two flags to send most of the commands below:

  • --key: Your seed from above
  • --ceramic: the URI of the node you want to connect.

You can get a node URI from the Ceramic Discord #community-nodes channel

Create the Data Model

We will use the Address Book data model used in the ETH Shanghai Hackathon. But before we do, lets look at some good tools to help you use these data models

JSON Schema Tools

  • This will make it easier to see the actual structure of a reversed engineer object from your schema
  • This will help reduce your schema to a one-liner if you need it
  • *This will allow you to view your deployed schema via the web

Example Schema

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "type": "object",
  "title": "AddressBook",
  "required": [
    "total_cnt",
    "contacts"
  ],
  "additionalProperties": false,
  "properties": {
    "total_cnt": {
      "type": "integer",
      "description": "The total number of contacts",
      "default": 0
    },
    "contacts": {
      "type": "array",
      "default": [],
      "items": {
        "type": "object",
        "required": [
          "name",
          "wallets"
        ],
        "additionalProperties": false,
        "properties": {
          "name": {
            "type": "string",
            "description": "The contacts name",
            "default": ""
          },
          "wallets": {
            "type": "array",
            "description": "Collection of the contacts wallet addresses and respective networks",
            "default": [],
            "items": {
              "type": "object",
              "default": {},
              "required": [
                "walletAddress",
                "network"
              ],
              "additionalProperties": false,
              "properties": {
                "walletAddress": {
                  "type": "string",
                  "default": ""
                },
                "network": {
                  "type": "string",
                  "default": ""
                }
              }
            }
          },
          "avatar": {
            "type": "string",
            "description": "Optional URI of user avatar",
            "default": ""
          },
          "tags": {
            "type": "array",
            "description": "Optional tags for the contact",
            "items": {
              "type": "string"
            },
            "minItems": 1,
            "uniqueItems": true
          },
          "data": {
            "type": "object",
            "description": "Fields to include optional arbitrary data",
            "properties": {}
          }
        }
      }
    }
  }
}
  • Create Data Model

glaze model:create address-book --key=<YOUR SEED> -c=<NODE URI>

  • Add Address Book Schema

glaze model:add address-book schema AddressBook “{JSON}” --key=<YOUR SEED> -c=<NODE URI>

If you have any other schemas. You would insert them now. For the hackathon there was one other Schema that was used - DIDToAddressBook

Definitions

You also want to add definitions to this model for any schemas you have created. -

  • Definitions are used in the Index of the DID DataStore.
  • An Index is a TileDocument matching the IdentityIndex spec from CIP-11, used by the DID DataStore to associate Definition IDs to Record IDs

Example Definition

'{
    "name": "My address book",
    "description": "Address book to keep track of a users        different accounts and contacts",        
    "schema": "ceramic://k3y52l7qbv1frxxzi0b8ecysa2rlbtrzwt78blhu9grb9ywdnwda918psqxtc7xts"
}' 
  • Add Definition

glaze model:add address-book definition myAddressBook --key=<YOUR SEED> -c=<NODE URI>

  • Publish the Model

glaze model:deploy address-book publishedAddressBook.json --key=<YOUR SEED> -c=<NODE URI>

Where publishedAddressBook.json is the aliases file you will use in your app.

Example publishedAddressBook.json

{
  "definitions": {
    "myAddressBook": "kjzl6cwe1jw1487esfmzik6u8hd9swrut7i73a1b7e8m0gqza0xxuhd61l952hs"
  },
  "schemas": {
    "AddressBook": "ceramic://k3y52l7qbv1frxxzi0b8ecysa2rlbtrzwt78blhu9grb9ywdnwda918psqxtc7xts"
  },
  "tiles": {}
}

Congratulations!!! You have now built and deployed at DataModel to Ceramic. It is ready to be integrated into your application. We will go over how to do that in another post but let’s first see how you can create a PR to add this new shiny DataModel to the Ceramic Data Model Registry.

Add the Data Model to the Ceramic Data Model Registry

You can find the repository here and an example PR here

  • Fork the Data Model Registry Repo and clone on your local computer
    git clone <YOUR NEW REPO>

  • Create a new branch
    git checkout -b add-new-data-model

  • Create a new folder in the /models directory with the name of your data model eg /address-book

  • Use one of the existing data models as a template, most of the root files will stay the same apart from package.json that will require some minor changes

  • Create a /schema directory and in the directory use the schemas that you just used to create your model and create a file in that directory.

  • Create a /src directory and add an index.js file. To get the details that you need for the EncodedManagedModel you will need the following command.
    glaze model:export address-book exportedAddressBook.json

    **Example exportedAddressBook.json

**

{
  "schemas": {
    "kjzl6cwe1jw147layx2v9p53o0i6q4hzjutuvpkkgf39u7xf68m958jdlsdos47": {
      "alias": "AddressBook",
      "commits": [
        {
          "jws": {
            "payload": "AXESIFHH8eYt5V4Sk7gHQnKgYYjKBPZHCCnJR4OuZgoi6jaU",
            "signatures": [
              {
                "signature": "b4EvyuK3NZr97VmT01nsy4QFCMVBw2ck4yhsNBcLLJIf2ssr687seAOT_b0cvYVoSwDaIrdc8NoBul2JHYZuCA",
                "protected": "eyJhbGciOiJFZERTQSIsImtpZCI6ImRpZDprZXk6ejZNa2VpOXJyelF2aVlqcGJhVjFNcDFhVFVibmY0aWpidTNvekpVZnB5VTVQWGg3I3o2TWtlaTlycnpRdmlZanBiYVYxTXAxYVRVYm5mNGlqYnUzb3pKVWZweVU1UFhoNyJ9"
              }
            ],
            "link": "bafyreicry7y6mlpflyjjhoahijzkaymizicpmryifheupa5omyfcf2rwsq"
          },
          "linkedBlock": "omRkYXRhpmR0eXBlZm9iamVjdGV0aXRsZWtBZGRyZXNzQm9va2ckc2NoZW1heCdodHRwOi8vanNvbi1zY2hlbWEub3JnL2RyYWZ0LTA3L3NjaGVtYSNocmVxdWlyZWSCaXRvdGFsX2NudGhjb250YWN0c2pwcm9wZXJ0aWVzomhjb250YWN0c6NkdHlwZWVhcnJheWVpdGVtc6RkdHlwZWZvYmplY3RocmVxdWlyZWSCZG5hbWVnd2FsbGV0c2pwcm9wZXJ0aWVzpWRkYXRho2R0eXBlZm9iamVjdGpwcm9wZXJ0aWVzoGtkZXNjcmlwdGlvbngpRmllbGRzIHRvIGluY2x1ZGUgb3B0aW9uYWwgYXJiaXRyYXJ5IGRhdGFkbmFtZaNkdHlwZWZzdHJpbmdnZGVmYXVsdGBrZGVzY3JpcHRpb25xVGhlIGNvbnRhY3RzIG5hbWVkdGFnc6VkdHlwZWVhcnJheWVpdGVtc6FkdHlwZWZzdHJpbmdobWluSXRlbXMBa2Rlc2NyaXB0aW9ueB1PcHRpb25hbCB0YWdzIGZvciB0aGUgY29udGFjdGt1bmlxdWVJdGVtc/VmYXZhdGFyo2R0eXBlZnN0cmluZ2dkZWZhdWx0YGtkZXNjcmlwdGlvbngbT3B0aW9uYWwgVVJJIG9mIHVzZXIgYXZhdGFyZ3dhbGxldHOkZHR5cGVlYXJyYXllaXRlbXOlZHR5cGVmb2JqZWN0Z2RlZmF1bHSgaHJlcXVpcmVkgm13YWxsZXRBZGRyZXNzZ25ldHdvcmtqcHJvcGVydGllc6JnbmV0d29ya6JkdHlwZWZzdHJpbmdnZGVmYXVsdGBtd2FsbGV0QWRkcmVzc6JkdHlwZWZzdHJpbmdnZGVmYXVsdGB0YWRkaXRpb25hbFByb3BlcnRpZXP0Z2RlZmF1bHSAa2Rlc2NyaXB0aW9ueENDb2xsZWN0aW9uIG9mIHRoZSBjb250YWN0cyB3YWxsZXQgYWRkcmVzc2VzIGFuZCByZXNwZWN0aXZlIG5ldHdvcmtzdGFkZGl0aW9uYWxQcm9wZXJ0aWVz9GdkZWZhdWx0gGl0b3RhbF9jbnSjZHR5cGVnaW50ZWdlcmdkZWZhdWx0AGtkZXNjcmlwdGlvbngcVGhlIHRvdGFsIG51bWJlciBvZiBjb250YWN0c3RhZGRpdGlvbmFsUHJvcGVydGllc/RmaGVhZGVyomZ1bmlxdWVwZjloTjNjY0h3U01jeFoyaGtjb250cm9sbGVyc4F4OGRpZDprZXk6ejZNa2VpOXJyelF2aVlqcGJhVjFNcDFhVFVibmY0aWpidTNvekpVZnB5VTVQWGg3"
        }
      ],
      "dependencies": {},
      "version": "k3y52l7qbv1frxxzi0b8ecysa2rlbtrzwt78blhu9grb9ywdnwda918psqxtc7xts"
    }
  },
  "definitions": {
    "kjzl6cwe1jw1487esfmzik6u8hd9swrut7i73a1b7e8m0gqza0xxuhd61l952hs": {
      "alias": "myAddressBook",
      "commits": [
        {
          "jws": {
            "payload": "AXESIFEWkK7SHlFy3aQWYiDEEhXgV561SEgurYkeaqNnGz7n",
            "signatures": [
              {
                "signature": "CYXT973re2KrezmZhr3KLzHdu9ZjBBXFonKwp1C3VhbL7pJz4wWYD64yY1NMLv1nYWJ-Dp3pkvKjxvf__zMXCw",
                "protected": "eyJhbGciOiJFZERTQSIsImtpZCI6ImRpZDprZXk6ejZNa2VpOXJyelF2aVlqcGJhVjFNcDFhVFVibmY0aWpidTNvekpVZnB5VTVQWGg3I3o2TWtlaTlycnpRdmlZanBiYVYxTXAxYVRVYm5mNGlqYnUzb3pKVWZweVU1UFhoNyJ9"
              }
            ],
            "link": "bafyreicrc2ik5uq6kfzn3jawmiqmieqv4blz5nkijaxk3ci6nkrwogz644"
          },
          "linkedBlock": "omRkYXRho2RuYW1lb015IGFkZHJlc3MgYm9va2ZzY2hlbWF4S2NlcmFtaWM6Ly9rM3k1Mmw3cWJ2MWZyeHh6aTBiOGVjeXNhMnJsYnRyend0NzhibGh1OWdyYjl5d2Rud2RhOTE4cHNxeHRjN3h0c2tkZXNjcmlwdGlvbnhFQWRkcmVzcyBib29rIHRvIGtlZXAgdHJhY2sgb2YgYSB1c2VycyBkaWZmZXJlbnQgYWNjb3VudHMgYW5kIGNvbnRhY3RzZmhlYWRlcqNmc2NoZW1heEtjZXJhbWljOi8vazN5NTJsN3FidjFmcnkxZnA0czBud2RhcmgwdmFodXNhcnBwb3NnZXZ5MHBlbWl5a3ltZDJvcmQ2c3d0aGFyY3dmdW5pcXVlcFFEMTVXWE5PT2ZJMkhlNlRrY29udHJvbGxlcnOBeDhkaWQ6a2V5Ono2TWtlaTlycnpRdmlZanBiYVYxTXAxYVRVYm5mNGlqYnUzb3pKVWZweVU1UFhoNw=="
        }
      ],
      "schema": "kjzl6cwe1jw147layx2v9p53o0i6q4hzjutuvpkkgf39u7xf68m958jdlsdos47",
      "version": "k3y52l7qbv1fry2cp677gjzkn0bidpl233pdefbdbol98jb3uvapcorhmzb501qf4"
    }
  },
  "tiles": {}
}
  • Create Types from your Schema
    yarn types

  • Check that the package builds
    yarn prepare

  • Test that it can be published
    yarn prepublishOnly

  • Commit changes
    git add .
    git commit -m ‘Add new data.model’

  • Push to the remote repo
    git push

  • When you now go to your repo in Github, you will be able to send a pull request with your changes to the Ceramic DataModel registry repo.

    NICE!!! You have now contributed to Web3 and the open-source community built around the Ceramic protocol.

If you have any suggestions on making this tutorial better, opinions or want to chat. Feel free to reach out via Twitter or Discord

Subscribe to 0xZOZ
Receive the latest updates directly to your inbox.
Verification
This entry has been permanently stored onchain and signed by its creator.