API

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.

Entry Objects and Masks

Status of Entries

Validation Functions

Validation Packaging

 

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.

 

expand_less Supported Languages

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)

You can write Holochain application code using Otto JavaScript. Most of the Otto flavor of the JavaScript language is described on the project's README page. Please note this is NOT a full implementation of JavaScript, and is missing a number of things you may be used to having, such as timer functions or access to a DOM. Because your app runs inside a scripting shell inside a Go program, most of those things don't make any sense in this context anyway. If you prefer, you can also write code in another language (or ES version) that compiles to JavaScript ES5 code. The code will need to be recompiled each time changes are made.

 

Functions

property(name)

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

expand_less JS example
var language = property("language")

 

makeHash(entryType, entryData)

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 getThe 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

expand_less JS example
var hash = makeHash("profile", {firstName:"Zippy", lastName:"Pinhead"})
debug(hash)
// QmYeinX5vhuA91D3v24YbgyLofw9QAxY6PoATrBHnRwbtt

 

debug(value)

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

expand_less JS example
var hash = makeHash({firstName:"Zippy", lastName:"Pinhead"})
debug(hash)
// QmYeinX5vhuA91D3v24YbgyLofw9QAxY6PoATrBHnRwbtt

 

call(zomeName, functionName, arguments)

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

expand_less JS example
call("clutter", "post", {message: "this is a message"})

 

bridge(appDNAHash, zomeName, functionName, arguments)

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 -bridgeSpecsand 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

expand_less JS example
bridge(
  "QmY8Mzg9F69e5P9AoQPYat655HEhc1TVGs11tmfNSzkqh2",
  "holodex",
  "index",
  {message: "this is a message"}
)

 

getBridges()

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.Callerdepending 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 a CalleeApp property with a hash of the app bridged to, and CalleeName, 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 a Token property with the value of the token that gives access to Caller app.

expand_less JS example
debug(JSON.stringify(getBridges()))
/*
[
  {"Side": 0, "CalleeName": "clutter", "CalleeApp": "QmY8Mzg9F69e5P9AoQPYat655HEhc1TVGs11tmfNSzkqto"},
  {"Token":"0393828348751323", "Side": 1 }
]
*/

 

sign(doc)

Uses the agent's private key to sign some contents. 

doc: string

Returns: string OR error

 

verifySignature(signature, data, pubKey)

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. pubKeyshould be a public key.

signature: string

data: string

pubKey: string

Returns: boolean OR error

 

commit(entryType, entryData)

Attempts to commit an entry to your local source chain. It will cause callback to your validateCommitfunction. 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 linksentry object looks like this

{ Links: [ { Base: "2bDja...", Link: "Fb4aXa...", Tag: "links to" } ] }

Base and Linkmust both be type hash. Tagcan be any string, describing the relationship between Base and LinkTagwill later be used in getLinks. It may optionally contain a 4th property LinkActionwhich should be set to HC.LinkAction.Delin order to mark the link as deleted. See the examples below.

entryType: string

entryData: any-type

Returns: hash-string OR error

