Skip to content

Commit 09492ff

Browse files
author
Lee Richmond
committed
Add main docs
1 parent 30e128f commit 09492ff

File tree

1 file changed

+235
-0
lines changed

1 file changed

+235
-0
lines changed

docs/index.md

Lines changed: 235 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,235 @@
1+
# What It Is
2+
3+
This library provides an interface to APIs following the JSONAPI spec. Though we're not striving for 1:1 compatibility with Active Record, you'll see it's the same basic usage, from scopes to error handling.
4+
5+
# How to Use It
6+
7+
### Defining Models
8+
9+
The first step is to define your models. These will match the [resource objects](http://jsonapi.org/format/#document-resource-objects) returned from your API. Your code can be written in Typescript, ES6, or vanilla JS/Coffeescript.
10+
11+
Let's say we have a `/api/v1/people` endpoint:
12+
13+
```es6
14+
// es6 import syntax
15+
// vanilla JS would expose 'jsorm' as a global
16+
import { Model, attr } from 'jsorm';
17+
18+
var Person = Model.extend({
19+
static: {
20+
baseUrl: 'http://localhost:3000', // set to '' in browser for relative URLs
21+
apiNamespace: '/api/v1',
22+
jsonapiType: 'people'
23+
},
24+
25+
firstName: attr(),
26+
lastName: attr()
27+
});
28+
```
29+
30+
Alternatively, in Typescript:
31+
32+
```ts
33+
// typescript
34+
class Person extends Model {
35+
static baseUrl: 'http://localhost:3000';
36+
static apiNamespace: '/api/v1';
37+
static jsonapiType: 'people';
38+
39+
firstName: attr();
40+
lastName: attr();
41+
}
42+
```
43+
44+
**NB**: *Once your models are defined, you must call `Config.setup()`:
45+
46+
```js
47+
import { Config } from 'jsorm';
48+
Config.setup();
49+
```
50+
51+
## Basic Usage
52+
53+
### Querying
54+
55+
All queries are
56+
57+
* Chainable
58+
* Overrideable
59+
60+
Call `all()`, `first()`, or `find()` to actually fire the query.
61+
62+
All of the following examples can be chained together:
63+
64+
```es6
65+
let scope = new Person();
66+
if (should_include_admins) {
67+
scope = scope.where({ admin: true });
68+
}
69+
scope.all().then((people) => {
70+
people.map((p) => { return p.firstName; }); // => ['Joe', 'Jane', 'Bill']
71+
});
72+
73+
scope.page(2).all().then((people) => {
74+
people.map((p) => { return p.firstName; }); // => ['Chris', 'Sarah', 'Ben']
75+
});
76+
```
77+
78+
### Pagination
79+
80+
[JSONAPI Pagination Docs](http://jsonapi.org/format/#fetching-pagination)
81+
82+
Use `per` and `page`. To limit 10 per page, viewing the second page:
83+
84+
```es6
85+
Person.per(10).page(2).all();
86+
```
87+
88+
> GET /people?page[number]=2&page[size]=10
89+
90+
### Sorting
91+
92+
[JSONAPI Sorting Docs](http://jsonapi.org/format/#fetching-sorting)
93+
94+
Use `order`. Passing an attribute will default to ascending order.
95+
96+
Ascending:
97+
98+
```es6
99+
Person.order('name');
100+
```
101+
102+
> GET /people?sort=name
103+
104+
Descending:
105+
106+
```es6
107+
Person.order({ name: 'desc' });
108+
```
109+
110+
> GET /people?sort=-name
111+
112+
### Filtering
113+
114+
[JSONAPI Filtering Docs](http://jsonapi.org/format/#fetching-filtering)
115+
116+
Use `where`:
117+
118+
```es6
119+
Person.where({ name: 'Joe' }).where({ age: 30 }).all();
120+
```
121+
122+
> GET /people?filter[name]=Joe&filter[age]=30
123+
124+
Filters are based on swagger documentation, not object attributes. This means you can do stuff like:
125+
126+
```es6
127+
Person.where({ age_greater_than: 30 }).all();
128+
```
129+
130+
> GET /people?filter[age_greater_than]=30
131+
132+
Arrays are supported automatically, defaulting to an OR clause:
133+
134+
```es6
135+
Person.where({ name: ['Joe', 'Bill'] }).all();
136+
```
137+
138+
> GET /people?&filter[name][]=Joe&filter[name][]=Bill
139+
140+
### Sparse Fieldsets
141+
142+
[JSONAPI Sparse Fieldset Docs](http://jsonapi.org/format/#fetching-sparse-fieldsets)
143+
144+
Use `select`:
145+
146+
```es6
147+
Person.select({ people: ['name', 'age'] }).all();
148+
```
149+
150+
> GET /people?fields[people]=name,age
151+
152+
### Extra Fields
153+
154+
This functionality is enabled by [jsonapi_suite](https://jsonapi-suite.github.io/jsonapi_suite). It works the same as Sparse fieldsets, but is for requesting additional fields, not limiting them.
155+
156+
Use `selectExtra`:
157+
158+
```es6
159+
Person.selectExtra({ people: ['name', 'age'] }).all();
160+
```
161+
162+
> GET /people?extra_fields[people]=name,age
163+
164+
### Inclusion of Related Resources
165+
166+
[JSONAPI Docs on Includes (sideloads)](http://jsonapi.org/format/#fetching-includes)
167+
168+
Use `includes`. This can be a symbol, array, hash, or combination of all. In short - it works exactly like it works in ActiveRecord:
169+
170+
```es6
171+
// a person has many tags, and has many pets
172+
// a pet has many toys, and many tags
173+
Person.includes(['tags', { pets: ['toys', 'tags'] }]);
174+
```
175+
176+
> GET /people?include=tags,pets.toys,pets.tags
177+
178+
The included resources will now be present:
179+
180+
```es6
181+
Person.includes('tags').then((person) => {
182+
person.tags.map((t) => { return t.name; }); // #=> ['funny', 'smart']
183+
});
184+
```
185+
186+
> GET /people?include=tags
187+
188+
### Basic Finders
189+
190+
`all`, `first`, and `find` can be used in conjunction with scopes.
191+
192+
```es6
193+
Person.all();
194+
```
195+
196+
> GET /people
197+
198+
```es6
199+
scope = Person.where({ name: 'Bill' }) # no query
200+
scope.all(); # => fires query, returns a Promise that resolves to an array of Person objects
201+
```
202+
203+
> GET /people?filter[name]=bill
204+
205+
Use `first` to grab the first result:
206+
207+
```es6
208+
// Limits per_page to 1, result is first element in the array
209+
Person.where({ name: 'Bill' }).first().then((person) => {
210+
// ...
211+
});
212+
```
213+
214+
> GET /people?page[size]=1&page[number]=1&filter[name]=Bill
215+
216+
Finally, use `find` to find a record by ID. This will hit the `show` action.
217+
218+
### Debugging
219+
220+
By default we will use `console` to log to STDOUT (or the browser's console log). If you are using node and want more in-depth options, inject another logger (we suggest [winston](https://github.com/winstonjs/winston)):
221+
222+
```es6
223+
import { Config } from 'jsorm';
224+
let winston = require('winston');
225+
226+
winston.level = 'warn';
227+
Config.logger = winston;
228+
```
229+
230+
This will log colorized request/responses when the log_level is debug, and only the request when the log level is info.
231+
232+
### Support or Contact
233+
234+
* Create a Github Issue
235+

0 commit comments

Comments
 (0)