--- layout: learn permalink: /:collection/:path.html --- # Manage Data with Gaia {:.no_toc} In this tutorial, you build a micro-blogging application using multi-player Gaia storage. Gaia is Blockstack's [decentralized high-performance storage system](https://github.com/blockstack/gaia). The tutorial contains the following topics: * TOC {:toc} This tutorial does not teach you about authentication. That is covered in depth [in the hello-blockstack tutorial](hello-blockstack.html). ## About this tutorial and the prerequisites you need {% include note.html content="This tutorial was written for a user running macOS. If you are running a Windows machine, you can still work through this tutorial. You will need to adjust the instructions for your environment."%} The application you build is a React.js application that is completely decentralized and server-less. While not strictly required to follow along, basic familiarity with React.js is helpful. When complete, the app is capable of the following: - authenticating users using Blockstack - posting new statuses - displaying statuses in the user profile - looking up the profiles and statuses of other users The basic identity and storage services are provided by `blockstack.js`. To test the application, you need to have already [registered a Blockstack ID](ids-introduction.html). The tutorial relies on the `npm` dependency manager. Before you begin, verify you have installed `npm` using the `which` command. ```bash $ which npm /usr/local/bin/npm ``` If you don't find `npm` in your system, [install it](https://www.npmjs.com/get-npm). Finally, if you get stuck at any point while working on the tutorial, the completed [source code is available for you](https://github.com/larrysalibra/publik) to check your work against. High Sierra 10.13.4. ## Use npm to install Yeoman and the Blockstack App Generator You use `npm` to install Yeoman. Yeoman is a generic scaffolding system that helps users rapidly start new projects and streamline the maintenance of existing projects. 1. Install Yeoman. ```bash npm install -g yo ``` 2. Install the Blockstack application generator. ```bash npm install -g generator-blockstack ``` ## Generate and launch the public application In this section, you build an initial React.js application called Publik. 1. Create a the `publik` directory. ```bash mkdir publik ``` 2. Change into your new directory. ```bash cd publik ``` 3. Use Yeoman and the Blockstack application generator to create your initial `publik` application. ```bash yo blockstack:react ``` You should see several interactive prompts. ```bash $ yo blockstack:react ? ========================================================================== We're constantly looking for ways to make yo better! May we anonymously report usage statistics to improve the tool over time? More info: https://github.com/yeoman/insight & http://yeoman.io ========================================================================== No _-----_ ╭──────────────────────────╮ | | │ Welcome to the │ |--(o)--| │ Blockstack app │ `---------´ │ generator! │ ( _´U`_ ) ╰──────────────────────────╯ /___A___\ / | ~ | __'.___.'__ ´ ` |° ´ Y ` ? Are you ready to build a Blockstack app in React? (Y/n) ``` 4. Respond to the prompts to populate the initial app. After the process completes successfully, you see a prompt similar to the following: ```bash [fsevents] Success: "/Users/theuser/repos/publik/node_modules/fsevents/lib/binding/Release/node-v59-darwin-x64/fse.node" is installed via remote npm notice created a lockfile as package-lock.json. You should commit this file. added 1060 packages in 26.901s ``` 5. Run the initial application. ```bash npm start ``` The system prompts you to accept incoming connections. ![Network Connection](./images/network-connections.gif) 6. Choose **Allow**. 7. Open your browser to `http://localhost:8080`. You should see a simple React app. ![](images/initial-app.gif) 8. Choose **Sign In with Blockstack**. The application tells you it will **Read your basic info**. ![](images/login.png) Leave your new application running and move onto the next section. ## Add the `publish_data` scope to sign in requests Every app that uses Gaia storage must add itself to the user's `profile.json` file. The Blockstack browser does this automatically when the `publish_data` scope is requested during authentication. For this application, the user files stored on Gaia are made visible to others via the `apps` property in the user's `profile.json` file. Modify your authentication request to include the `publish_data` scope. 1. Open `src/components/App.jsx` file. 2. Locate the `handleSignIn` handler method. ```javascript handleSignIn(e) { e.preventDefault(); redirectToSignIn(); } ``` 2. Modify the method to this: ```javascript handleSignIn(e) { e.preventDefault(); const origin = window.location.origin redirectToSignIn(origin, origin + '/manifest.json', ['store_write', 'publish_data']) } ``` By default, authentication requests include the `store_write` scope which enables storage. This is what allows you to store information to Gaia. 3. Save your changes. 4. Go back to your app at `http://localhost:8080/`. 5. Log out and sign in again. The authentication request now prompts the user for permission to **Publish data stored for the app**. ![](images/publish-data-perm.png) ## Understand Gaia storage methods Once you authenticate a user with `store_write` and `publish_data`, you can begin to manage data for your users. Blockstack JS provides two methods `getFile()` and `putFile()` for interacting with Gaia storage. The storage methods support all file types. This means you can store SQL, Markdown, JSON, or even a custom format. You can create a meaningful and complex data layer using these two methods. Before creating an application, consider fundamental data architecture and make some decisions about how you’re modeling data. For example, consider building a simple grocery list app. A user should be able to create, read, update, and delete grocery lists. A single file collection stores items as an array nested inside each grocery list: ```js // grocerylists.json { "3255": { "items": [ "1 Head of Lettuce", "Haralson apples" ] }, // ...more lists with items } ``` This is conceptually the simplest way to manage grocery lists. When you read a `/grocerylists.json` file with `getFile()`, you get back one or more grocery lists and their items. When you write a single list, the `putFile()` method overwrites the entire list. So, a write operation for a new or updated grocery list must submit all existings lists as well. Further, because this runs on the client where anything can go wrong. If the client-side code encounters a parsing error with a user-input value and you could overwrite the entire file with: `line 6: Parsing Error: Unexpected token.` Further, a single file makes pagination impossible and if your app stores a single file for all list you have less control over file permissions. To avoid these issues, you can create an index file that stores an array of IDs. These IDs point to a name of another file in a `grocerylists` folder. ![](images/multiple-lists.png) This design allows you to get only the files you need and avoid accidentally overwriting all lists. Further, you’re only updating the index file when you add or remove a grocery list; updating a list has no impact. ## Add support for user status submission and lookup In this step, you add three `blockstack.js` methods that support posting of "statuses". These are the `putFile()`, `getFile()`, and `lookupProfile()` methods. 1. Open the `src/components/Profile.jsx` file. 2. Expand the `import from blockstack` statement with data methods. The `Person` object holds a Blockstack profile. Add `putFile`, `getFile`, and `lookupProfile` after `Person`. When you are done, the import statement should look like the following: ```javascript import { isSignInPending, loadUserData, Person, getFile, putFile, lookupProfile } from 'blockstack'; ``` 3. Replace the `constructor()` initial state so that it holds the key properties required by the app. This code constructs a Blockstack `Person` object to hold the profile. Your constructor should look like this: ```javascript constructor(props) { super(props); this.state = { person: { name() { return 'Anonymous'; }, avatarUrl() { return avatarFallbackImage; }, }, username: "", newStatus: "", statuses: [], statusIndex: 0, isLoading: false }; } ``` 4. Locate the `render()` method. 5. Modify the `render()` method to add a text input and submit button to the application. The following code echos the `person.name` and `person.avatarURL` properties from the profile on the display: ```javascript render() { const { handleSignOut } = this.props; const { person } = this.state; const { username } = this.state; return ( !isSignInPending() && person ?

{ person.name() ? person.name() : 'Nameless Person' }

{username}  |  (Logout)