Skip to content

Commit

Permalink
Merge pull request #2 from tb/master
Browse files Browse the repository at this point in the history
Rewrite with feathers-client
  • Loading branch information
josx authored Mar 14, 2017
2 parents 5d46647 + 7572969 commit d517d0c
Show file tree
Hide file tree
Showing 6 changed files with 177 additions and 117 deletions.
13 changes: 13 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# http://editorconfig.org
root = true

[*]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true

[*.md]
trim_trailing_whitespace = false
73 changes: 67 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,26 +1,87 @@
# feathers rest Client for admin-on-rest

For using [feathers](https://www.feathersjs.com) with [admin-on-rest](https://github.com/marmelab/admin-on-rest), convert AOR's REST dialect into one compatible with feathers.
For using [feathers](https://www.feathersjs.com) with [admin-on-rest](https://github.com/marmelab/admin-on-rest).

## Installation

```sh
npm install aor-feathers-client --save
```

## Usage
## Usage with stable

```js
// in src/feathersClient.js
import feathers from 'feathers-client';

const host = 'http://localhost:3030';

export default feathers()
.configure(feathers.hooks())
.configure(feathers.rest(host).fetch(window.fetch.bind(window)))
.configure(feathers.authentication({ storage: window.localStorage }));
```

```js
// in src/App.js
import React from 'react';
import { Admin, Resource } from 'admin-on-rest';
import { authClient, restClient } from 'aor-feathers-client';
import feathersClient from './feathersClient';
import { PostList } from './posts';

const App = () => (
<Admin
authClient={authClient(feathersClient)}
restClient={restClient(feathersClient)}
>
<Resource name="posts" list={PostList} />
</Admin>
);

export default App;
```

## Usage with Auk

```js
// in src/feathersClient.js
import feathers from 'feathers-client';
import hooks from 'feathers-hooks';
import rest from 'feathers-rest/client';
import authentication from 'feathers-authentication-client';

const host = 'http://localhost:3030';

export default feathers()
.configure(hooks())
.configure(rest(host).fetch(window.fetch.bind(window)))
.configure(authentication({
jwtStrategy: 'jwt',
storage: window.localStorage,
}));
```

```js
// in src/App.js
import React from 'react';
import { Admin, Resource } from 'admin-on-rest';
import feathersClient from 'aor-feathers-client';
import { authClient, restClient } from 'aor-feathers-client';
import feathersClient from './feathersClient';
import { PostList } from './posts';

const authClientOptions = {
storageKey: 'feathers-jwt',
authenticate: { strategy: 'local' },
};

const App = () => (
<Admin restClient={feathersClient('http://localhost:3030')}>
<Resource name="posts" list={PostList} />
</Admin>
<Admin
authClient={authClient(feathersClient, authClientOptions)}
restClient={restClient(feathersClient)}
>
<Resource name="posts" list={PostList} />
</Admin>
);

export default App;
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "aor-feathers-client",
"version": "0.1.0",
"version": "0.2.0",
"description": "A feathers client for admin-on-rest",
"main": "lib/index.js",
"scripts": {
Expand Down Expand Up @@ -33,7 +33,7 @@
},
"homepage": "https://github.com/josx/aor-feathers-client#readme",
"dependencies": {
"admin-on-rest": "^0.7.0"
"admin-on-rest": "^0.9.0"
},
"devDependencies": {
"babel-cli": "^6.18.0",
Expand Down
31 changes: 31 additions & 0 deletions src/authClient.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import {
AUTH_LOGIN,
AUTH_LOGOUT,
AUTH_CHECK,
} from 'admin-on-rest';

export default (client, options = {}) => (type, params) => {
const {
storageKey,
authenticate,
} = Object.assign({}, {
storageKey: 'token',
authenticate: { type: 'local' },
}, options);

switch (type) {
case AUTH_LOGIN:
const { username, password } = params;
return client.authenticate({
...authenticate,
email: username,
password,
});
case AUTH_LOGOUT:
return client.logout();
case AUTH_CHECK:
return localStorage.getItem(storageKey) ? Promise.resolve() : Promise.reject();
default:
throw new Error(`Unsupported FeathersJS authClient action type ${type}`);
}
};
111 changes: 2 additions & 109 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -1,109 +1,2 @@
import { queryParameters, fetchJson } from 'admin-on-rest/lib/util/fetch';

import {
GET_LIST,
GET_ONE,
CREATE,
UPDATE,
DELETE,
fetchUtils,
} from 'admin-on-rest/lib/rest/types';

/**
* Maps admin-on-rest queries to a feathers REST API
*
* @example
* GET_LIST => GET http://my.api.url/posts?$sort[title]=-1&$limit=10&$skip=10&title=value
* GET_ONE => GET http://my.api.url/posts/123
* UPDATE => PUT http://my.api.url/posts/123
* CREATE => POST http://my.api.url/posts/123
* DELETE => DELETE http://my.api.url/posts/123
*/
export default (apiUrl, httpClient = fetchJson) => {
/**
* @param {String} type One of the constants appearing at the top if this file, e.g. 'UPDATE'
* @param {String} resource Name of the resource to fetch, e.g. 'posts'
* @param {Object} params The REST request params, depending on the type
* @returns {Object} { url, options } The HTTP request parameters
*/
const convertRESTRequestToHTTP = (type, resource, params) => {
let url = '';
const options = {};
let query = {};
switch (type) {
case GET_LIST: {
const { page, perPage } = params.pagination;
const { field, order } = params.sort;

let sortKey = '$sort[' + field + ']';
let sortVal = (order === 'DESC') ? -1 : 1;
if(perPage && page) {
query['$limit'] = perPage;
query['$skip'] = perPage*(page-1);
}
if (order) {
query[sortKey] = JSON.stringify(sortVal);
}

Object.assign(query, params.filter);

url = `${apiUrl}/${resource}?${queryParameters(query)}`;
break;
}
case GET_ONE:
url = `${apiUrl}/${resource}/${params.id}`;
break;
case UPDATE:
url = `${apiUrl}/${resource}/${params.id}`;
options.method = 'PUT';
options.body = JSON.stringify(params.data);
break;
case CREATE:
url = `${apiUrl}/${resource}`;
options.method = 'POST';
options.body = JSON.stringify(params.data);
break;
case DELETE:
url = `${apiUrl}/${resource}/${params.id}`;
options.method = 'DELETE';
break;
default:
throw new Error(`Unsupported fetch action type ${type}`);
}
return { url, options };
};

/**
* @param {Object} response HTTP response from fetch()
* @param {String} type One of the constants appearing at the top if this file, e.g. 'UPDATE'
* @param {String} resource Name of the resource to fetch, e.g. 'posts'
* @param {Object} params The REST request params, depending on the type
* @returns {Object} REST response
*/
const convertHTTPResponseToREST = (response, type, resource, params) => {
const { headers, json } = response;
switch (type) {
case GET_LIST:
return {
data: json.data,
total: json.total
};
case CREATE:
return { ...params.data, id: json.id };
default:
return json;
}
};

/**
* @param {string} type Request type, e.g GET_LIST
* @param {string} resource Resource name, e.g. "posts"
* @param {Object} payload Request parameters. Depends on the request type
* @returns {Promise} the Promise for a REST response
*/
return (type, resource, params) => {
const { url, options } = convertRESTRequestToHTTP(type, resource, params);
return httpClient(url, options)
.then(response => convertHTTPResponseToREST(response, type, resource, params));
};
};
export authClient from './authClient';
export restClient from './restClient';
62 changes: 62 additions & 0 deletions src/restClient.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import {
GET_MANY,
GET_MANY_REFERENCE,
GET_LIST,
GET_ONE,
CREATE,
UPDATE,
DELETE,
} from 'admin-on-rest';

export default client => {
const mapRequest = (type, resource, params) => {
const service = client.service(resource);
let query = {};

switch (type) {
case GET_MANY:
case GET_MANY_REFERENCE:
case GET_LIST:
const {page, perPage} = params.pagination || {};
const {field, order} = params.sort || {};

let sortKey = '$sort[' + field + ']';
let sortVal = (order === 'DESC') ? -1 : 1;
if (perPage && page) {
query['$limit'] = perPage;
query['$skip'] = perPage * (page - 1);
}
if (order) {
query[sortKey] = JSON.stringify(sortVal);
}
Object.assign(query, params.filter);
return service.find({ query });
case GET_ONE:
return service.get(params.id);
case UPDATE:
return service.update(params.id, params.data);
case CREATE:
return service.create(params.data);
case DELETE:
return service.remove(params.id);
default:
throw new Error(`Unsupported FeathersJS restClient action type ${type}`);
}
};

const mapResponse = (response, type, resource, params) => {
switch (type) {
case GET_ONE:
case UPDATE:
return { data: response };
case CREATE:
return { data: {...params.data, id: response.id} };
default:
return response;
}
};

return (type, resource, params) =>
mapRequest(type, resource, params)
.then(response => mapResponse(response, type, resource, params));
}

0 comments on commit d517d0c

Please sign in to comment.