# Deployd

Deployd lets you quickly build secure, dynamic JavaScript and Mobile apps without writing backend code. Instead you boot a simple server that is very good at securely proxying requests to a storage layer such as a database. This enables your un-trusted client code to do things it never could before, such as write directly to a database without a custom application running in-between.

Instead of reinventing a protocol, deployd embraces HTTP. This means that any HTTP client, such as a JavaScript app, a mobile app, or even another server, can securely interact with your data without having to setup a web server and write a custom backend.

## Quick start

To install deployd locally you must have `npm` and a running instance of mongodb.

    [sudo] npm install deployd -g

First you'll want to generate an authentication key.

    dpd key

Copy the key for use in the dashboard. Then start the server.

    dpd listen

You can view the dashboard at `http://localhost:2403/__dashboard/`. It will prompt you for your auth key.

## How does it work?

### Resources

When deployd receives an HTTP request, it checks the first part of the URL to see which resource should handle the request:

- /todos/12345 - handled by the /todos resource
- /img/bg.jpg - handled by the /img resource
- /index.html - handled by the / resource

Once deployd knows what resource is being requested, it will validate the input, execute any event handlers you have defined and either return or store the result. You can create and configure resources and event handlers in the dashboard.

## REST API

REST is a web service design pattern that conforms closely to HTTP itself. In Deployd, HTTP methods or verbs have meaning:

