6.5 KiB
layout | permalink |
---|---|
learn | /:collection/:path.html |
How to create a Collection type
{:.no_toc}
Collections support data portability between applications. Blockstack supplies a Contact
collection for use by Blockstack applications. Developers can create additional collection types, use them in their own applications, and publish them so other developers can make use of them too.
In this section, you learn the coding guidelines for creating and publishing a new Collection
type. The following topics are included:
- TOC {:toc}
Before you begin
New collections rely on the blockstack-collections
package. Before you code, make sure you have installed this package and it is available to your project.
npm install -g blockstack-collections
You should also familiarize yourself with the Collection class and review the existing Collection types. Keep in mind, someone else may have already added a custom type similar to what you want to add.
Collection types can be written in .js
Javascript or .ts
(Typescript) files. Typescript is a typed superset of Javascript, you can read the language documentation to learn more.
Essential steps for creating a Collection type
This section demonstrates how to create a new collection type using Typescript. While this is written in Typescript, the steps in Javascript are the same. Follow these steps to create a new collection type:
-
Create a new
.ts
file and open it for editing. -
Import the
Collection
class.import { Collection, Attrs, Serializable } from 'blockstack-collections'
-
Extend the abstract
Collection
class from theblockstack-collections
package.export class Contact extends Collection implements Serializable { ... }
-
Give your
Collection
a unique identifier.The Blockstack Collection frameworks uses this identifier to place Collection data into a corresponding Gaia storage bucket.
static get collectionName(): string { return 'contact' }
{% include warning.html content="While you must specify a unique identifier, the Blockstack platform does not currently enforce uniqueness. If your
Collection
type shares the same identifier as another type, it will lead to data corruption for the user. In the future, the Blockstack platform will enforce unique collection names. " %} -
Define a static
schema
constant.This is your type's schema.
static schema = { identifier: String, firstName: String, lastName: String, blockstackID: String, email: String, website: String, address: String, telephone: String, organization: String }
-
Determine if you need to set the
singleFile
storage flag.By default, the
singleFile
flag is false. This setting causes every record in a collection to store in Gaia as a separate file. The default works well for larger types that describe data such as documents or photos. If yourCollection
type only has a few fields and is not expected to have a large number of records, set thesingleFile
data format flag totrue
.static singleFile = true
-
Define the
fromObject
andfromData
serializaiton methods.These methods serialize and deserialize your
Collection
type. You can use any serialization method you want. Data encryption is handled automatically by the parentCollection
class, so you should not perform any additional encryption.In the following example code, data is converted to JSON string for storage.
static fromObject(object: object) { // Create from plain Javascript object return new Contact(object) } static fromData(data: string) { // Deserialize JSON data return new Contact(JSON.parse(data)) } serialize() { // Serialize to JSON string return JSON.stringify(this.attrs) }
-
Test and iterate development of your type in your application.
-
Publish your type for others to use.
Add a listener (optional)
If you need to listen for changes to any of the object’s attributes, you can implement the onValueChange
method. For example, in the Contacts
Collection type, when the contact is renamed, the unique identifier for the object needs to be updated.
onValueChange(key: string, value: any) {
if (key === 'firstName') {
this.previousIdentifier = this.attrs.identifier
this.attrs.identifier = this.constructIdentifier()
this.identifierChanged = true
}
else if (key === 'lastName') {
this.previousIdentifier = this.attrs.identifier
this.attrs.identifier = this.constructIdentifier()
this.identifierChanged = true
}
}
Override processing methods (optional)
To perform additional processing of a collection, you can override the get
, save
, list
and delete
methods. For example, in the Contact
type, the save
method is overridden to also perform a delete
if a contact is renamed. Deletion is necessary because identifiers for a Contact
are generated from the contact name. And data stored under the previous identifier must be deleted after writing to a new identifier.
async save(userSession?: UserSession) {
// Delete old file on save if object identifier changes
return super.save(userSession)
.then((result) => {
if (this.identifierChanged) {
return Contact.delete(this.previousIdentifier, userSession)
.then(() => {
this.identifierChanged = false
return result
})
} else {
return result
}
})
}
Publish your new type for others to use
While you can use your collection exclusively in your application, the Collections feature is intended to enable data portability between DApps. So, you should publish your new type so other developers can make use of it.
To publish your Collection type, do the following:
- Clone or fork the blockstack-collections repo.
- Add your new type file to the
src/types
subdirectory. - Create a pull request back to the
blockstack-collection
repository.