Skip to content

Commit

Permalink
Merge pull request #5 from yahoo/createclass
Browse files Browse the repository at this point in the history
Fetchr refactored for createFetchrClass and per-request instantiation
  • Loading branch information
Vijar committed Aug 20, 2014
2 parents 79e2cb7 + 6146609 commit 9bcd6c5
Show file tree
Hide file tree
Showing 14 changed files with 637 additions and 546 deletions.
100 changes: 83 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,35 +23,44 @@ Fetchr needs delicate set up to work properly.
On the server side, add the fetchr middleware into your express app.

```js
//...
var express = require('express'),
Fetcher = require('fetchr'),
fetcher = new Fetcher({}),
fetchr = require('fetchr'),
Fetcher = fetchr({
pathPrefix: '/myCustomAPIEndpoint'
}),
app = express();

app.use(fetcher.middleware(
pathPrefix: '/myCustomAPIEndpoint'
));
app.use(Fetcher.middleware());
//...
```

## 2. API pathPrefix

`pathPrefix` config option for the middleware is optional. Defaults to `/api`.

It is necessary to expose this prefix to the client side fetcher (`fetchr.client.js`) via a global variable, `window.fetcherPathPrefix`.

After setting up the middleware, you can get the pathPrefix by calling `fetcher.getPathPrefix()` and assign it to the global `window.fetcherPathPrefix`.

It is necessary to define this prefix on the client side fetcher (`fetchr.client.js`) just as on the server side.
```js
//...
var fetchr = require('fetchr'),
Fetcher = fetchr({
pathPrefix: '/myCustomAPIEndpoint'
});
//...
```

## 3. Register data fetchers for API and/or DB access

```js
//app.js
//...
var Fetcher = require('fetchr'),
fetcher = new Fetcher({}),
var fetchr = require('fetchr'),
Fetcher = fetchr({
pathPrefix: '/myCustomAPIEndpoint'
}),
myDataFetcher = require('./dataFetcher');

fetcher.addFetcher(myDataFetcher);
Fetcher.addFetcher(myDataFetcher);
//...
```