expand_less JS examples
/* 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;
}

 

update(entryType, entryData, replaces)

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 Modifiedstatus 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

expand_less JS example
function updatePost(oldHash) {
  var hash = update("post", {message: "this is a message"}, oldHash)
  return hash
}

 

updateAgent(options)

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

expand_less JS example
updateAgent({Identity:"[email protected]",Revocation:"sample revocation reason"})

 

remove(entry, message)

Commits a DelEntry to the local chain with given delete message, and, if the entry type of entry is not private, moves the entry to the Deleted status on the DHT.

entry: hash-string

message: string

Returns: hash-string

expand_less JS example
function removePost(oldHash) {
  var hash = remove(oldHash)
  return hash
}

 

get(hash [, options])

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.StatusMaskStatus-int

options.GetMaskMask-int

options.Localboolean

options.Bundleboolean

Returns: Entry-object OR HC.HashNotFound

expand_less JS examples
// 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
}

 

 

query([options])

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. HashEntry, 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

expand_less JS examples
// 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>

 

send(to, message [,options])

Sends a message to a node, using the App.Key.Hash of that node, its permanent address in the DHT. The return value of this function will be whatever is returned by the receive function on the receiving node. Alternatively, you can indicate that this call should be made asynchronously, and specify the callback function using these properties:

options.Callback.Function: the name of a function to call back when the call completes or times out.

options.Callback.ID: an id that will be passed to your callback function to identify the particular call

to: hash-string (see App.Key.Hash)

message: object

options: object

options.Callback: object (optional)

options.Callback.Function: string

options.Callback.ID: string

Returns: any-type

expand_less JS example
// Synchronous send:
var agentHash = send(toHash,{type:"ping"})

function receive(from, msg) {
  var type = msg.type;
  if (type=="ping") {
    return App.Agent.Hash
  }
  return "unknown type"
}

// Asynchronous send:
function asyncPing(message, id) {
  debug("async result of message id "+id+" was: "+JSON.stringify(message))
}
send(destHash, {ping: "foobar"}, {Callback: { Function: "asyncPing", ID:"123"}})
// async result of message id 123 was: QmVGtdTZdTFaLsaj2RwdVG8jcjNNcp1DE914DKZ2kHmXHx

 

receive(from, message)

This function gets called by the system when a message is received by a node. The return value of the function will be sent back to the sender and will be the result of the send function that sent the message. The value you return from this function will be sent back to the node that sent you the message.

from: hash-string

message: string

Return: any-type

expand_less JS example
// Synchronous send:
var agentHash = send(toHash,{type:"ping"})

function receive(from, msg) {
  var type = msg.type;
  if (type=="ping") {
    return App.Agent.Hash
  }
  return "unknown type"
}

// Asynchronous send:
function asyncPing(message, id) {
  debug("async result of message id "+id+" was: "+JSON.stringify(message))
}
send(destHash, {ping: "foobar"}, {Callback: { Function: "asyncPing", ID:"123"}})
// async result of message id 123 was: QmVGtdTZdTFaLsaj2RwdVG8jcjNNcp1DE914DKZ2kHmXHx

 

genesis()

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

 

bridgeGenesis(side, dna, appData)

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

 

validateCommit(entryType, entry, header, package, sources)

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

 

validatePut(entryType, entry, header, package, sources)

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.

entryTypestring

entryany-type

headerHeader-object

packagePackage-object

sourcesarray-of-string

Return: boolean

 

validateMod(entryType, entry, header, replaces, package, sources)

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.

entryTypestring

entryany-type

headerHeader-object

replaceshash-string

packagePackage-object

sourcesarray-of-string

Return: boolean

expand_less JS example
// 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
}

 

validateDel(entryType, hash, package, sources)

This function gets called as a consequence of a del command being issued. For more background, read the Validation Functions section.

entryTypestring

hashhash-string

packagePackage-object

sourcesarray-of-string

Return: boolean

 

validateLink(entryType, hash, links, package, sources)

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.

entryTypestring

hashhash-string

links: array-of-Link-object

packagePackage-object

sourcesarray-of-string

Return: boolean

 

validatePutPkg(entryType)

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.

entryTypestring

Return: PkgReq-object OR nil

 

validateModPkg(entryType)

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

 

validateDelPkg(entryType)

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.

entryTypestring

Return: PkgReq-object OR nil

 

validateLinkPkg(entryType)

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.

entryTypestring

Return: PkgReq-object OR nil

 

bundleStart(timeout, userParam)

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).

timeoutinteger

userParamany-type

Returns: nil

Note: bundling is an experimental feature and may be deprecated

 

bundleClose(commit)

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) .  

commitboolean

Returns: nil

Note: bundling is an experimental feature and may be deprecated

 

bundleCanceled(reason, userParam)

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.HashbecomesApp_DNA_Hash).

System globals and constants

 

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: LiveDeletedModifiedRejectedAnyfor use with StatusMask when getting entries or links.

 

HC.GetMask 

Object with get option value constants: DefaultEntryEntryTypeSourcesAll

 

HC.LinkAction 

Object with link action value constants: AddDel for use when committing Links entries.

 

HC.PkgReq 

Object with package request constants: ChainChainOptEntryTypes

 

HC.PkgReq.ChainOpt

Object with package request Chain request constants: NoneHeadersEntriesFull (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.

 

Application globals
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.