Hoodie Documentation¶
Welcome to Hoodie¶
Hoodie is a backend for web applications with a JavaScript API for your frontend. If you love building apps with HTML, CSS and JavaScript or a frontend framework, but dread backend work, Hoodie is for you.
Hoodie’s frontend API gives your code superpowers by allowing you to do things that usually only a backend can do (user accounts, emails, payments, etc.).
All of Hoodie is accessible through a simple script include, just like jQuery or lodash:
<script src="/hoodie/client.js"></script>
<script type="javascript">
var hoodie = new Hoodie();
</script>
From that point on, things get really powerful really quickly:
// In your front-end code:
hoodie.ready.then(function () {
hoodie.account.signUp({
username: username,
password: password
})
})
That’s how simple signing up a new user is, for example. But anyway:
Hoodie is a frontend abstraction of a generic backend web service. As such, it is agnostic to your choice of frontend application framework. For example, you can use jQuery for your web app and Hoodie for your connection to the backend, instead of raw jQuery.ajax. You could also use React with Hoodie as a data store, or any other frontend framework or library, really.
Open Source¶
Hoodie is an Open Source project, so we don’t own it, can’t sell it, and it won’t suddenly vanish because we got aquired. The source code for Hoodie is available on GitHub under the Apache License 2.0.
How to proceed¶
You could read up on some of the ideological concepts behind Hoodie, such as noBackend and Offline First. These explain why Hoodie exists and why it looks and works the way it does.
If you’re more interested in the technical details of Hoodie, check out How Hoodie Works. Learn how Hoodie handles data storage, does syncing, and where the offline support comes from.
Eager to build stuff? Skip ahead to the quickstart guide!
Quickstart¶
In this guide you’ll learn how to create a demo Hoodie app, learn about the basic structure of a Hoodie project and its folders, the endpoints and app URLs and how to include and use the Hoodie library in your project.
Prerequisites¶
For all operating systems, you’ll need Node.js installed. You can download Node from nodejs.org. We recommend the LTS (Long Term Support) version.
Make sure you have version 4 or higher. You can find out with
$ node -v
Create a new Hoodie Backend¶
First you need to create a new folder, let’s call it testapp
$ mkdir testapp
Change into the testapp
directory.
$ cd testapp
Now we need to create a package.json file. For that we can use npm which comes with Node by default. It will ask you a few questions, you can simply press enter to leave the default values.
$ npm init
Now we can install hoodie using npm
$ npm install hoodie --save
The resulting package.json file in the current folder, should look something like this
{
"name": "funky",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"start": "hoodie",
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC"
}
Now you can start Hoodie with
$ npm start
Great, your Hoodie backend started up and is now telling you at which URL you can access it. By default that is http://127.0.0.1:8080
Congratulations, you just created your first Hoodie Backend :) You can now load the Hoodie client on any website with
<script src="http://127.0.0.1:8080/hoodie/client.js"></script>
You can also create a public/index.html
file, which will be served
at http://127.0.0.1:8080 after you restart the server. All assets in the public
folder, like images, CSS files or JavaScript files, will be served by your
Hoodie Backend at http://127.0.0.1:8080/<path/to/your/file.ext>
.
What’s next?¶
Our Hoodie Tracker App is a great place to see how to use a Hoodie backend. It’s an intentionally simple and well commented application built with only HTML, JavaScript and CSS, without using any library or framework. You can see it running at https://tracker.hood.ie/
Having Trouble?¶
Sorry it didn’t go smoothly for you. Come chat with us or ask a question on StackOverflow
Configuration¶
Your Hoodie backend can be configured using default options that are part of your repository as well as using hidden files, CLI arguments and environment variables.
Options¶
Here is a list of all available options
Option | Default value | CLI argument | ENV variable | description | |
---|---|---|---|---|---|
address | '127.0.0.1' |
--address |
hoodie_address | Address to which Hoodie binds |
||
data | '.hoodie' |
--data |
hoodie_data | Data path |
||
dbUrl | – | --dbUrl |
hoodie_dbUrl | If provided, uses external CouchDB. URL has to contain credentials. Sets dbAdapter to pouchdb-adapter-http |
||
dbAdapter | 'pouchdb-adapter-fs' |
--dbAdapter |
hoodie_dbAdapter | Sets default PouchDB adapter <https://pouchdb.com/adapters.html> unless inMemory or dbUrl set |
||
loglevel | 'warn' |
--loglevel |
hoodie_loglevel | One of: silent, error, warn, http, info, verbose, silly |
||
inMemory | false |
-m , --inMemory |
hoodie_inMemory | Whether to start the PouchDB Server in memory. Sets dbAdapter to pouchdb-adapter-memory |
||
port | 8080 |
--port |
hoodie_port | Port-number to run the Hoodie App on |
||
public | 'public' |
--public |
hoodie_public | path to static assets |
||
url | --url |
hoodie_url | Optional: external URL at which Hoodie Server is accessible (e.g. http://myhoodieapp.com ) |
|||
adminPassword | --adminPassword |
hoodie_adminPassword |
Password to login to Admin Dashboard. Login is not possible unless set |
Defaults¶
Default options are set in your app’s package.json
file, using the
"hoodie"
key. Here is an example with all avaialble options and their
default values
{
"hoodie": {
"address": "127.0.0.1",
"port": 8080,
"data": ".hoodie",
"public": "public",
"dbUrl": "",
"dbAdapter": "pouchdb-adapter-fs",
"inMemory": false,
"loglevel": "warn",
"url": "",
"adminPassword": ""
}
}
.hoodierc¶
The .hoodierc
can be used to set configuration when running your Hoodie
backend in that folder. It should not be comitted to your repository.
The content can be in JSON or INI format. See the rc package on npm for more information
CLI arguments and environment variables¶
To pass CLI options when starting Hoodie, you have to separate them with --
, for example:
$ npm start -- --port=8090 --inMemory
All environment varibales are prefixed with hoodie_
. So to set the port to
8090
and to start Hoodie in memory mode, you have to
- set the
hoodie_port
environment variable to8090
- set the
hoodie_inMemory
environment variable totrue
Hoodie CLI is using rc for configuration,
so the same options can be set with environment variables and config files.
Environment variables are prefixed with hoodie_
.
The priority of configuration¶
- command line arguments
- Environment variables
.hoodierc
files- Your app’s defaults form the
"hoodie"
key in"package.json"
- Hoodie’s default values as shown in table above
Plugins¶
You can extend your Hoodie backend in two ways
- App-specific plugins
- 3rd party plugins
App-specific plugins¶
You can extend your Hoodie’s client by creating the file hoodie/client/index.js
in your app’s repository, which should export a Hoodie Client plugin <https://github.com/hoodiehq/hoodie-client#hoodieplugin>.
It will dynamically be bundled into your client accessible at the /hoodie/client.js
route.
You can extend your Hoodie’s server routes and API by creating hoodie/server/index.js
in your app’s, which should export a hapi plugin <https://hapijs.com/tutorials/plugins>.
3rd party plugins¶
Hoodie will soon support loading 3rd party plugins from npm packages. You can watch this pull request for updates.
To get an idea how 3rd party plugins will work and look like, have a look at https://github.com/hoodiehq/hoodie-plugin-example
Deployment¶
One line deploy¶
After you’ve built your Hoodie app you probably want to put it online. You can choose to deploy your app as read-only or deploy the backend couchdb database as well. This video and the text below descibes how to deploy your app using one line of code. Alternatively, you can deploy your app using Docker, please refer to the Docker section.
Deploying to Now¶
Now allows you to deploy a Node application with its command line tool. It’s 100% free for Open Source projects. You can deploy an app from your computer or right from a GitHub repository. For example, to deploy our Hoodie Tracker demo app all you have to do is to run this command:
$ now hoodiehq/hoodie-app-tracker --npm -e NODE_ENV=production -e hoodie_inMemory=true
To decribe this further:
hoodiehq/hoodie-app-tracker
is the GitHub repository slug.--npm
tells now to deploy using npm as there is also Dockerfile in the repository.-e NODE_ENV=production
sets the NODE_ENV environment variable to production, which makes the deployment faster as no devDependencies will be installed.-e hoodie_inMemory=true
makes the Hoodie app run in-memory mode, meaning that no data is persisted and no files are written. This is important because now is a read-only file system. That means that all user accounts and data will be lost on the next deployment, but it is great for for a quick test or demo of your application.
Alternatively, add this script to your package.json and you are good to go:
"now-start": "hoodie --inMemory",
Store Data With Cloudant¶
Cloudant is a DBaaS (database-as-a-service). It provides most of CouchDB’s APIs and can be used as Hoodie’s database backend. Signing up for a free account only takes a moment. After sign up, you need to slightly adjust the now deployment command above.
$ now hoodiehq/hoodie-app-tracker -e NODE_ENV=production -e hoodie_inMemory=true -e hoodie_dbUrl=https://username:password@username.cloudant.com/
The hoodie_inMemory
environment variable makes sure that Hoodie does not try to write any files like the bundled /hoodie/client.js library. The hoodie_dbUrl
environment variable sets the address and credentials to your CouchDB. Replace username and password to whatever you signed up with.
Test and set an alias¶
When you deploy with now you will receive a random subdomain where you can access your application. It looks something like https://hoodie-app-tracker-randomxyz.now.sh/ and was already copied to your clipboard during the deployment. Open the URL in your browser to give it a try. Once everything is good, you can change the subdomain to your preference by running:
$ now alias set hoodie-app-tracker-randomxyz my-tracker-app
That will make your deployed Hoodie Tracker app accessible at https://my-tracker-app.now.sh. For example, here is the app that I deployed myself: https://hoodie-app-tracker.now.sh/
Docker¶
We continuously deploy our Hoodie Tracker App using Docker. You can read about our continuous deployment set at hoodie-app-tracker/deployment.md.
Hoodie API¶
Hoodie provides two APIs
The Hoodie Client API
The Hoodie Client API is what you load into your web application using a script tag. It connects to your Hoodie Backend’s routes
The Hoodie Server API
The Hoodie Server API is used within Hoodie’s route handlers and by plugins to manage accounts, data and to securely integrate with 3rd party services.
The Hoodie Client API¶
hoodie¶
Introduction¶
This document describes the functionality of the hoodie base object. It provides a number of helper methods dealing with event handling and connectivity, as well as a unique id generator and a means to set the endpoint which Hoodie communicates with.
Initialisation¶
The Hoodie Client persists state in the browser, like the current user’s
id, session or the connection status to the backend. On page load,
Hoodie has to load this state from the local store before you can use
its APIs. You can use the Promise returned by hoodie.ready
to wait
until all APIs are fully initialised
hoodie.ready.then(function () {
// all hoodie APIs are ready now
})
This is work in progress¶
Please help us make this awesome <3
For the time being, check out hoodie-client’s README.
hoodie.account¶
The account object in the client-side Hoodie API covers all user and authentication-related operations, and enables you to do previously complex operations, such as signing up a new user, with only a few lines of frontend code. Since data in Hoodie is generally bound to a user, it makes sense to familiarise yourself with account before you move on to store.
This is work in progress¶
Please help us make this awesome <3
For the time being, check out hoodie-account-client’s README.
hoodie.store¶
If you want to do anything with data in Hoodie, this is where it happens.
This is work in progress¶
Please help us make this awesome <3
For the time being, check out hoodie-store-client’s README.
hoodie.connectionStatus¶
This is work in progress¶
Please help us make this awesome <3
For the time being, check out hoodie-connection-status’s README.
hoodie.log¶
This is work in progress¶
Please help us make this awesome <3
For the time being, check out hoodie-log’s README.
This library, commonly called Hoodie Client, is what you’ll be working with on the client side. It consists of:
- The Hoodie Client API, which has a couple of useful helpers
- The account API, which lets you do user authentication, such as signing users up, in and out
- The store API, which provides means to store and retrieve data for each individial user
- The connectionStatus API, which provides helpers for connectivity.
- The log API, which provides a nice API for logging all the things
The Hoodie Server API¶
The Hoodie Server API is currently work-in-progress. But you can have a look at the Account Server API and the Store Server API for a sneak peak.
Contributing to Hoodie¶
Please take a moment to review this document in order to make the contribution process easy and effective for everyone involved.
Following these guidelines helps to communicate that you respect the time of the developers managing and developing this open source project. In return, they should reciprocate that respect in addressing your issue, assessing changes, and helping you finalize your pull requests.
As for everything else in the project, the contributions to Hoodie are governed by our Code of Conduct.
Using the issue tracker¶
First things first: Do NOT report security vulnerabilities in public issues! Please disclose responsibly by letting the Hoodie team know upfront. We will assess the issue as soon as possible on a best-effort basis and will give you an estimate for when we have a fix and release available for an eventual public disclosure.
The issue tracker is the preferred channel for bug reports, features requests and submitting pull requests, but please respect the following restrictions:
- Please do not use the issue tracker for personal support requests. Use the Hoodie Chat.
- Please do not derail or troll issues. Keep the discussion on topic and respect the opinions of others.
Bug reports¶
A bug is a demonstrable problem that is caused by the code in the repository. Good bug reports are extremely helpful - thank you!
Guidelines for bug reports:
- Use the GitHub issue search — check if the issue has already been reported.
- Check if the issue has been fixed — try to reproduce it using the
latest
master
ornext
branch in the repository. - Isolate the problem — ideally create a reduced test case.
A good bug report shouldn’t leave others needing to chase you up for more information. Please try to be as detailed as possible in your report. What is your environment? What steps will reproduce the issue? What OS experiences the problem? What would you expect to be the outcome? All these details will help people to fix any potential bugs.
Example:
Short and descriptive example bug report title
A summary of the issue and the browser/OS environment in which it occurs. If suitable, include the steps required to reproduce the bug.
- This is the first step
- This is the second step
- Further steps, etc.
<url>
- a link to the reduced test caseAny other information you want to share that is relevant to the issue being reported. This might include the lines of code that you have identified as causing the bug, and potential solutions (and your opinions on their merits).
Feature requests¶
Feature requests are welcome. But take a moment to find out whether your idea fits with the scope and aims of the project. It’s up to you to make a strong case to convince the project’s developers of the merits of this feature. Please provide as much detail and context as possible.
Pull requests¶
Good pull requests - patches, improvements, new features - are a fantastic help. They should remain focused in scope and avoid containing unrelated commits.
Please ask first before embarking on any significant pull request (e.g. implementing features, refactoring code), otherwise you risk spending a lot of time working on something that the project’s developers might not want to merge into the project.
For new Contributors¶
If you never created a pull request before, welcome :tada: :smile: Here is a great tutorial on how to send one :)
- Fork the project, clone your fork, and configure the remotes:
bash # Clone your fork of the repo into the current directory git clone https://github.com/<your-username>/<repo-name> # Navigate to the newly cloned directory cd <repo-name> # Assign the original repo to a remote called "upstream" git remote add upstream https://github.com/hoodiehq/<repo-name>
- If you cloned a while ago, get the latest changes from upstream:
bash git checkout master git pull upstream master
- Create a new topic branch (off the main project development branch) to contain your feature, change, or fix:
bash git checkout -b <topic-branch-name>
- Make sure to update, or add to the tests when appropriate. Patches
and features will not be accepted without tests. Run
npm test
to check that all tests pass after you’ve made changes. Look for aTesting
section in the project’s README for more information. - If you added or changed a feature, make sure to document it
accordingly in the
README.md
file. - Push your topic branch up to your fork:
bash git push origin <topic-branch-name>
- Open a Pull Request with a clear title and description.
For Members of the Hoodie Contributors Team¶
- Clone the repo and create a branch
bash git clone https://github.com/hoodiehq/<repo-name> cd <repo-name> git checkout -b <topic-branch-name>
- Make sure to update, or add to the tests when appropriate. Patches
and features will not be accepted without tests. Run
npm test
to check that all tests pass after you’ve made changes. Look for aTesting
section in the project’s README for more information. - If you added or changed a feature, make sure to document it
accordingly in the
README.md
file. - Push your topic branch up to our repo
bash git push origin <topic-branch-name>
- Open a Pull Request using your branch with a clear title and description.
Optionally, you can help us with these things. But don’t worry if they are too complicated, we can help you out and teach you as we go :)
- Update your branch to the latest changes in the upstream master branch. You can do that locally with
bash git pull --rebase upstream master
Afterwards force push your changes to your remote feature branch.
- Once a pull request is good to go, you can tidy up your commit messages using Git’s interactive rebase. Please follow our commit message conventions shown below, as they are used by semantic-release to automatically determine the new version and release to npm. In a nutshell:
Commit Message Conventions¶
- Commit test files with
test: ...
ortest(scope): ...
prefix - Commit bug fixes with
fix: ...
orfix(scope): ...
prefix - Commit breaking changes by adding
BREAKING CHANGE:
in the commit body (not the subject line) - Commit changes to
package.json
,.gitignore
and other meta files withchore(filenamewithoutext): ...
- Commit changes to README files or comments with
docs: ...
- Cody style changes with
style: standard
IMPORTANT: By submitting a patch, you agree to license your work under the same license as that used by the project.
Triagers¶
There is a defined process to manage issues, because this helps to speed up releases and minimizes user pain. Triaging is a great way to contribute to Hoodie without having to write code. If you are interested, please leave a comment here asking to join the triaging team.
Maintainers¶
If you have commit access, please follow this process for merging patches and cutting new releases.
Reviewing changes¶
- Check that a change is within the scope and philosophy of the component.
- Check that a change has any necessary tests.
- Check that a change has any necessary documentation.
- If there is anything you don’t like, leave a comment below the respective lines and submit a “Request changes” review. Repeat until everything has been addressed.
- If you are not sure about something, mention
@hoodie/maintainers
or specific people for help in a comment. - If there is only a tiny change left before you can merge it and you think it’s best to fix it yourself, you can directly commit to the author’s fork. Leave a comment about it so the author and others will know.
- Once everything looks good, add an “Approve” review. Don’t forget to say something nice 👏🐶💖✨
- If the commit messages follow our conventions
- If there is a breaking change, make sure that
BREAKING CHANGE:
with exactly that spelling (incl. the ”:”) is in body of the according commit message. This is very important, better look twice :) - Make sure there are
fix: ...
orfeat: ...
commits depending on wether a bug was fixed or a feature was added. Gotcha: look for spaces before the prefixes offix:
andfeat:
, these get ignored by semantic-release. - Use the “Rebase and merge” button to merge the pull request.
- Done! You are awesome! Thanks so much for your help 🤗
- If the commit messages do not follow our conventions
- Use the “squash and merge” button to clean up the commits and merge at the same time: ✨🎩
- Is there a breaking change? Describe it in the commit body. Start
with exactly
BREAKING CHANGE:
followed by an empty line. For the commit subject: - Was a new feature added? Use
feat: ...
prefix in the commit subject - Was a bug fixed? Use
fix: ...
in the commit subject
Sometimes there might be a good reason to merge changes locally. The process looks like this:
Reviewing and merging changes locally¶
git checkout master # or the main branch configured on github
git pull # get latest changes
git checkout feature-branch # replace name with your branch
git rebase master
git checkout master
git merge feature-branch # replace name with your branch
git push
When merging PRs from forked repositories, we recommend you install the hub command line tools.
This allows you to do:
hub checkout link-to-pull-request
meaning that you will automatically check out the branch for the pull request, without needing any other steps like setting git upstreams! :sparkles:
Triage new issues/PRs on GitHub¶
This document illustrates the steps the Hoodie community is taking to triage issues. The labels are used later on for assigning work. If you want to help by sorting issues please leave a comment here asking to join the triaging team.
Triaging Process¶
This process based on the idea of minimizing user pain from this blog post.
- Open the list of non triaged
issues
- Sort by submit date, with the newest issues first
- You don’t have to do issues in order; feel free to pick and choose issues as you please.
- You can triage older issues as well
- Triage to your heart’s content
- Assign yourself: Pick an issue that is not assigned to anyone and assign it to you
- Understandable? - verify if the description of the request is clear.
- If not, close it according to the instructions below and go to the last step.
- Duplicate?
- Bugs:
- Label
Type: Bug
- Reproducible? - Steps to reproduce the bug are clear. If they are not, ask for a clarification. If there’s no reply after a week, close it.
- Reproducible on master?
- Label
- Non bugs:
- Label
Type: Feature
,Type: Chore
, orType: Perf
- Belongs in core? – Often new features should be implemented as a plugin rather than an addition to the core. If this doesn’t belong, close it, and go to the last step.
- Label
needs: breaking change
- if needed - Label
needs: public api
- if the issue requires introduction of a new public API
- Label
- Label
frequency: *
– How often does this issue come up? How many developers does this affect?- low - obscure issue affecting a handful of developers
- moderate - impacts a common usage pattern
- high - impacts most or all Hoodie apps
- Label
severity: *
- How bad is the issue?- regression
- memory leak
- broken expected use - it’s hard or impossible for a developer using Hoodie to accomplish something that Hoodie should be able to do
- confusing - unexpected or inconsistent behavior; hard-to-debug
- inconvenience - causes ugly/boilerplate code in apps
- Label
starter
- These issues are good targets for PRs from the open source community. Apply to issues where the problem and solution are well defined in the comments, and it’s not too complex. - Label
milestone: *
– Assign a milestone:
- Backlog - triaged fixes and features, should be the default choice
- x.y.z - e.g. 0.3.0
- Unassign yourself from the issue
Closing an Issue or PR¶
We’re grateful to anyone who takes the time to submit an issue, even if we ultimately decide not to act on it. Be kind and respectful as you close issues. Be sure to follow the code of conduct.
- Always thank the person who submitted it.
- If it’s a duplicate, link to the older or more descriptive issue that supersedes the one you are closing.
- Let them know if there’s some way for them to follow-up.
- When the issue is unclear or reproducible, note that you’ll reopen it if they can clarify or provide a better example. Mention jsbin for examples. Watch your notifications and follow-up if they do provide clarification. :)
- If appropriate, suggest implementing a feature as a third-party module.
If in doubt, ask a core team member what to do.
Example:
Thanks for submitting this issue! Unfortunately, we don’t think this functionality belongs in core. The good news is that you could implement this as a plugin and publish it to npm with thehoodie-plugin
keyword.
Assigning Work¶
These criteria are then used to calculate a “user pain” score. Work is assigned weekly to core team members starting with the highest pain, descending down to the lowest.
pain = severity × frequency
severity:
- regression (5)
- memory leak (4)
- broken expected use (3)
- confusing (2)
- inconvenience (1)
frequency:
- low (1)
- moderate (2)
- high (3)
Note: Regressions and memory leaks should almost always be set to
frequency: high
.
Coding Style Guide¶
Please see Contributing to Hoodie for more guidelines on contributing to Hoodie.
Hoodie uses the Standard JavaScript coding style.
This file explains coding-style considerations that are beyond the syntax check of Standard.
There are three sections:
- General: coding styles that are applicable to all JavaScript code.
- Client: coding styles that are only applicable to in-browser code.
- Server: coding styles that are only applicable in server code.
Note: Client and Server coding styles can be contradicting, make sure to read these carefully.
General¶
File Structure¶
A typical JavaScript file looks like this (without the comments). Sort
all modules that you require
alphabetically within their blocks.
// If your module exports something, put it on top
module.exports = myMethod
// require Node.js core modules in the 1st block (separaeted by empty line).
// These are modules that come with Node.js and are not listed in package.json.
// See https://nodejs.org/api/ for a list of Node.js core modules
var EventEmitter = require('events').EventEmitter
var util = require('util')
// In the 2nd block, require all modules listed in package.json
var async = require('async')
var lodash = require('lodash')
// in the 3rd block, require all modules using relative paths
var helpers = require('./utils/helpers')
var otherMethod = require('./other-method')
function myMethod () {
// code here
}
Avoid “this” and object-oriented coding styles.¶
Do this
function MyApi (options) {
var state = {
foo: options.foo
}
return {
doSomething: doSomething.bind(null, state)
}
}
function doSomething (state) {
return state.foo ? 'foo!' : 'bar'
}
Instead of
function MyApi (options) {
this.foo = options.foo
}
MyApi.prototype.doSomething = function () {
return this.foo ? 'foo!' : 'bar'
}
The bind method allows for partially applied functions, that way we can pass internal state between different methods without exposing in the public API. At the same time we can easily test the different methods in isolation by setting the internal state to what ever context we want to test with.
Folder Structure¶
In the root, have
package.json
.gitignore
(should at least list node_modules)README.md
LICENSE
(Apache License Version 2.0)
In most cases you will have index.js
file which is listed in
package.json
as the "main"
property.
If you want to split up logic into separate files, move them into a
server/
folder. Put reusable, state-less helper methods into
server/utils/
For tests, create a test/
folder. If your module becomes a bit more
complex, split up the tests in test/unit
and test/integration/
.
All files that contain tests should end with -test.js
.
Misc¶
- Prefer lodash over underscore.
Client¶
Testing¶
Client code should be tested using tape. The reason we use tape is its support for browserify.
Libraries with sub-modules that can be required individually, like lodash¶
For client-side JavaScript code, it is important to limit the amount of code that is downloaded to the client to the code that is actually needed. The loadash library is a collection of utilities that are useful individually and in combination.
For example, if you want to use the merge
function of lodash,
require it like this:
var merge = require('lodash/merge')
If you want to use more than one function within one module, or if you want to combine multiple functions for a single operation, require the full lodash module:
var _ = require('lodash')
If multiple modules use the same lodash function, our frontend bundling tool will do the right thing and only include that code once.
Server¶
Libraries with sub-modules that can be required individually, like lodash¶
For server-side code, it is important to load the minimal amount of code into memory.
On the server require the full library, e.g.
var _ = require('lodash')
var c = _.merge(a, b)
That way, all of our server code will only ever load a single instance of lodash into memory.
Contributing to Documentation¶
This guide describes how to make changes to Hoodie documentation.
Make small changes¶
We love small contributions, if you spot small errors or additions please feel free to request a change. Every page on Hoodie documentation has an “Edit on GitHub” button on the top right corner, please use this to make changes.
Hoodie documentation uses the reStructuredText format. This may be unfamiliar but provides advanced features which are useful for complex documentation.
The Github editor is very basic, if you need more editing tools try copying and pasting into this online editor. You can then click ‘commit’ and create a ‘pull request’ on Github. The pull request will be automatically tested for grammar, style and common misspellings. Your changes will then be reviewed by a Hoodie Admin, who may suggest changes. Please read the Documentation Style Guide for advice on writing and more info on testing.
Make big changes¶
For big changes, follow the Contributing to Hoodie guidelines for new contributors. This allows you to build and test the documentation locally. For example, adding, moving or updating several documents. The index.rst file in the docs/ folder controls the order in which the documents are displayed on the docs webpages. Remember to update the index file if you have removed, added or want to reorder the documents.
To build the docs locally, you will need to install python 2.7+
Then install two pip packages: Sphinx and sphinx_rtd_theme.
sudo pip sphinx
sudo pip sphinx_rtd_theme
Change directory to ..hoodie/docs/
make html
After building, your updated documents are in the docs/_build/html subdirectory. Click on any .html document, this will open your web browser and the documents will be viewable.
Get in touch if you have any questions or want to contribute to Hoodie documentation.
Documentation Style Guide¶
This guide provides style advice for how to write documentation. Please take the time to read this before contributing a large change or update to documentation.
Style helps you and your reader¶
Word choice and writing style are a personal choice and we understand documentation can be difficult to write. These recommendations have been designed to help you write clear and beautiful documents.
Testing¶
The contributing to docs guide describes the process to follow when updating documentation. This process includes automatic testing. Testing provides you peace of mind that your contribution won’t contain typos, broken links or other style whoopsies. Testing is not used to criticise your writing, we really love and appreciate any contributions. Please be patience through the testing and review process. Together we can keep Hoodie documentation awesome!
Style guidance¶
Please see the helpful guide provided by OpenStack documentation. This guide will further explain these key style tips:
- Use standard English
- Write in active voice
- Use the present simple tense
- Write in second person
- Use appropriate mood
- Keep sentences short
- Avoid ambiguous titles
- Be clear and concise
- Write objectively
- Describe the most common use case first
- Do not humanize inanimate objects
- Write positively
- Avoid prepositions at the end of sentences
- Do no overuse this, that, these, and it
- Do not split infinitives
- Avoid personification
- Eliminate needless politeness
- Use consistent terminology
- Use spelling and grammar checking tools
Automatic testing¶
The current tests we run on pull requests using Travis Continuous Integration (CI) service:
Style guide | Tested | Test type | Package |
---|---|---|---|
Keep sentences short, concise and readable | ✔ | Warning | rousseau |
Write in the active voice | ✔ | Warning | rousseau |
Avoid “Lexical illusion’s” – cases where a word is repeated | ✔ | Warning | rousseau |
Check for ‘So’ at the beginning of sentences | ✔ | Warning | rousseau |
Avoid adverbs that can weaken meaning: really, very, extremely, etc | ✔ | Warning | rousseau |
Use the most simple expressions | ✔ | Warning | rousseau |
Avoid using “weasel words”: quite, several, mostly etc | ✔ | Warning | rousseau |
Leave no space between a sentence and its ending punctuation | ✔ | Warning | rousseau |
Spell checker - we test for common misspelling but please check technical words | ✔ | Error | common |
Broken or dead links (excluding redirects) | ✔ | Error | awesome |
- Remember, follow the Code of Conduct
Bonus style points¶
- Be fun and friendly as long as it does not distract or confuse the reader
- Include videos or gifs to demostrate a feature
- You can use humour but remember the reader is looking for an answer not a comedy sketch
- Cultural references and puns don’t always translate - keep jokes light
- Remember English is not the first language for many readers - keep language simple where possible
Further reading¶
This guide is influenced by the Open Stack style guide.
Hoodie’s Concepts¶
Hoodie was designed around a few core beliefs and concepts, and they explain a lot if the choices made in the code and the functionality. They are:
Dreamcode¶
While designing Hoodie’s API, we realised that we wanted to do more than simply expose some server code to the frontend. We wanted to reduce complexity, not move it around. And to make something simple and intuitive, you can’t start with the tech stack, you have to start with the humans that are going to use it. What would their dream API look like? Dreamcode is essentially user-centered design for APIs.
To put it bluntly: Hoodie’s API is optimized for being awesome. For being intuitive and accessible. And it’s optimized for making the lives of frontend developers as good as possible. It’s also an API first: it’s a promise - everything else can change or is replaceable. The API is all that matters.
Forget all the constraints of today’s browsers. Then write down the code of your dreams for all the tasks you need to build your app. The implementation behind the API doesn’t matter, it can be simple or tough as nails, but crucially: the users shouldn’t have to care. This is dreamcode.
Everything is hard until someone makes it easy. We’re making web app development easy.
Here’s some further information and links to Dreamcode examples.
noBackend¶
Servers are difficult. Databases are difficult. The interplay between client and server is difficult, there are many moving parts, there are many entertaining mistakes to make, and the barrier to entry for web app development is, in our mind, needlessly high. You shouldn’t have to be a full stack developer to build a functioning app prototype, or code a small tool for yourself or your team, or launch a simple MVP.
People have been building web apps for quite a while now, and their basic operations (sign up, sign in, sign out, store and retrieve data, etc.) must have been written a million separate times by now. These things really shouldn’t be difficult anymore. So we’re proposing Hoodie as a noBackend solution. Yes, a backend does exist, but it doesn’t have to exist in your head. You don’t have to plan it or set it up. You simply don’t have to worry about it for those basic operations, you can do all of them with Hoodie’s frontend API. Of yourse, we let you dig as deep as you want, but for the start, you don’t have to.
noBackend gives you time to work on the hard problems, the parts of the app that are justifiably difficult and non-abstractable, like the interface, the user experience, the things that make your product what it is.
With Hoodie, you scaffold out your app with
$ hoodie new best-app-ever
and you’re good to go. Sign up users, store data… it’s all right there, immediately. It’s a backend in a box, empowering frontend developers to build entire apps without thinking about the backend at all. Check out some example Hoodie apps if you’d like to see some code.
More information about noBackend¶
See nobackend.org, Examples for noBackend solutions and @nobackend on Twitter.
Offline First¶
We make websites and apps for the web. The whole point is to be online, right? We’re online when we build these things, and we generally assume our users to be in a state of permanent connectivity. That state, however, is a myth, and that assumption causes all sorts of problems.
With the stellar rise of mobile computing, we can no longer assume anything about our users’ connections. Just as we all had to learn to accept that screens now come in all shapes and sizes, we’ll have to learn that connections can be present or absent, fast or slow, steady or intermittent, free or expensive… We reacted to the challenge of unknowable screen sizes with Responsive Webdesign and Mobile First, and we will react to the challenge of unknowable connections with Offline First.
Offline First means: build your apps without the assumption of permanent connectivity. Cache data and apps locally. Build interfaces that accomodate the offline state elegantly. Design user interactions that will not break if their train goes into a tunnel. Don’t freak out your users with network error messages or frustrate them with inaccessible data. Offline First apps are faster, more robust, more pleasant to use, and ultimately: more useful.
More information about Offline First¶
See offlinefirst.org, on GitHub and discussions and research
So now you know what motivates us¶
We hope this motivated you too! So let’s continue to the system requirements for Hoodie.
How Hoodie Works¶
Hoodie has several components that work together in a somewhat atypical way to deliver our promise of simplicity, out-of-the-box syncing, and offline capability.
Everything starts in the frontend, with your app. This is your user interface, your client side business logic, etc.

