Merge pull request #13 from strongloop/doc_edits

API Doc Style / Formatting
This commit is contained in:
Ritchie Martori 2013-08-27 08:44:04 -07:00
commit 989e9f398c
6 changed files with 621 additions and 482 deletions

View File

@ -6,6 +6,7 @@
"docs/gettingstarted.md",
"docs/resources.md",
"docs/concepts.md",
{"title": "API", "depth": 2},
"docs/api.md",
"docs/rest.md"
]

View File

@ -1,9 +1,10 @@
## API
## Node.js API
### App
Create a Loopback application.
```js
var loopback = require('loopback');
var app = loopback();
@ -12,17 +13,19 @@ Create a Loopback application.
});
app.listen(3000);
```
**Notes:**
- extends [express](http://expressjs.com/api.html#express)
- see [express docs](http://expressjs.com/api.html) for details
- supports [express / connect middleware](http://expressjs.com/api.html#middleware)
> **Notes**
>
> - extends [express](http://expressjs.com/api.html#express)
> - see [express docs](http://expressjs.com/api.html) for details
> - supports [express / connect middleware](http://expressjs.com/api.html#middleware)
#### app.model(Model)
Expose a `Model` to remote clients.
```js
// create a testing data source
var memory = loopback.memory();
var Color = memory.createModel('color', {name: String});
@ -30,18 +33,21 @@ Expose a `Model` to remote clients.
app.model(Color);
app.use(loopback.rest());
```
**Note:** this will expose all [shared methods](#shared-methods) on the model.
> **Note** - this will expose all [shared methods](#shared-methods) on the model.
#### app.models()
Get the app's exposed models.
```js
var models = app.models();
models.forEach(function (Model) {
console.log(Model.modelName); // color
});
```
#### app.docs(options)
@ -53,8 +59,10 @@ Enable swagger REST api documentation.
**Example**
```js
// enable docs
app.docs({basePath: 'http://localhost:3000'});
```
Run your app then navigate to [the api explorer](http://petstore.swagger.wordnik.com/). Enter your API basepath to view your generated docs.
@ -62,6 +70,7 @@ Run your app then navigate to [the api explorer](http://petstore.swagger.wordnik
A Loopback `Model` is a vanilla JavaScript class constructor with an attached set of properties and options. A `Model` instance is created by passing a data object containing properties to the `Model` constructor. A `Model` constructor will clean the object passed to it and only set the values matching the properties you define.
```js
// valid color
var Color = loopback.createModel('color', {name: String});
var red = new Color({name: 'red'});
@ -70,6 +79,7 @@ A Loopback `Model` is a vanilla JavaScript class constructor with an attached se
// invalid color
var foo = new Color({bar: 'bat baz'});
console.log(foo.bar); // undefined
```
**Properties**
@ -81,55 +91,71 @@ Some [DataSources](#data-source) may support additional `Model` options.
Define A Loopbackmodel.
```js
var User = loopback.createModel('user', {
first: String,
last: String,
age: Number
});
```
### Validation (expiremental)
#### Validation (expiremental)
#### Model.validatesFormatOf(property, options)
##### Model.validatesFormatOf(property, options)
Require a model to include a property that matches the given format.
```js
User.validatesFormat('name', {with: /\w+/});
```
#### Model.validatesPresenceOf(properties...)
##### Model.validatesPresenceOf(properties...)
Require a model to include a property to be considered valid.
```js
User.validatesPresenceOf('first', 'last', 'age');
```
#### Model.validatesLengthOf(property, options)
##### Model.validatesLengthOf(property, options)
Require a property length to be within a specified range.
```js
User.validatesLengthOf('password', {min: 5, message: {min: 'Password is too short'}});
```
#### Model.validatesInclusionOf(property, options)
##### Model.validatesInclusionOf(property, options)
Require a value for `property` to be in the specified array.
```js
User.validatesInclusionOf('gender', {in: ['male', 'female']});
```
#### Model.validatesExclusionOf(property, options)
##### Model.validatesExclusionOf(property, options)
Require a value for `property` to not exist in the specified array.
```js
User.validatesExclusionOf('domain', {in: ['www', 'billing', 'admin']});
```
#### Model.validatesNumericalityOf(property, options)
##### Model.validatesNumericalityOf(property, options)
Require a value for `property` to be a specific type of `Number`.
```js
User.validatesNumericalityOf('age', {int: true});
```
#### Model.validatesUniquenessOf(property, options)
##### Model.validatesUniquenessOf(property, options)
Ensure the value for `property` is unique in the collection of models.
```js
User.validatesUniquenessOf('email', {message: 'email is not unique'});
```
**Note:** not available for all [connectors](#connectors).
@ -139,15 +165,22 @@ Currently supported in these connectors:
- [Oracle](http://github.com/strongloop/loopback-connector-oracle)
- [MongoDB](http://github.com/strongloop/loopback-connector-mongodb)
#### myModel.isValid()
##### myModel.isValid()
Validate the model instance.
```js
user.isValid(function (valid) {
if (!valid) {
user.errors // hash of errors {attr: [errmessage, errmessage, ...], attr: ...}
console.log(user.errors);
// => hash of errors
// => {
// => username: [errmessage, errmessage, ...],
// => email: ...
// => }
}
});
```
#### Model.properties
@ -155,6 +188,7 @@ An object containing a normalized set of properties supplied to `loopback.create
Example:
```js
var props = {
a: String,
b: {type: 'Number'},
@ -166,9 +200,11 @@ Example:
var MyModel = loopback.createModel('foo', props);
console.log(MyModel.properties);
```
Outputs:
```js
{
"a": {type: String},
"b": {type: Number},
@ -183,11 +219,13 @@ Outputs:
"id": 1
}
}
```
#### Model.attachTo(dataSource)
Attach a model to a [DataSource](#data-source). Attaching a [DataSource](#data-source) updates the model with additional methods and behaviors.
```js
var oracle = loopback.createDataSource({
connector: require('loopback-connector-oracle'),
host: '111.22.333.44',
@ -197,6 +235,7 @@ Attach a model to a [DataSource](#data-source). Attaching a [DataSource](#data-s
});
User.attachTo(oracle);
```
**Note:** until a model is attached to a data source it will **not** have any **attached methods**.
@ -206,14 +245,17 @@ Mixins are added by attaching a vanilla model to a [data source](#data-source) w
Log the available methods for a memory data source.
```js
var ops = loopback
.createDataSource({connector: loopback.Memory})
.operations();
console.log(Object.keys(ops));
```
Outputs:
```js
[ 'create',
'updateOrCreate',
'upsert',
@ -238,15 +280,18 @@ Outputs:
'updateAttribute',
'updateAttributes',
'reload' ]
```
Here is the definition of the `count()` operation.
```js
{
accepts: [ { arg: 'where', type: 'object' } ],
http: { verb: 'get', path: '/count' },
remoteEnabled: true,
name: 'count'
}
```
#### Static Methods
@ -256,9 +301,11 @@ Here is the definition of the `count()` operation.
Create an instance of Model with given data and save to the attached data source. Callback is optional.
```js
User.create({first: 'Joe', last: 'Bob'}, function(err, user) {
console.log(user instanceof User); // true
});
```
**Note:** You must include a callback and use the created model provided in the callback if your code depends on your model being saved or having an `id`.
@ -266,9 +313,11 @@ Create an instance of Model with given data and save to the attached data source
Query count of Model instances in data source. Optional query param allows to count filtered set of Model instances.
```js
User.count({approved: true}, function(err, count) {
console.log(count); // 2081
});
```
##### Model.find(filter, callback)
@ -289,6 +338,7 @@ Find all instances of Model, matched by query. Fields used for filter and sort s
Find the second page of 10 users over age 21 in descending order exluding the password property.
```js
User.find({
where: {
age: {gt: 21}},
@ -299,6 +349,7 @@ Find the second page of 10 users over age 21 in descending order exluding the pa
},
console.log
);
```
**Note:** See the specific connector's [docs](#connectors) for more info.
@ -310,17 +361,21 @@ Delete all Model instances from data source. **Note:** destroyAll method does no
Find instance by id.
```js
User.findById(23, function(err, user) {
console.info(user.id); // 23
});
```
##### Model.findOne(where, callback)
Find a single instance that matches the given where expression.
```js
User.findOne({id: 23}, function(err, user) {
console.info(user.id); // 23
});
```
##### Model.upsert(data, callback)
@ -330,6 +385,7 @@ Update when record with id=data.id found, insert otherwise. **Note:** no setters
Define a static model method.
```js
User.login = function (username, password, fn) {
var passwordHash = hashPassword(password);
this.findOne({username: username}, function (err, user) {
@ -348,9 +404,11 @@ Define a static model method.
}
});
}
```
Setup the static model method to be exposed to clients as a [remote method](#remote-method).
```js
loopback.remoteMethod(
User.login,
{
@ -362,6 +420,7 @@ Setup the static model method to be exposed to clients as a [remote method](#rem
http: {path: '/sign-in'}
}
);
```
#### Instance Methods
@ -371,6 +430,7 @@ Setup the static model method to be exposed to clients as a [remote method](#rem
Save an instance of a Model to the attached data source.
```js
var joe = new User({first: 'Joe', last: 'Bob'});
joe.save(function(err, user) {
if(user.errors) {
@ -379,44 +439,54 @@ Save an instance of a Model to the attached data source.
console.log(user.id);
}
});
```
##### model.updateAttributes(data, [callback])
Save specified attributes to the attached data source.
```js
user.updateAttributes({
first: 'updatedFirst',
name: 'updatedLast'
}, fn);
```
##### model.destroy([callback])
Remove a model from the attached data source.
```js
model.destroy(function(err) {
// model instance destroyed
});
```
##### Custom Instance Methods
Define an instance method.
```js
User.prototype.logout = function (fn) {
MySessionModel.destroyAll({userId: this.id}, fn);
}
```
Define a remote model instance method.
loopback.remoteMethod(User.prototype.logout);
```js
loopback.remoteMethod(User.prototype.logout)
```
#### Remote Methods
Both instance and static methods can be exposed to clients. A remote method must accept a callback with the conventional `fn(err, result, ...)` signature.
##### loopback.remoteMethod(fn, [options]);
##### loopback.remoteMethod(fn, [options])
Expose a remote method.
```js
Product.stats = function(fn) {
var calc = require('./stats');
@ -433,10 +503,11 @@ Expose a remote method.
http: {path: '/info', verb: 'get'}
}
);
```
**Options**
- **accepts** - (optional) an arguments description specifying the remote method's arguments. A
- **accepts** - (optional) an arguments description specifying the remote method's arguments.
- **returns** - (optional) an arguments description specifying the remote methods callback arguments.
- **http** - (advanced / optional, object) http routing info
- **http.path** - the path relative to the model the method will be exposed at. May be a path fragment (eg. '/:myArg') which will be populated by an arg of the same name in the accepts description. For example the stats method above will be at the whole path `/products/stats`.
@ -446,6 +517,7 @@ Expose a remote method.
An arguments description defines either a single argument as an object or an ordered set of arguments as an array.
```js
// examples
{arg: 'myArg', type: 'number'}
@ -453,6 +525,7 @@ An arguments description defines either a single argument as an object or an ord
{arg: 'arg1', type: 'number', required: true},
{arg: 'arg2', type: 'array'}
]
```
**Types**
@ -467,6 +540,7 @@ Each argument may define any of the [loopback types](#loopback-types).
Run a function before or after a remote method is called by a client.
```js
// *.save === prototype.save
User.beforeRemote('*.save', function(ctx, user, next) {
if(ctx.user) {
@ -480,17 +554,21 @@ Run a function before or after a remote method is called by a client.
console.log('user has been saved', user);
next();
});
```
Remote hooks also support wildcards. Run a function before any remote method is called.
```js
// ** will match both prototype.* and *.*
User.beforeRemote('**', function(ctx, user, next) {
console.log(ctx.methodString, 'was invoked remotely'); // users.prototype.save was invoked remotely
next();
});
```
Other wildcard examples
```js
// run before any static method eg. User.find
User.beforeRemote('*', ...);
@ -511,6 +589,7 @@ Other wildcard examples
next();
});
```
#### Context
@ -536,21 +615,22 @@ The express ServerRequest object. [See full documentation](http://expressjs.com/
The express ServerResponse object. [See full documentation](http://expressjs.com/api.html#res).
Access the raw `req` object for the remote method call.
#### Relationships
##### Model.hasMany(Model)
Define a "one to many" relationship.
```js
// by referencing model
Book.hasMany(Chapter);
// specify the name
Book.hasMany('chapters', {model: Chapter});
```
Query and create the related models.
```js
Book.create(function(err, book) {
// create a chapter instance
// ready to be saved in the data source
@ -577,6 +657,7 @@ Query and create the related models.
console.log(chapters);
});
});
```
#### Shared Methods
@ -588,6 +669,7 @@ A Loopback `DataSource` provides [Models](#model) with the ability to manipulate
Define a data source for persisting models.
```js
var oracle = loopback.createDataSource({
connector: 'oracle',
host: '111.22.333.44',
@ -595,17 +677,21 @@ Define a data source for persisting models.
username: 'username',
password: 'password'
});
```
#### dataSource.createModel(name, properties, options)
Define a model and attach it to a `DataSource`.
```js
var Color = oracle.createModel('color', {name: String});
```
#### dataSource.discoverModelDefinitions([username], fn)
Discover a set of model definitions (table or collection names) based on tables or collections in a data source.
```js
oracle.discoverModelDefinitions(function (err, models) {
models.forEach(function (def) {
// def.name ~ the model name
@ -614,6 +700,7 @@ Discover a set of model definitions (table or collection names) based on tables
});
});
});
```
#### dataSource.discoverSchema([owner], name, fn)
@ -621,6 +708,7 @@ Discover the schema of a specific table or collection.
**Example schema from oracle connector:**
```js
{
"name": "Product",
"options": {
@ -711,6 +799,7 @@ Discover the schema of a specific table or collection.
}
}
}
```
#### dataSource.enableRemote(operation)
@ -721,6 +810,7 @@ Enable remote access to a data source operation. Each [connector](#connector) ha
Disable remote access to a data source operation. Each [connector](#connector) has its own set of set enabled and disabled operations. You can always list these by calling `dataSource.operations()`.
```js
// all rest data source operations are
// disabled by default
var oracle = loopback.createDataSource({
@ -731,6 +821,7 @@ Disable remote access to a data source operation. Each [connector](#connector) h
// or only disable it as a remote method
oracle.disableRemote('destroyAll');
```
**Notes:**
@ -746,6 +837,7 @@ List the enabled and disabled operations.
Output:
```js
{
find: {
remoteEnabled: true,
@ -762,14 +854,17 @@ Output:
},
...
}
```
#### Connectors
Create a data source with a specific connector. See **available connectors** for specific connector documentation.
```js
var memory = loopback.createDataSource({
connector: loopback.Memory
});
```
**Available Connectors**
@ -788,16 +883,19 @@ Create a data source with a specific connector. See **available connectors** for
Include the connector in your package.json dependencies and run `npm install`.
```js
{
"dependencies": {
"loopback-connector-oracle": "latest"
}
}
```
##### Memory Connector
The built-in memory connector allows you to test your application without connecting to an actual persistent data source, such as a database. Although the memory connector is very well tested it is not recommended to be used in production. Creating a data source using the memory connector is very simple.
```js
// use the built in memory function
// to create a memory data source
var memory = loopback.memory();
@ -826,6 +924,7 @@ The built-in memory connector allows you to test your application without connec
function count() {
Product.count(console.log); // 3
}
```
###### Operations
@ -841,37 +940,47 @@ The memory connector also supports geo-filtering when using the `find()` operati
Use the `GeoPoint` class.
```js
var GeoPoint = require('loopback').GeoPoint;
```
Embed a latitude / longitude point in a [Model](#model).
```js
var CoffeeShop = loopback.createModel('coffee-shop', {
location: 'GeoPoint'
});
```
Loopback Model's with a GeoPoint property and an attached DataSource may be queried using geo spatial filters and sorting.
Find the 3 nearest coffee shops.
```js
CoffeeShop.attachTo(oracle);
var here = new GeoPoint({lat: 10.32424, lng: 5.84978});
CoffeeShop.find({where: {location: {near: here}}, limit:3}, function(err, nearbyShops) {
console.info(nearbyShops); // [CoffeeShop, ...]
});
```
#### geoPoint.distanceTo(geoPoint, options)
Get the distance to another `GeoPoint`.
```js
var here = new GeoPoint({lat: 10, lng: 10});
var there = new GeoPoint({lat: 5, lng: 5});
console.log(here.distanceTo(there, {type: 'miles'})); // 438
```
#### GeoPoint.distanceBetween(a, b, options)
Get the distance between two points.
```js
GeoPoint.distanceBetween(here, there, {type: 'miles'}) // 438
```
#### Distance Types
@ -924,6 +1033,7 @@ Register and authenticate users of your app locally or against 3rd party service
Extend a vanilla Loopback model using the built in User model.
```js
// create a data source
var memory = loopback.memory();
@ -938,6 +1048,7 @@ Extend a vanilla Loopback model using the built in User model.
// expose over the app's api
app.model(User);
```
**Note:** By default the `loopback.User` model uses the `loopback.Session` model to persist sessions. You can change this by setting the `session` property.
@ -947,10 +1058,12 @@ Extend a vanilla Loopback model using the built in User model.
Create a user like any other model.
```js
// username and password are not required
User.create({email: 'foo@bar.com', password: 'bar'}, function(err, user) {
console.log(user);
});
```
##### Login a User
@ -959,14 +1072,17 @@ Create a session for a user using the local auth strategy.
**Node.js**
```js
User.login({username: 'foo', password: 'bar'}, function(err, session) {
console.log(session);
});
```
**REST**
You must provide a username and password over rest. To ensure these values are encrypted, include these as part of the body and make sure you are serving your app over https (through a proxy or using the https node server).
```
POST
/users/login
@ -983,11 +1099,13 @@ You must provide a username and password over rest. To ensure these values are e
"sid": "1234abcdefg",
"uid": "123"
}
```
##### Logout a User
**Node.js**
```js
// login a user and logout
User.login({"email": "foo@bar.com", "password": "bar"}, function(err, session) {
User.logout(session.id, function(err) {
@ -999,19 +1117,23 @@ You must provide a username and password over rest. To ensure these values are e
User.findOne({email: 'foo@bar.com'}, function(err, user) {
user.logout();
});
```
**REST**
```
POST /users/logout
...
{
"sid": "<session id from user login>"
}
```
##### Verify Email Addresses
Require a user to verify their email address before being able to login. This will send an email to the user containing a link to verify their address. Once the user follows the link they will be redirected to `/` and be able to login normally.
```js
User.requireEmailVerfication = true;
User.afterRemote('create', function(ctx, user, next) {
var options = {
@ -1026,35 +1148,41 @@ Require a user to verify their email address before being able to login. This wi
user.verify(options, next);
});
```
##### Send Reset Password Email
Send an email to the user's supplied email address containing a link to reset their password.
```js
User.reset(email, function(err) {
console.log('email sent');
});
```
##### Remote Password Reset
The password reset email will send users to a page rendered by loopback with fields required to reset the user's password. You may customize this template by defining a `resetTemplate` setting.
```js
User.settings.resetTemplate = 'reset.ejs';
```
##### Remote Password Reset Confirmation
Confirm the password reset.
```js
User.confirmReset(token, function(err) {
console.log(err || 'your password was reset');
});
```
#### Session Model
Identify users by creating sessions when they connect to your loopback app. By default the `loopback.User` model uses the `loopback.Session` model to persist sessions. You can change this by setting the `session` property.
```js
// define a custom session model
var MySession = loopback.Session.extend('my-session');
@ -1067,6 +1195,7 @@ Identify users by creating sessions when they connect to your loopback app. By d
// attach both Session and User to a data source
User.attachTo(loopback.memory());
MySession.attachTo(loopback.memory());
```
#### Email Model
@ -1076,7 +1205,9 @@ Send emails from your loopback app.
Expose models over rest using the `loopback.rest` router.
```js
app.use(loopback.rest());
```
**REST Documentation**
@ -1086,5 +1217,6 @@ View generated REST documentation by visiting: [http://localhost:3000/_docs](htt
**Coming Soon** - Expose models over socket.io using the `loopback.sio()` middleware.
```js
app.use(loopback.sio);
```

View File

@ -1,5 +1,9 @@
##Concepts
###SDKs
**PLACEHOLDER FOR SDK INTRO**
###Model
LoopBack is centered around models. A model is an object that encapsulates data. A model is usually named after its real life counterpart. Like its real life counterpart a model has properties or attributes.

View File

@ -1,13 +1,13 @@
##LoopBack
v1.0.0
**v1.0.0**
###Introduction
LoopBack is a mobile backend framework that puts you in control. As a mobile developer you decide where to run your mobile backend - in the cloud or on permise.
LoopBack is built on open source Node.js and leverages the power of Node and the community that stands behind Node.
LoopBack is here to help you develop mobile applications with rich functionality and data that is in your datacenter and the cloud.
Since LoopBack is built on open source, it is highly extensible and familiar with developers already using Node.
Node.js leverages Javascript. The ubiquituous language of the web that most developers have already had familiarity with it's ease of use.
> **Introduction**
>
> LoopBack is a mobile backend framework that puts you in control. As a mobile developer you decide where to run your mobile backend - in the cloud or on permise.
> LoopBack is built on open source Node.js and leverages the power of Node and the community that stands behind Node.
>
> LoopBack is here to help you develop mobile applications with rich functionality and data that is in your datacenter and the cloud.
> Since LoopBack is built on open source, it is highly extensible and familiar with developers already using Node.
> Node.js leverages Javascript. The ubiquituous language of the web that most developers have already had familiarity with it's ease of use.
---

View File

@ -21,3 +21,5 @@ $ slc run app
**Step 5** Try out the various REST apis by clicking the button below.
<a href="http://localhost:3000/explorer" class="status btn btn-primary">Explore the REST APIs</a>
---

View File

@ -1,9 +1,9 @@
#Model REST API
## REST API
LoopBack automatically binds a model to a list of HTTP endpoints that provide REST APIs for CRUD and other remote
operations.
##Sample Model
### Sample Model
We use the following `Location` model as an example to illustrate generated REST APIs.
@ -83,7 +83,7 @@ The remoting is defined using the following properties:
- returns: Description of the return value
- http: Binding to the HTTP endpoint
##Generated APIs
###Generated APIs
###create