- GET - Load a resource without modifying it (this is a browser's default method)
- POST - Create a resource, or send data to a special that doesn't fit within these methods
- PUT - Update an existing resource
- DELETE - Destroy an existing resource

In Deployd, HTTP response codes are also important:

- 200 OK - The request succeeded
- 204 No Content - The request succeeded, but there is no content to return (for example, after a deletion, or requesting an empty list)
- 400 Bad Request - The request did not pass validation. Change the parameters and try again.
- 401 Unauthorized - The request's session does not have permission to access that resource.
- 404 Not Found - That URL does not reference an existing resource
- 500 Internal Server Error - Deployd has failed to process the request due to an unexpected error.

## Cross-Origin AJAX

Deployd is configured so that you can easily develop a web app locally on your computer. It will send Access-Control-Allow-Origin HTTP headers if a request is coming from localhost or your filesystem, which will allow modern web browsers to use AJAX normally. It will not send these headers for any other domain.

# Collection Resource

A Collection resource allows client apps to save and query data.

## Setting up a collection

After creating a Collection resource in the dashboard, you can set up the schema that will automatically validate data sent to the resource url over HTTP. You can configure this schema in the dashboard.

The grid view below the property list allows you to edit the Collection manually.

## Property types

You can currently use the following property types:

- String - Arbritrary text data
- Number - Numeric value, supports floating points
- Boolean - True or false
- Date - A specific point in time

## Formats

When POSTing or PUTing data to a resource `/path`, you must format the request body as a JSON string and pass the header "Content-Type: application/json".

## Saving data

To save data, send a POST request to the root of the Collection:

    POST /people
    Content-Type: application/json
    {
      "age": 23,
      "firstName": "Joe",
      "lastName": "Smith"
    }

The server will respond with the object, which will have a new `_id` property.

    200 OK
    {
      "_id": "4f71fc7c2ba744786f000001",
      "age": 23,
      "firstName": "Joe",
      "lastName": "Smith"
    }

This `_id` is used to find the object's URL (i.e. `/people/4f71fc7c2ba744786f000001`)

## Listing data

A GET request to the root of the Collection will return an array of objects in the collection:

    GET /people

    200 OK
    [
      {
        "_id": "4f71fc7c2ba744786f000001",
        "age": 23,
        "firstName": "Joe",
        "lastName": "Smith"
      },
      {
        "_id": "4f71fe8b2ba744786f000002",
        "age": 36,
        "firstName": "John",
        "lastName": "Doe"
      }
    ]

## Retrieving a specific object

A GET request at an object's URL will return the properties of that object:

    GET /people/4f71fc7c2ba744786f000001

    200 OK
    {
      "_id": "4f71fc7c2ba744786f000001",
      "age": 23,
      "firstName": "Joe",
      "lastName": "Smith"
    }

## Updating an object

A PUT request at an object's URL will update the object. You must include all properties except for `_id`.

    PUT /people/4f71fc7c2ba744786f000001
    Content-Type: application/json
    {
      "age": 24,
      "firstName": "Fred",
      "lastName": "Smith"
    }

The server will respond with the entire object:

    200 OK
    {
      "_id": "4f71fc7c2ba744786f000001",
      "age": 24,
      "firstName": "Fred",
      "lastName": "Smith"
    }

## Deleting an object

A DELETE request at an object's URL will permanently remove that object from the collection:

    DELETE /people/4f71fc7c2ba744786f000001

    204 No Content

## Filtering results

You can add querystring parameters to a GET request at the root to filter the results by properties specified:

    GET /people?firstName=Joe&lastName=Smith

NOTE: This currently only works for String properties.

## Advanced querying

If you need to query additional types of properties, pass a JSON object as the `q` parameter with the properties you wish to filter:

    GET /people?q={
      "age": 23
    }

The `q` parameter supports MongoDB's query language for particularly advanced queries. Note that Collections do not currently support embedded documents or arrays.

    GET /people?q={
      "$orderby": { "age": 1 },
      "name": {
        "$regex": "^j"
        "$options": "i",
      }
    }

# Collection Event Handlers

You can attach micro-scripts to events to add logic and validation to your objects. Collections currently support the following events:

- On Get - called when data is read
- On Post - called when data is created
- On Put - called when data is updated
- On Delete - called when data is destroyed

## Reading and setting properties

In an event micro-script, the `this` object refers to the current object, and has all of the properties of the object.

You can set values on the `this` object during an On Post or On Put event. These changes will be saved to the database.

    // On Post:
    this.dateCreated = new Date();

    // On Put:
    this.totalScore = this.level1Points + this.level2Points;

## Accessing the current user

If the request is coming from a logged in User, you can use the "me" object to access their properties.

    // On Post:
    this.creator = me._id;

## Cancelling an event

You can stop any event by calling the `cancel(message, [code])` method.

    //On Delete:
    if (this.protected) {
      cancel('This post is protected and cannot be deleted');
    }

    DELETE /posts/123456

    400 Bad Request
    {
      "message": "This post is protected and cannot be deleted"
    }

You can pass an integer to the `cancel()` method as the second parameter to set the HTTP status code. For example, 401 means "Unauthorized".

    //On Put
    if (this.creator !== me._id) {
      cancel("You cannot view this post because it is not yours!", 401);
    }

    PUT /posts/13456
    Content-Type: application/json
    { ... }

    401 Unauthorized
    {
      "message": "You cannot view this post because it is not yours!"
    }

## Validation

Use the `error(name, message)` function to add a validation error.

    //On Post
    if (this.age < 18) {
      error('age', 'must be older than 18')
    }

    POST /people
    {
      "firstName": "Joe",
      "lastName": "Smith",
      "age": 12
    }

    400 Bad Request
    {
      errors: {
        "age": "must be older than 18"
      }
    }

## Hiding properties

If you wish to hide certain properties from a user, use the `hide(propertyName)` function.

    //On Get
    if (this.creator !== me._id) {
      hide('lastName');
      hide('age');
    }

## Protecting properties from modification

Use the `protect(propertyName)` function to protect specified properties during a POST or PUT.

    //On Put
    protect('createdDate');

# Files Resource

The Files Resource allows you host static files from your app, such as HTML, browser JavaScript, CSS, images, and videos.

## Accessing files

Send a GET request with the filename to load the raw file. This is how browsers request pages and files by default.

    GET /files/bg.jpg

## Folders

If you prefer to have separate folders for Javascript, CSS, and images, create multiple Static Resources at the paths you want to store the files.

You can also give a Static Resource an empty path `/`. This will assign it to the root of your app.

## Home page

If a Static Resource receives a request without a filename, it will automatically redirect to "index.html" if available.

# User Collection Resource

A User Collection resource behaves much like the standard Collection resource, but adds the ability to authenticate with a username and password.

## Special properties

The User Collection contains two special properties:

- email - For security, hidden by default on all users except the current user.
- password - Never readable under any circumstances. Can only be set when the user is logged in, when creating a new user, or from the Dashboard.

## Registering a user

First create a user by POSTing it to the root of the collection. For this example our collection will be called `/users`.

    POST /users
    Content-Type: application/json
    {
      "email": "foo@bar.com",
      "password": "barfoo"
    }

## Authenticating a user

To login a user, send a POST request to `/<collection name>/login`:

    POST /users/login
    Content-Type: application/json
    {
      "email": "foo@bar.com",
      "password": "barfoo"
    }

The server will respond with the user, without the password.

    200 OK
    {
      "_id": "4f71fc7c2ba744786f000001",
      "email": "foo@bar.com"
    }

## Current user

The currently logged in user is available by sending a GET request to `/users/me`.

    200 OK
    {
      "_id": "4f71fc7c2ba744786f000001",
      "email": "foo@bar.com"
    }

## Logging out

To logout a user send a POST request to `/<collection name>/logout`:

    204 No Content