One of the core design principles of the HAT has been its ability to store any structure data. Data is grouped under a combination of namespace and endpoint.
The namespace is similar to a "database" and you can define the unique namespace name in your application. The applications can by default have read-and-write data permission in this namespace and they cannot read data from other namespaces.
The endpoint is similar to a "table" in a "database". We have the option to create multiple endpoints for our app. One common pattern is to create endpoints to keep the same structured data together. For example, if we want to store the user's profile and their location in our app, we can create two separate endpoints – "profile" and "locations" – and store the data there. We don't have to define the endpoints in our application; once we write the first data the endpoints will be created.
You can learn more about the API and how you can structure the data here.
Create data into the HAT
For the Notes we can use the following structure:
{ value:'This is a note!', dateCreated:"2020-05-20T10:17:10.398Z",}
Lets start by storing our first note into the HAT:
// src/features/Notes/Notes.jsimport React, { useContext, useState } from'react';import { HatClient } from'@dataswift/hat-js';import'./Notes.scss';import { appConfig } from'../../app.config';import AuthContext from"../../components/context/AuthContext";functionNotes() {const [newNote,setNewNote] =useState('');constauthContext=useContext(AuthContext);// The endpoint to store the Notes dataconstnotesEndpoint='my-notes';// Create the configuration object to pass the auth token, api version and// the ssl flag to the HAT-JSconstconfig= { token:authContext.user.token, apiVersion:appConfig.hatApiVersion, secure:appConfig.secure, };// Initialize the HatClient with the configuration fileconsthat=newHatClient(config);consthandleChange= event => {setNewNote(event.target.value); };consthandleSubmit= event => {event.preventDefault();createData(); };constcreateData=async () => {try {if (!newNote) return;constdateCreated=newDate().toISOString();// Create the structure for the Noteconstbody= { value: newNote, dateCreated: dateCreated, };// Use the HAT-JS library to create our first data recordconstres=awaithat.hatData().create(appConfig.namespace, notesEndpoint, body);if (res.parsedBody) {// Reset the Note valuesetNewNote(''); } } catch (e) {console.log(e.cause +e.state) } };return ( <formonSubmit={e =>handleSubmit(e)} > <input . .value={newNote}onChange={e =>handleChange(e)} /> . . </form> );}exportdefault Notes;
Read data from the HAT
And now, we can create a list to fetch the available data:
// src/features/Notes/Notes.jsfunctionNotes() {const [notes,setNotes] =useState([]); . . .constfetchNotes=async () => {try {// Use the HAT-JS library to get all the data records for the Note endpointconstres=awaithat.hatData().getAllDefault(appConfig.namespace, notesEndpoint);if (res.parsedBody) {setNotes(res.parsedBody); } } catch (e) {console.log(e.cause +e.status); } };useEffect(() => {fetchNotes(); }, []);constListNotes= () => notes.sort((a, b) =>newDate(b.data.dateCreated) -newDate(a.data.dateCreated)).map((item, index) => {return ( <likey={index}> <divclassName={'note-row-wrapper'}> <divclassName={'note-content'}>{item.data.value}</div> <buttontype={'button'}> <iclassName={'material-icons'}>delete</i> </button> <buttontype={'button'}> <iclassName={'material-icons'}>edit</i> </button> </div> </li> ); });return ( <form ..> . . <ul className={'notes-list'}> <ListNotes /> </ul></form> );}exportdefault Notes;
We can now see our first note!
The response from the HAT is:
[ {"endpoint":"testhatapp/my-notes","recordId":"552551c8-6b46-451d-b91c-c2022561d0c6","data":{"value":"this is my first note!","dateCreated":"2020-05-13T10:44:59.651Z" } }]
The "endpoint" is combined with the application namespace. The unique "recordId" for every data record that can be used for the data record deletion, and the "data" field where we can find the stored data.
Update a data record
In order to update the HAT record, we have to send the same structure as the response from the HAT. To keep the example simple, we can add an exclamation mark at the end of the value every time the user clicks the Update button. In order to update a data record, we have to send the data as structured in the HAT's response.
// src/features/Notes/Notes.jsfunctionNotes() { . .constupdateData=async hatRecord => {constnoteIndex=notes.indexOf(hatRecord);// Update the valuehatRecord.data.value +='!';try {// Update the HAT record. We have the option to pass multiple records with the arrayconstres=awaithat.hatData().update([hatRecord]);if (res.parsedBody) {setNotes(prevNotes => {constdraft= [...prevNotes]; draft[noteIndex] =res.parsedBody[0];return draft; }); } } catch (e) {console.log(e.cause +e.status); } }; . .constListNotes= () => notes.sort((a, b) =>newDate(b.data.dateCreated) -newDate(a.data.dateCreated)).map((item, index) => {return ( <likey={index}> <divclassName={'note-row-wrapper'}> . . <buttontype={'button'} onClick={() =>updateData(item)}> <iclassName={'material-icons'}>edit</i> </button> </div> </li> ); });return ( <form ..> .. </form> );}exportdefault Notes;
Delete data from the HAT
Using the unique record ID from the Note, we can delete it easily from the HAT:
// src/features/Notes/Notes.jsfunctionNotes() { . .constdeleteData=async recordId => {try {// Delete a note with record ID. We can pass an array of multiple records IDsconstres=awaithat.hatData().delete([recordId]);if (res.parsedBody) {setNotes(prevNotes => {// Find index to remove from the Note arrayconstindex=prevNotes.findIndex(note =>note.recordId === recordId);if (index !==-1) {constdraft= [...prevNotes];draft.splice(index,1);return draft; } else {return prevNotes; } }); } } catch (e) {console.log(e.cause +e.status); } };constListNotes= () => notes.sort((a, b) =>newDate(b.data.dateCreated) -newDate(a.data.dateCreated)).map((item, index) => {return ( <likey={index}> <divclassName={'note-row-wrapper'}> <divclassName={'note-content'}>{item.data.value}</div> <buttontype={'button'} onClick={() =>deleteData(item.recordId)}> <iclassName={'material-icons'}>delete</i> </button> . . </div> </li> ); });return ( <form ..> .. </form> );}exportdefault Notes;
To learn more detail about HAT Login, HAT-JS and storing data into the HAT please see the Javascript Developers Guide.