The app code only talks to the Hoodie frontend API, never directly to the server-side code, the database, or even the in-browser storage.

Hoodie uses PouchDB for storing data locally, which uses IndexedDb or WebSQL, whatever is available. Hoodie saves all data here first, before doing anything else. So if you’re offline, your data is safely stored locally.

This, by itself, is already enough for an app. But if you want to save your data remotely or send an email, for example, you’ll need a bit more.
Hoodie relies on CouchDB, the database that replicates. We use it to sync data back and forth between the server and the clients, which is something that CouchDB happens to be really good at.

A small aside: In CouchDB, each user has their own private database which only they can access, so all user data is private by default. It can be shared to the public if the user decides to do so, but it can’t happen by accident. This is why we’ll often mention sharing and global data as a separate feature.
Behind the database, we have the actual server code in the form of a small node.js core with various plugins running alongside it. These then act upon the data in the CouchDB, which then replicates the changes back to the clients.

So Hoodie does client ↔ database ↔ server instead of the traditional client ↔ server ↔ database, and this is where many of its superpowers come from.
The clever bit is indicated by the dotted line in the middle; the connection between clients and server can be severed at any time without breaking the system. Frontend and backend never talk directly to each other. They only leave each other messages and tasks. It’s all very loosely-coupled and event-based, and designed for eventual consistency.
Architecture¶
After installing hoodie, npm start
will run
cli/index.js
which reads out the configuration
from all the different places using the rc
package, then passes it as options to server/index.js
, the Hoodie core
hapi plugin.
In server/index.js,
the passed options are merged with defaults and parsed into configuration for
the Hapi server. It passes the configuration on to`hoodie-server <https://github.com/hoodiehq/hoodie-server#readme>`__,
which combines the core server modules. It also bundles the Hoodie
client on first request to /hoodie/client.js
and passes in the
configuration for the client. It also makes the app’s public
folder
accessible at the /
root path, and Hoodie’s Core UIs at
/hoodie/admin
, /hoodie/account
and /hoodie/store
.
Hoodie uses CouchDB for data
persistence. If options.dbUrl
is not set, it falls back to PouchDB.
Once all configuration is taken care of, the internal plugins are initialised (see server/plugins/index.js). We define simple Hapi plugins for logging and for serving the app’s public assets and the Hoodie client.
Once everything is setup, the server is then started at the end of cli/start.js and the URL where hoodie is running is logged to the terminal.
Modules¶
Hoodie is a server built on top of hapi with frontend APIs for account and store related tasks. It is split up in many small modules with the goal to lower the barrier to new code contributors and to share maintenance responsibilities.
-
Hoodie’s core server logic as hapi plugin. It integrates Hoodie’s server core modules: account-server, store-server
-
Hapi plugin that implements the Account JSON API routes and exposes a corresponding API at
server.plugins.account.api.*
. -
Hapi plugin that implements CouchDB’s Document API. Compatible with CouchDB and PouchDB for persistence.
-
-
Hoodie’s front-end client for the browser. It integrates Hoodie’s client core modules: account-client, store-client, connection-status and log
-
Client for the Account JSON API. It persists session information on the client and provides front-end friendly APIs for things like creating a user account, confirming, resetting a password, changing profile information, or closing the account.
-
Store client for data persistence and offline sync. It combines pouchdb-hoodie-api and pouchdb-hoodie-sync.
-
Browser library to monitor a connection status. It emits
disconnect
&reconnect
events if the request status changes and persists its status on the client. -
JavaScript library for logging to the browser console. If available, it takes advantage of CSS-based styling of console log outputs.
-
-
Hoodie’s built-in Admin Dashboard, built with Ember.js
Files & Folders¶
package.json¶
Contains a list of javascript addon packages hosted on npm. Hoodie includes a few addon packages but you can add more to the list if required. Addons provide additional features which you can use in your app. The npm website works as an addon package manager. It keeps track of specific versions of packages so your app won’t break if a new version of an addon is released.
README.md¶
The README file provides guidance about your app’s code for new users or contributors. It’s the place to describe what your app does and the motivation behind it. If you choose to host your code online using websites such as gitlab or github, the README file is displayed prominently on the project page. The file is saved in markdown format. This allows you to write in plain text or use the markdown language to add formatting such as hyperlinks and or headings.
.hoodie/¶
TO BE DONE: Describe .hoodie/ folder (caching of bundled client, data stored by PouchDB, ...)
hoodie/¶
TO BE DONE: Describe hoodie/ folder, extending app with hoodie/server/indexjs and hoodie/client/index.js.
public/¶
When you open your app in the browser you will see Hoodie’s default page telling you that your app has no public/ folder. So let’s create it
mkdir public
touch public/index.html
Now edit the public/index.html file and pass in the following content.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>My Hoodie App</title>
</head>
<body>
<h1>My Hoodie App</h1>
<script src="/hoodie/client.js"></script>
</body>
</html>
You need to stop the server now (ctrl + c) and start it again. If you reload your app in your browser, you will now see your HTML file.
The only line interesting for us is t
Requirements¶
Before you start working with Hoodie, here’s what you need to know regarding your development/server environment and the browsers Hoodie will run in.
System Requirements for Hoodie Server¶
- Mac OSX
- Windows 7 and up
- Linux (Ubuntu, Fedora 19+)
Browser Compatibilities (all latest stable)¶
- Firefox (29+)
- Chrome (34+)
- Desktop Safari (7+)
- Internet Explorer 10+
- Opera (21+)
- Android 4.3+
- iOS Safari (7.1+)
Important: This list is currently based on PouchDB’s requirements, since Hoodie is using PouchDB for its in-browser storage.
Glossary¶
CouchDB¶
CouchDB is a non-relational, document-based database that replicates, which means it’s really good at syncing data between multiple instances of itself. All data is stored as JSON, all indices (queries) are written in JavaScript, and it uses regular HTTP as its API.
PouchDB¶
PouchDB is an in-browser datastore inspired by CouchDB. It enables applications to store data locally while offline, then synchronize it with CouchDB.
hapi¶
hapi is a rich framework for building applications and services, enabling developers to focus on writing reusable application logic and not waste time with infrastructure logic. You can load hoodie as a hapi plugin to use it in your existing hapi application.
Users¶
Hoodie isn’t a CMS, but a backend for web apps, and as such, it is very much centered around users. All of the offline and sync features are specific to each individual user’s data, and each user’s data is encapsulated from that of all others by default. This allows Hoodie to easily know what to sync between a user’s clients and the server: simply all of the user’s private data.
Private User Store¶
Every user signed up with your Hoodie app has their private little database. Anything you do in the hoodie.store methods stores data in here.