Every wrapper project has a schema. The schema defines the wrapper's dependencies, methods, and custom types. In short, it's an interface describing how to use the wrapper.
The schema is a sort of contract between a wrapper's developers and its users. A Wasm wrapper will not compile unless it implements and exports all of the methods declared in the schema. A Wasm wrapper's users can be certain that all of the methods declared in a schema are callable using the declared method signatures. Plugin wrappers do not have this same guarantee. However, the client will throw an exception if a user attempts to invoke a method and the method is not found.
A wrapper project's schema must be declared in the project manifest (Polywrap Manifest or Plugin Manifest).
The wrapper schema tells the Polywrap compiler which types and serialization logic to generate.
Generated types are updated every time you
build the wrapper.
polywrap CLI also provides a
codegen command to
quickly update the generated
wrap folder where generated types are stored.
The Polywrap compiler generates types for method arguments and custom schema types. Wrapper developers must use the generated method arguments for methods declared in the schema, and generated types for method return values when the return value is of a custom type. The generated types come with serialization logic that allows Wrappers to communicate with the client.
The following example demonstrates this practice.
Wrapper schemas are written in Polywrap's variant of the GraphQL schema definition language (SDL). Polywrap's GraphQL variant is simpler than standard GraphQL and easy to learn.
Custom types are declared with the
type keyword. They can be given any number of properties. Properties can be of
any supported type, including other custom types.
As in standard GraphQL, properties, method arguments, and method return values are declared non-nullable by appending
! at the end of the type name.
The absence of a
! indicates that a value is nullable.
Methods are declared within the
Module type. Methods must return a value.
Custom types and modules can be imported from other wrappers by placing an import statement at the top of the schema. Imports become available in the schema immediately and in the wrapper following codegen.
Imported types and modules must be assigned a namespace. References to them are prepended with the namespace.
The following example uses all of the elements we've discussed so far.
Polywrap's schema definition language supports three kinds of default types:
- Basic types like integers and strings
- Complex types like BigInt and JSON
- Generic types like Array and Map
These types may be implemented differently in different programming languages. The language-specific implementations are clarified in each of the following sections.
Basic types include primitive types like integers and boolean values, as well as Strings and Bytes.
- Wasm wrapper
|UInt||32-bit unsigned integer|
|UInt8||8-bit unsigned integer|
|UInt16||16-bit unsigned integer|
|UInt32||32-bit unsigned integer|
|Int||32-bit signed integer|
|Int8||8-bit signed integer|
|Int16||16-bit signed integer|
|Int32||32-bit signed integer|
|Boolean||True or false stored as 1 byte|
|Bytes||Array of 8-bit unsigned integers|
|UInt||number||Coming soon...||Coming soon...|
|UInt8||number||Coming soon...||Coming soon...|
|UInt16||number||Coming soon...||Coming soon...|
|UInt32||number||Coming soon...||Coming soon...|
|Int||number||Coming soon...||Coming soon...|
|Int8||number||Coming soon...||Coming soon...|
|Int16||number||Coming soon...||Coming soon...|
|Int32||number||Coming soon...||Coming soon...|
|String||string||Coming soon...||Coming soon...|
|Boolean||boolean||Coming soon...||Coming soon...|
|Bytes||Uint8Array||Coming soon...||Coming soon...|
Complex types are represented as basic types to the Polywrap client and plugin wrappers. Within Wasm wrappers, they are implemented as classes or structs with behavior.
If the invoked method requires an argument of type
BigInt, the application developer will provide a
representation of an integer number to satisfy the argument.
Within the wrapper, the
string is deserialized into an instantion of the wrapper language's implementation of a
If the invoked method returns a
BigInt, the wrapper will serialize the returned
which the client will then deserialize into a
string before returning it to the application developer.
- Wasm wrapper
|BigInt||Multiple precision integer|
|BigNumber||Multiple precision float|
|BigInt||string||Coming soon...||Coming soon...|
|BigNumber||string||Coming soon...||Coming soon...|
|JSON||string||Coming soon...||Coming soon...|
|BigNumber||BigNumber||bigdecimal::BigDecimal as BigNumber||Coming soon...|
|JSON||JSON.Value||serde_json::Value as JSON::Value||Coming soon...|
When using a generic type, with the exception of arrays, schema writers must add a directive annotation declaring its subtype(s).
The directive takes the form
@annotate(type: "TypeName<T\>"), where
T is the type of the subtype.
The generic type and its subtype(s) can be independently nullable or non-nullable.
The following example illustrates use of the generic type directive with the
Like complex types, the implementation of generic types can differ by language.
- Wasm wrapper
|[Type]||Array of elements.|
|Map||Map of key-value pairs.|
|[Type]||Array<Type>||Coming soon...||Coming soon...|
|Map||Map<K,V>||Coming soon...||Coming soon...|
|Map||Map<K, V>||BTreeMap<K, V>||Coming soon...|
A module can inherit the method declarations of any other module by using the
A module that implements an interface in this manner is required to implement and export the interface module's declared methods.
Similarly, a type can inherit the property declarations of any other type by using the
If a type implements an interface, it inherits the interface type's property declarations as though the properties
were declared explicitly.
Wrapper developers can declare a map of environmental variables for application developers to provide. To use environmental variables, declare an
Env type and add a directive to each schema method that will use it.
You can learn how to access environmental variables in code by reading the Access Env in the module section of our Environmental Variables documentation for wrapper developers.
#Declare the Env object
Environmental variables are declared in a custom type named
#Add the @env directive
To access an
Env object during a method invocation, add the
@env directive to a method. The
@env directive has one attribute that indicates whether the
Env is required or optional.