!CHAPTER The Users App The users app provides a username-based user storage JavaScript API that can be used in other Foxx apps. ```js var userStorage = Foxx.requireApp('/_users').userStorage; ``` !SECTION Exceptions !SUBSECTION User Not Found Indicates a user could not be found in the database. `new userStorage.errors.UserNotFound(userId)` Thrown by the user storage's *delete* and *get* methods if passed a user ID that does not exist in the database. @EXAMPLES ```js try { userStorage.get(invalidUserId); } catch(err) { assertTrue(err instanceof userStorage.errors.UserNotFound); } ``` !SUBSECTION Username Not Available Indicates a username is already in use. `new userStorage.errors.UsernameNotAvailable(username)` Thrown by the user storage's *create* method if passed a *userData* object with a *username* that is already in use. @EXAMPLES ```js try { userStorage.create({username: 'alreadyTaken'}); } catch(err) { assertTrue(err instanceof userStorage.errors.UsernameNotAvailable); } ``` !SECTION The user object User objects are instances of a Foxx model with the following attributes: * *userData*: application-specific user data. This is an arbitrary object that must at least have a *username* property set to the user's username. * *authData*: an arbitrary object used by authentication apps to store sensitive data. For password authentication this could be a hash, for third-party authentication services this could be information about the user's identity. This attribute should never be exposed to the user directly. !SECTION Create a user Creates and saves a new instance of the user model. `userStorage.create(userData)` Throws *UsernameNotAvailable* if a user with the given username already exists. *Parameter* * *userData*: an arbitrary object that will be stored as the user's *userData* attribute when the model is saved to the database. This object must at least have a *username* property set to a string. @EXAMPLES ```js var user = userStorage.create({username: 'malaclypse'}); assertEqual(user.get('userData').username, 'malaclypse'); ``` !SECTION Fetch an existing user There are two ways to fetch a user via the user storage API: * resolving a *username* with the user storage's *resolve* method * calling the user storage's *get* method with a user ID directly !SUBSECTION Resolve a *username* Fetches a user with a given *username*. `userStorage.resolve(username)` If the username can not be resolved, a *UserNotFound* exception will be thrown instead. *Parameter* * *username*: an arbitrary string matching the username of the user you are trying to fetch. @EXAMPLES ```js var user = userStorage.resolve('malaclypse'); assertEqual(user.get('userData').username, 'malaclypse'); ``` !SUBSECTION Resolve a user ID directly Fetches a user with a given ID. `userStorage.get(userId)` Attempts to fetch the user with the given ID from the database. If the user does not exist, a *UserNotFound* exception will be thrown instead. *Parameter* * *userId*: a user *_key*. @EXAMPLES ```js var user = userStorage.get(userId); assertEqual(user.get('_key'), userId); ``` !SECTION Delete a user There are two ways to delete a user from the database: * calling the user storage's *delete* method with a user ID directly * telling a user to delete itself !SUBSECTION Delete a user by its ID Delete a user with a given ID. `userStorage.delete(userId)` Attempts to delete the user with the given user ID from the database. If the user does not exist, a *UserNotFound* exception will be thrown. The method always returns *null*. *Parameter* * *userId*: a user *_key*. @EXAMPLES ```js userStorage.delete(userId); ``` !SUBSECTION Tell a user to delete itself Delete a user from the database. `user.delete()` Attempts to delete the user from the database. Returns *true* if the user was deleted successfully. Returns *false* if the user already didn't exist. @EXAMPLES ```js user.delete(); ``` !SECTION Save a user Save a user to the database. `user.save()` In order to commit changes made to the user in your code, you need to call this method. @EXAMPLES ```js var userData = user.get('userData'); userData.counter++; user.save(); ```