Make sure that you’ve completed the last HoloWorld tutorial step of writing the application DNA.
Recall that while writing the application DNA, in dna.json, we declared two functions called holoTextWrite
and holoTextRead
and an entry type called holoText
. In this tutorial, we will implement those functions, and any others needed in order to make our app function.
With a text editor, open up the dna/readerWriter/readerWriter.js file. To maximize learning, let’s start by removing all the code from the file. Delete it all, don’t worry.
The code we will write in this file is responsible for multiple things:
- Defining a small number of functions required by Holochain to function (the "required callbacks")
- Defining any validation rules of the application
- Defining any custom functions implemented by an application
When writing code, we have access to the entire suite of "native functions" that Holochain provides. We use some of these functions to read and write data.
Sidenotes:
- Holochain currently only supports ES5 JavaScript syntax, if you want to use the latest syntax, use a transpiler
- Each time it calls a function in this file, Holochain runs the code in a sandboxed way in a virtual machine, so nothing can be held in memory
Genesis
The first step to take in our code file is to implement the critical genesis
function. This is the one function which Holochain requires you to implement for each Zome. It is a function which is called the first time any individual attempts to run a Holochain application, and it provides an opportunity for any setup to occur, and any validation rules to execute to check whether the user is able to join the app. It must return true or false. For HoloWorld, we have nothing special to define here, but we must add it regardless, and return true.
Add the following at the very top of the file
function genesis() { return true }
holoTextWrite
Next we will implement our first custom function, holoTextWrite
, which will take a string of text as an input, and write it to our local source chain.
Below the genesis function we defined, add a new function by adding the code below:
function holoTextWrite() {}
Provide an input for the function by adding it between the parentheses, so the code looks like this:
function holoTextWrite(text) {}
Now some background. When an entry gets written to the source chain, it gets assigned a "hash". The hash is generated by using a hashing algorithm (whichever one is specified in the dna file under DHTConfig.HashType, such as sha2-256) on the combination of two things: the entry type, and the entry contents. The data is also signed using the private key of the current user/agent. When attempting to write something to the chain, we call the native function commit.
We can simply call the native functions from anywhere in our code, without doing anything fancy like "importing" it. Make your function look like this:
function holoTextWrite(text) { var hash = commit('holoText', text) }
We declare a variable, hash, to store the result of calling commit. The first parameter we pass commit is the entry type we are adding, as declared in our DNA file, holoText
. The second parameter we pass to commit is the variable text, which was passed as the input to the function.
!!The following is very important!!
A very important aspect of Holochain, as a platform for P2P applications to be built with, is the concept of data validation. Validation occurs at many points, but it all begins with commit, since commit is where data is originally authored to a chain. Every time that your application triggers a call to commit, Holochain will also perform a built in call to another function which you must implement, called validateCommit. You only need to define validateCommit if you utilize commit. Let’s finish authoring holoTextWrite, and then define validateCommit.
If commit succeeds, it will return a hash. In turn, we should make our function use this hash as the value that it returns, so that the caller has the value with which it can be retrieved again, similar (but different!) to its ID in a standard database.
Modify your function so it looks like this:
function holoTextWrite(text) { var hash = commit('holoText', text) return hash }
The function is complete, except we need to perform the required validation that was mentioned before it will work!
Because at this point in time, we have no special validation rules, implementing validateCommit is very simple. We just need it to return true. Add the following function definition in between the genesis
and holoTextWrite
functions:
function validateCommit() { return true }
With that, we’ve successfully implemented holoTextWrite
!
holoTextRead
Fortunately, reading data is actually much simpler than writing it! To retrieve data from the source chain, we must have the hash for the contents we want to retrieve. This is the same as the hash that was returned by holoTextWrite
. For holoTextRead
, a hash will be our input, and a holoText
entry will be our return value, if one is found with the hash.
So add your function definition below holoTextWrite
, so that it looks like this:
function holoTextRead(hash) {}
To retrieve contents from our local source chain, we use the native function get. get takes a hash and an optional config object, and returns an entry, or a HC.HashNotFound message.
Recall that in dna.json, we declared the "Sharing"
property for holoText
to be "private"
. This means that entries were only written to local source chains and not the DHT. In order for get to work properly, we need to mention this by passing a Local: true
option into it.
Make your holoTextRead
function look like this:
function holoTextRead(hash) { var holoText = get(hash, { Local: true }) return holoText }
That’s it! We’ve implemented functions which write data to a local source chain, and read it back. With this, we could technically write "Hello World" into our chain and read it back, but there are other things to learn before we get to see it in action. The following HoloWorld Tutorial articles will cover how to test your application, how to do more complex validation of entries, and how to connect a user interface.
Return to the API documentation page, or continue with the tutorial.