Skip to section
Native Functions | Required Callbacks | Optional Callbacks |
property | genesis | bridgeGenesis |
makeHash | validateCommit | receive |
debug | validatePut | bundleCanceled |
call | validateMod | |
bridge | validateDel | Globals and Constants |
getBridges | validateLink | System Constants |
sign | validatePutPkg | Application Globals |
verifySignature | validateModPkg | |
commit | validateDelPkg | |
get | validateLinkPkg | |
getLinks | ||
update | ||
updateAgent | ||
remove | ||
query | ||
send | ||
bundleStart | ||
bundleClose |
Introduction
With familiarity with configuring the application DNA already, we can cover how to getting into writing the actual code for a Holochain application.
In Holochain, the unique application logic is stored in folders known as Zomes. Zomes can contain code written (currently) in either JavaScript or Lisp. A Zome contains implementations of a few different methods required to perform the application functions by reading and writing chains. Your code can also call built-in API helper functions. Following is an API reference containing documentation on all of the API functions and top-level considerations in working with the Holochain API.
All Ribosome types provide access to the same Holochain API, which consists in a set of functions that allow you as a Holochain app developer to commit entries to your chain, put or get data from the DHT, and expose functions to a UI or to other bridged Holochain applications.
There are a number of articles that help explain this part of application development. We encourage checking out the ones that pique your interest.
HoloWorld Tutorial: Writing Functions
HoloWorld Tutorial: Sharing to the DHT
Once you've developed familiarity with this aspect of app development, the next step is to check out how to test your code, and use test-driven development patterns.
Lisp (Zygomys)
You can write Holochain application code using the Zygomys flavor of Lisp. Here is the language reference for the commands you can use in Zygo Lisp.
JavaScript (ES5)
Functions
Returns an application property, which are defined by the app developer. It returns values from the DNA file that you set as properties of your application (e.g. Name, Language, Description, Author, etc.).
name: string
Returns: string OR error
var language = property("language")
Use this function to make a hash of the given entry data. This is the same hash value that would be returned if entryData
were passed to commit
and by which an entry of this type would be retrievable from the DHT using get
. The type of the entryData
parameter depends on the entry format of entry. If it's a string entry format then the type must be string. If it's a JSON entry format, then it can be any type, and the value will get appropriately converted to JSON. If it is a links format entry, then the type must by a JSON object.
entryType: string
entryData: any-type
Returns: hash-string OR error
var hash = makeHash("profile", {firstName:"Zippy", lastName:"Pinhead"}) debug(hash) // QmYeinX5vhuA91D3v24YbgyLofw9QAxY6PoATrBHnRwbtt
Sends output to the debugging log. The type of value
is arbitrary and will get converted to a string according to the language conversion limitations.
value: any-type
Returns: void
var hash = makeHash({firstName:"Zippy", lastName:"Pinhead"}) debug(hash) // QmYeinX5vhuA91D3v24YbgyLofw9QAxY6PoATrBHnRwbtt
Calls an exposed function from another zome. arguments
is a string or an object depending on the CallingType
that was specified in the function's definition in the DNA. Returns the value that's returned by the given function.
zomeName: string
functionName: string
arguments: string OR object
Returns: any-type OR error
call("clutter", "post", {message: "this is a message"})
Calls a bridged function from another app. appDNAHash
is the application being called. Note that the application must have explicitly been bridged. In development use hcdev
's -bridgeSpecs
and a bridge_specs.json
file to setup bridging. Just like in send
, the arguments
parameter is a string or an object/hash depending on the CallingType that was specified in the function's definition. Returns the value that's returned by the given function on the other side of the bridge.
appDNAHash: hash-string
zomeName: string
functionName: string
arguments: string OR object
Returns: any-type
bridge( "QmY8Mzg9F69e5P9AoQPYat655HEhc1TVGs11tmfNSzkqh2", "holodex", "index", {message: "this is a message"} )
This function allows your app to examine which bridges have been put in place.
Returns
An array of objects with aSide
property that will be either: HC.Bridge.Callee
or HC.Bridge.Caller
depending which side of the bridge the app is on.
-
If
Side
is Callerr, i.e. this is the app making calls over the bridge, then object will also contain aCalleeApp
property with a hash of the app bridged to, andCalleeName
, with the name of the app bridged to. -
If
Side
is Callee, i.e. this is the app receiving calls over the bridge, then object will also contain aToken
property with the value of the token that gives access to Caller app.
debug(JSON.stringify(getBridges()))
/*
[
{"Side": 0, "CalleeName": "clutter", "CalleeApp": "QmY8Mzg9F69e5P9AoQPYat655HEhc1TVGs11tmfNSzkqto"},
{"Token":"0393828348751323", "Side": 1 }
]
*/
Uses the agent's private key to sign some contents.
doc: string
Returns: string OR error
Uses the signature, data and signatory's public key to verify the sign in contents of data
. Result represents whether its a match or not. pubKey
should be a public key.
signature: string
data: string
pubKey: string
Returns: boolean OR error
Attempts to commit an entry to your local source chain. It will cause callback to your validateCommit
function. Returns either an error or the hash of the committed entry upon success. The type of the entryData
parameter depends on the entry format of entry. If it's a string entry format then the type must be string. If it's a JSON entry format, then it can by any type, and the value will get appropriately converted to JSON. If it is a links format entry, then the type must by a JSON object.
A links
entry object looks like this
{ Links: [ { Base: "2bDja...", Link: "Fb4aXa...", Tag: "links to" } ] }
Base
and Link
must both be type hash. Tag
can be any string, describing the relationship between Base
and Link
. Tag
will later be used in getLinks. It may optionally contain a 4th property LinkAction
which should be set to HC.LinkAction.Del
in order to mark the link as deleted. See the examples below.
entryType: string
entryData: any-type
Returns: hash-string OR error
/* This is an example of a function you might have in your code for committing a "post" entry in a blog or social-media-sharing type of app. It illustrates two aspects of committing data to your local chain. The first is committing a regular "data" style entry, and the second is committing Holochain's links type entry. When you commit a post, you would probably also want to commit links on your identity hash for people to be able to look up a list of your posts. Make sure that you complete the proper validation functions too. For the first commit, you will need to check your validateCommit and validatePut functions, for the second commit, you'll need to check validateCommit, validatePut, and validateLink. */ function createPost(post) { // Commit post entry to my source chain var hash = commit("post",post); // On the DHT, put a link from my hash to the hash of the new post var me = App.Agent.Hash; commit("post_links",{ Links: [ {Base: me,Link: hash, Tag: "post"} ] }); // Returns the hash of the new post to the caller return hash; } // Note that if you want to "remove" a links type entry, you also use commit. That looks something like this: function removePost(postHash) { // Use remove to remove the post entry remove(postHash); // On the DHT, mark the links as deleted var me = App.Agent.Hash; commit("post_links",{ Links: [ { Base: me, Link: postHash, Tag: "post", LinkAction: HC.LinkAction.Del } ] }); // return success return true; }
Attempts to commit an entry to your local source chain that "replaces" a previous entry. If entryType
is not private, update
will movereplaces
to a Modified
status on the DHT. Additionally the modification action will be recorded in the entries' header in the local chain, which will be used by validation routes.
entryType: string
entryData: string OR object
replaces: hash-string
Returns: hash-string OR error
function updatePost(oldHash) { var hash = update("post", {message: "this is a message"}, oldHash) return hash }
Commits a new agent entry to the chain, with either or both new identity information or a new public key, while revoking the old key. If revoking a key, also adds that key to the node blockedlist (which is also gossiped), as it's no longer a valid peer address.
options: object
options.Revocation: Revocation-Data-string
options.Identity: Identity-Info-string
Returns: hash-string OR error
updateAgent({Identity:"newemail@example.com",Revocation:"sample revocation reason"})
This function retrieves an entry from the local chain or the DHT. If options.StatusMask
is present, it determines which entries to return, depending on their status. If options.GetMask
is present, this option allows you to specify what information about the entry you want. For more on that, see Entry Objects and Masks.
If options.Local
is set to true, it indicates that the get refers to the local chain only. This allows you to retrieve specific entries from your chain, which includes private entries that aren't published to the DHT.
If options.Bundle
is set to true, it indicates that the get refers to the currently started bundle only. If no bundle has been started, returns an error.
If only StatusMask
value specified or only Entry
is specified the return value will be the actual entry value. Otherwise the return value will be an object with properties of the same name as the mask name.
hash: hash-string
options: object (optional)
options.StatusMask: Status-int
options.GetMask: Mask-int
options.Local: boolean
options.Bundle: boolean
Returns: Entry-object OR HC.HashNotFound
// Assume postHash is the hash of a previous post. In this example we do a simple get with no options: var r = get(postHash) debug(r) // "I can haz cheezburger?" // In this example we do a "get" with "GetMask" options: var r = get(postHash, { GetMask: HC.GetMask.Entry + HC.GetMask.EntryType }) debug(r) /* { "Entry":"I can haz cheezburger?", "EntryType":"meow" } */ // There is a scenario where no entry is found matching the hash, you should usually check it var r = get(postHash) if (r === HC.HashNotFound) { // handle hashNotFound case } else { // do something with the entry }
Retrieves a list of links tagged as tag
on base
from the DHT. If tag
is an empty string it will return all the links on the base
and the list will also include the Tag property on entries. With options as {Load: false}
(which is the default) returns a list of the form [{Hash:"QmY..."},..]
With options as {Load: true}
it will get the entry values of the links and return a list of the form [{Hash:"QmY...",EntryType:"<entry-type>",Entry:"<entry value here>",Source:"<source-hash>"},..]}
. Use options.StatusMask
to return only links with a certain status. Default is to return only Live links. You can use defined constants HC.Status.Live/Deleted/Rejected
as the int value.
base: hash-string
tag: string
options: object
options.Load: boolean (default: false)
options.StatusMask: Status-int (default: HC.Status.Live)
Returns: array-of-Entry-object OR error
var links = getLinks(base, tag, { Load: true })
Keep in mind that you will want to retrieve most data from the DHT (shared data space), so that you are seeing what the rest of the nodes on your Holochain are seeing. However, there are times you will want to query private data fields, or package up data from your source chain for sending. In those cases you can use this function. query
returns a list whose contents depend on what was chosen in the Returns
option. If a single option was chosen, then it will be a bare list consisting of that item type. If more than than one return option was chosen, then it will be a list of items whose key will be the singular name of that option, i.e. Hash
, Entry
, or Header
. See the examples below for reference.
options: object
options.Return: object
options.Return.Hashes: boolean
options.Return.Entries: boolean (default: true)
options.Return.Hashes: boolean
options.Constrain: object
options.Constrain.EntryTypes: array-of-string
options.Constrain.Contains: string
options.Constrain.Equals: string
options.Constrain.Matches: regex
options.Constrain.Count: int
options.Constrain.Page: int
options.Order.Ascending: boolean (default: false)
options.Bundle: boolean
Returns: array-of-Query-object OR error
// Here is an example of choosing a single Return option: var result = query({ Return: { Hashes: true }, Constrain: { EntryTypes: ["posts"] } }) debug(result) /* [ "QmSwMfay3iCynzBFeq9rPzTMTnnuQSMUSe84whjcC9JPAo", "QmfMPAEdN1BB9imcz97NsaYYaWEN3baC5aSDXqJSiWt4e6" ] */ // Here is an example of choosing multiple Return options: var result = query({ Return: { Hashes: true, Entries: true }, Constrain: { EntryTypes: ["posts"], Count:1 } }) debug(result) /* [ { "Entry": {"message":"this is my test post"}, "Hash": "QmSwMfay3iCynzBFeq9rPzTMTnnuQSMUSe84whjcC9JPAo" } ] */ // Here is an example of searching for content in JSON structured entries: var result = query({ Constrain: { EntryTypes: ["posts"], Contains: "{\"message\": \"test\"}" } }) debug(result) // [{"message": "this is my test post"}, {"message": "I passed the test!"}]
Not Yet Implemented
There are some intended options that have not yet been implemented and are scheduled for completion in alpha 2.
options.Constrain.AfterHash: hash-string (non-inclusive)
options.Constrain.BeforeHash: hash-string (non-inclusive)
options.Constrain.Negate: boolean (default: false)
options.Order.Criteria: ByDate|ByField:<fieldname>
Each zome must include this function, which is called during system genesis. It executes just after the initial genesis entries are committed to your chain (1st - DNA entry, 2nd Identity entry). It enables you specify any additional operations you want performed when a node joins your holochain, for example, you may want to add some user/address/key information to the DHT to announce the presence of this new node. This function must return true if it is to succeed, and the application to start successfully.
Return: boolean
All zomes which expose functions for bridging from other applications MUST also define a bridgeGenesis function (i.e. the "Bridge-To" side). Zomes which want to call functions in other applications MAY define a bridgeGenesis function and declare that they do so by setting the Zome.BridgeTo value in their DNA.
This function will be called just once when bridging is established. This allows applications to do any initialization which might be required for the bridging to operate. For example the holodex indexing mixin zome registers the node as an indexing node in the bridgeGenesis function.
side
will be an integer indicating if this is a "from" or a "to" call. The constants HC.Bridge.From and HC.Bridge.To are defined with the appropriate integer values. dna
will be the hash of the dna on the other side of the bridge. appData
will be user specified data provided at bridge time. This function must return true if it is to succeed, and the bridge to form successfully.
side: int
dna: hash-string
appData: string
Return: boolean
This function gets called when an entry is about to be committed to a source chain. Use this function to describe the agreements about data as it should be added to shared Holochain. This function gets called for all entry types. For more background, read the Validation Functions section.
entryType: string
entry: any-type
header: Header-object
package: Package-object
sources: array-of-string
Return: boolean
This function gets called when an entry is about to be committed to the DHT on any node. It is very likely that this validation routine should check the same data integrity as validateCommit, but, as it happens during a different part of the data life-cycle, it may require additional validation steps. This function will only get called on entry types with "public" sharing, as they are the only types that get put to the DHT by the system. For more background, read the Validation Functions section.
entryType: string
entry: any-type
header: Header-object
package: Package-object
sources: array-of-string
Return: boolean
This function gets called as a consequence of a mod
command being issued. replaces
is the hash of the entry being replaced. For more background, read the Validation Functions section.
entryType: string
entry: any-type
header: Header-object
replaces: hash-string
package: Package-object
sources: array-of-string
Return: boolean
// Often you may be validating that only the agent who committed an entry can modify it. // Such a validation routine might look like this: function validateMod(entry_type, entry, header, replaces, pkg, sources) { var valid = false if (entry_type === "your_type") { var orig_sources = get(replaces, { GetMask: HC.GetMask.Sources }) // Note: error checking on this is removed for simplicity valid = (orig_sources.length === 1 && orig_sources[0] == sources[0]) } return valid }
This function gets called as a consequence of a del
command being issued. For more background, read the Validation Functions section.
entryType: string
hash: hash-string
package: Package-object
sources: array-of-string
Return: boolean
This function gets called when ever links are being written to the DHT. Links are added for every linking element in the special "links" entry type. Note that this is a DHT level validation routine, in that it gets called when the Link message is received by a DHT node, not when the linking entry is committed. The regular validateCommit routine gets called as usual when that linking entry is committed to the source chain. For more background, read the Validation Functions section.
entryType: string
hash: hash-string
links: array-of-Link-object
package: Package-object
sources: array-of-string
Return: boolean
This function should simply return nil if the data required by its corresponding validation function is just the minimum default of the Entry and Header of the action. Otherwise this function must return a "Package Request" object, which specifies what data to be sent to the validating node. For more background, read the Validation Packaging section.
Note that a commit
action will trigger a call to validatePutPkg locally when committing happens as validateCommit must have the same data available to it as does validatePut.
entryType: string
Return: PkgReq-object OR nil
This function should simply return nil if the data required by its corresponding validation function is just the minimum default of the Entry and Header of the action. Otherwise this function must return a "Package Request" object, which specifies what data to be sent to the validating node. For more background, read the Validation Packaging section.
entryType: string
Return: PkgReq-object OR nil
This function should simply return nil if the data required by its corresponding validation function is just the minimum default of the Entry and Header of the action. Otherwise this function must return a "Package Request" object, which specifies what data to be sent to the validating node. For more background, read the Validation Packaging section.
entryType: string
Return: PkgReq-object OR nil
This function should simply return nil if the data required by its corresponding validation function is just the minimum default of the Entry and Header of the action. Otherwise this function must return a "Package Request" object, which specifies what data to be sent to the validating node. For more background, read the Validation Packaging section.
entryType: string
Return: PkgReq-object OR nil
This function begins a bundle. Any subsequent commits made will not be added to the chain or sent to the DHT until a call to bundleClose(true)
is made or a the bundle is canceled by a call to bundleClose(false).
timeout: integer
userParam: any-type
Returns: nil
Note: bundling is an experimental feature and may be deprecated
This function closes a bundle either by finilizing any commits made since the bundle was open (if the commit
parameter is true
) or discarding the bundle (if the commit
parameter is false
) .
commit: boolean
Returns: nil
Note: bundling is an experimental feature and may be deprecated
This is a callback that will be called by the system when a bundle is about to be canceled. The reason
parameter will hold a value indicating the reason the bundle is being canceled. Currently the only implemented reason is HC.BundleCancel.Reason.UserCancel.
reason: HC.BundleCancel.Reason.UserCancel
userParam: <value of userParam passed into bundleStart()>
Return: HC.BundleCancel.Response.OK OR HC.BundleCancel.Response.Commit
Cancel can be canceled by returning HC.BundleCancel.Response.Commit in which case the bundle will be commited instead of canceled.
Note: bundling is an experimental feature and may be deprecated
Constants and Application Variables
There are two kinds of values that are available to your application: system globals and app specific values. They are displayed below using the dot notation used in JavaScript. To access these values in the Lisp ribosome replace the dots with underscores (soApp.DNA.Hash
becomesApp_DNA_Hash
).
HC.Version
Contains a string with the version of the Holochain software
HC.HashNotFound
A constant value returned by the get function if the hash provided could not be found.
HC.Status
Object with status value constants: Live
, Deleted
, Modified
, Rejected
, Any
for use with StatusMask
when getting entries or links.
HC.GetMask
Object with get option value constants: Default
, Entry
, EntryType
, Sources
, All
HC.LinkAction
Object with link action value constants: Add
, Del
for use when committing Links entries.
HC.PkgReq
Object with package request constants: Chain
, ChainOpt
, EntryTypes
HC.PkgReq.ChainOpt
Object with package request Chain
request constants: None
, Headers
, Entries
, Full
(see validation for example uses of these package request constants)
HC.Bridge
Object with constant that will be passed to bridgeGenesis in the side
parameter, or will be returned by getBridges: From
, To
.
HC.SysEntryType
Object with system entry type constants: DNA
, Agent
, Key
, Headers, Del
HC.BundleCancel.Reason
Object with constant that will be passed into bundleCanceled in the reason
parameter: UserCancel
and Timeout
.
HC.BundleCancel.Response
Object with constants one of which must be returned from a call to the bundleCanceled callback: Commit
, OK
.
App.Name
Holds the Name of this Holochain from the DNA.
App.DNA.Hash
Holds the unique identifier of this Holochain's DNA. Nodes must run the same DNA to be on the same Holochain.
App.Agent.Hash
Holds your peer's identity info on the DHT. This is the hash for the second entry (identity info) on your chain.
App.Key.Hash
Holds the hash of your public key. This is your node address on the DHT. It can be used for node-to-node messaging with send
and receive
functions.
App.Agent.TopHash
Holds the most recent agent indentity entry that has been committed to the chain. To start with its value is equivalent to App.Agent.Hash
after a call to updateAgent it will have the value of the newly committed agent entry.
App.Agent.String
Holds the identity string used to initialize the holochain software with hcadmin init If you used JSON to embed multiple properties (such as FirstName, LastName, Email, etc), they can be retrieved here as App.Agent.FirstName, etc.