Schema
In the context of CosmWasm, “schema” refers to the description of the interface between a contract and the client (aka. frontend). This interface is always JSON encoded and the schema describes the structure of that JSON. In terms of EVM equivalents, it is more or less what the Contract ABI does.
For the execution of contracts the schema is not used. If the contract interface is simple enough you can write the JSON by hand in the client code. Then no schema needs to be created ever. However, this approach does not scale well and is just mentioned for better understanding.
Sometimes you also see schema generation for storage types but this is usually not needed as long as only the contract itself reads and writes storage. There might be cases where a storage schema could be useful to allow indexers to better use state data, but that is far from well established practice. Also in contrast to the contract-client API, storage is not necessarily JSON encoded. These days MessagePack should be the encoding of choice for high efficient storage and the Storey library is one approach using that.
There are two different types of schemas in CosmWasm:
- JSON Schema (version 1): the original schema used since 2020 relying on the
JSON Schema specification. In CosmWasm we use the
#[cw_serde]
annotation, thecosmwasm-schema
crate and thecargo schema
scripts to generate a JSON Schema from Rust message types. - CosmWasm Schema (version 2): taking the learnings from working with JSON Schema and seeing how it is not meant to be a code generator, we developed a new type of schema. This aims to be more compact and include more data relevant for generating clients in various programming languages. See this article for a full explanation of the motivation and differences.
CosmWasm Schema is first shipped as part of CosmWasm 3 but for the foreseable future you are free to use any of the formats.
Generating the schema
Both schemas are generated as follows:
-
Annotate the relevant types with
#[cw_serde]
-
Have a
src/bin/schema.rs
that looks more or less like this:use cosmwasm_schema::write_api; use hackatom::msg::{ExecuteMsg, InstantiateMsg, MigrateMsg, QueryMsg, SudoMsg}; fn main() { write_api! { instantiate: InstantiateMsg, query: QueryMsg, execute: ExecuteMsg, // 👇 only add those entries if you use the sudo/migrate entry point sudo: SudoMsg, migrate: MigrateMsg, } }
-
In
.cargo/config.toml
, ensure you have this alias:[alias] # ... schema = "run --bin schema"
-
In your contract folder, run
cargo schema
.
This generates a folder structure similar to this:
schema
├── cw_schema
│ ├── hackatom.json
│ └── raw
│ ├── execute.json
│ ├── instantiate.json
│ ├── migrate.json
│ ├── query.json
│ ├── response_to_get_int.json
│ ├── response_to_recurse.json
│ ├── response_to_verifier.json
│ └── sudo.json
├── hackatom.json
└── raw
├── execute.json
├── instantiate.json
├── migrate.json
├── query.json
├── response_to_get_int.json
├── response_to_recurse.json
├── response_to_verifier.json
└── sudo.json
Here the cw_schema
folder contains the schema in the new format and hackatom.json
plus raw
is
the JSON Schema. The raw folder hosts the original JSON Schema output, one file per struct. The
hackatom.json
(or more generally <contract_name>.json
) combined those into a simple API file as
documented in CosmWasm IDL v1.0.0.
Using the schema
By parsing <contract_name>.json
or cw_schema/<contract_name>.json
you can generate client code
to interact with the contract. One project implementing this is ts-codegen. You can also use the
schema to dynamically generate UIs at runtime for developers and power users.
The raw
folder is only needed if the code generator cannot handle the container file
<contract_name>.json
and you want to get access to the plain JSON Schema.
Checking in schemas
The files in the ./schema
folder are auto-generated from the source code. So they don’t
necessarily need to be added to your source repository. Other deployment methods like GitHub release
artifacts could be used for dirstribution. But often it is just the simplest solution to check them
in and track schema changes during development in pull requests. This ensures they are up-to-date
and no interface is changed by accident.
At the end of the day the contract developer and the users of the schema files have to agree on the best way to share the files.