Expand All @@ -61,18 +70,75 @@ module.exports = {
//Name is required
name: 'data_api_fetcher',
//At least one of the CRUD methods is Required
read: function(resource, params, context, callback) {
read: function(req, resource, params, config, callback) {
//...
},
//other methods
//create: function(resource, params, body, context, callback) {},
//update: function(resource, params, body, context, callback) {},
//del: function(resource, params, context, callback) {}
//create: function(req, resource, params, body, config, callback) {},
//update: function(req, resource, params, body, config, callback) {},
//del: function(req, resource, params, config, callback) {}
}

```

## 4. Swap Fetchr <=> Fetchr.client
## 4. Instantiating the Fetchr Class

Data fetchers might need access to each individual request, for example, to get the current logged in user's session. For this reason, Fetcher will have to be instantiated once per request.

On the serverside, this requires fetcher to be instantiated per request, in express middleware.

On the clientside, this only needs to happen on page load.


```js
//app.js - server
//...
var express = require('express'),
fetchr = require('fetchr'),
Fetcher = fetchr({
pathPrefix: '/myCustomAPIEndpoint'
}),
app = express(),
myDataFetcher = require('./dataFetcher');

Fetcher.addFetcher(myDataFetcher);

app.use(Fetcher.middleware());

app.use(function(req, res, next) {
//instantiated fetcher with access to req object
var fetcher = new Fetcher({req: req});

fetcher.read('data_api_fetcher', {id: ###}, {}, function (err, data) {
//handle err and/or data returned from data fetcher in this callback
})
});

//...
```


```js
//app.js - client
//...
var fetchr = require('fetchr'),
Fetcher = fetchr({
pathPrefix: '/myCustomAPIEndpoint'
}),
fetcher = new Fetcher({
requireCrumb: false, // if crumbs should be required for each request, default: false
context: {
crumb: 'Ax89D94j', //optional crumb string to send back to server with each request. Validation should happen on server.
}
});
fetcher.read('data_api_fetcher', {id: ###}, {}, function (err, data) {
//handle err and/or data returned from data fetcher in this callback
})
//...
```


## 5. Swap Fetchr <=> Fetchr.client

Fetchr relies on a build process that swaps out `lib/fetchr.js` with `lib/fetchr.client.js` in the bundle that is generated for client side use. Usually the bundle is generated using tools like [webpack](http://webpack.github.io/) or [browserify](http://browserify.org/).

Expand Down
8 changes: 6 additions & 2 deletions examples/simple/client/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@
* Copyrights licensed under the New BSD License. See the accompanying LICENSE file for terms.
*/
var readFlickr = require('../shared/getFlickrPhotos'),
readFlickrClient;
readFlickrClient,
Fetcher = require('../shared/fetcherClass'),
fetcher = new Fetcher({
requireCrumb: false
});

//client specific callback
readFlickrClient = function(err, data) {
Expand All @@ -20,4 +24,4 @@ readFlickrClient = function(err, data) {
};

//client-server agnostic call for data
readFlickr(readFlickrClient);
readFlickr(fetcher, readFlickrClient);
12 changes: 8 additions & 4 deletions examples/simple/server/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,23 @@ var http = require('http'),
path = require('path'),
fs = require('fs'),
express = require('express'),
fetcher = require('../shared/fetcherInstance'),
Fetcher = require('../shared/fetcherClass'),
readFlickr = require('../shared/getFlickrPhotos'),
flickrFetcher = require('./fetchers/flickr'),
readFlickrServer,
templatePath = path.join(__dirname, '..', 'shared', 'index.html');

Fetcher.addFetcher(flickrFetcher);

var app = express();

app.use(fetcher.middleware());
app.use(Fetcher.middleware());


app.use('/server', function (req, res, next) {

var fetcher = new Fetcher({req: req});

//client specific callback
readFlickrServer = function(err, data) {
if(err) {
Expand All @@ -40,7 +45,7 @@ app.use('/server', function (req, res, next) {
};

//client-server agnostic call for data
readFlickr(readFlickrServer);
readFlickr(fetcher, readFlickrServer);

});

Expand All @@ -50,7 +55,6 @@ app.use(express.static(path.join(__dirname, '..', 'client', 'build')));
//For the index.html file
app.use('/client', function(req, res) {
var tpl = fs.readFileSync(templatePath, {encoding: 'utf8'});
tpl = tpl.replace('<script src="/app.js"></script>', '<script>window.fetcherPathPrefix = "' + fetcher.getPathPrefix() + '";</script><script src="/app.js"></script>');
res.send(tpl);
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@ var request = require('superagent'),
FlickrFetcher = {
name: 'flickr',
//At least one of the CRUD methods is Required
read: function(resource, params, context, callback) {
read: function(req, resource, params, config, callback) {
var paramsObj = {
api_key: flickr_api_key,
method: params.method || 'flickr.photos.getRecent',
per_page: parseInt(params.per_page, 10) || 10,
format: context.format || 'json',
nojsoncallback: context.nojsoncallback || 1
format: config.format || 'json',
nojsoncallback: config.nojsoncallback || 1
},
url = flickr_api_root + '?' + querystring.stringify(paramsObj);

Expand All @@ -28,9 +28,9 @@ FlickrFetcher = {
});
}
//TODO: other methods
//create: function(resource, params, body, context, callback) {},
//update: function(resource, params, body, context, callback) {},
//del: function(resource, params, context, callback) {}
//create: function(req, resource, params, body, config, callback) {},
//update: function(req, resource, params, body, config, callback) {},
//del: function(req, resource, params, config, callback) {}

};

Expand Down
6 changes: 6 additions & 0 deletions examples/simple/shared/fetcherClass.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
var fetchr = require('../../../libs/fetcher.js'),
Fetcher = fetchr({
pathPrefix: '/myapi'
});

module.exports = Fetcher;
9 changes: 0 additions & 9 deletions examples/simple/shared/fetcherInstance.js

This file was deleted.

3 changes: 1 addition & 2 deletions examples/simple/shared/getFlickrPhotos.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@
* Copyright 2014, Yahoo! Inc.
* Copyrights licensed under the New BSD License. See the accompanying LICENSE file for terms.
*/
var fetcher = require('./fetcherInstance');
module.exports = function flickrRead (callback) {
module.exports = function flickrRead (fetcher, callback) {
fetcher.read('flickr', {
method: 'flickr.photos.getRecent',
per_page: 5
Expand Down
5 changes: 3 additions & 2 deletions examples/simple/webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
* Copyright 2014, Yahoo! Inc.
* Copyrights licensed under the New BSD License. See the accompanying LICENSE file for terms.
*/
var webpack = require('webpack');
var webpack = require('webpack'),
path = require('path');
module.exports = {
entry: require.resolve('./client/app.js'),
output: {
Expand All @@ -11,6 +12,6 @@ module.exports = {
},
plugins: [
//Replace fetcher lib with client side fetcher lib
new webpack.NormalModuleReplacementPlugin(/^..\/..\/..\/index.js$/, require.resolve('fetchr/libs/fetcher.client.js'))
new webpack.NormalModuleReplacementPlugin(/^..\/..\/..\/libs\/fetcher.js$/, path.resolve('../../libs/fetcher.client.js'))
]
};
Loading

0 comments on commit 9bcd6c5

Please sign in to comment.