From f0c24b3dcc1e2fe5b4b6b2a8fea5d138044d82c5 Mon Sep 17 00:00:00 2001 From: Lars Krieger Date: Fri, 6 May 2016 16:26:44 +0200 Subject: [PATCH 001/343] Added support for pagination --- src/jsonapi.js | 19 +++++++++++++++++-- src/utils.js | 26 ++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/src/jsonapi.js b/src/jsonapi.js index 67ad317..096d3b9 100644 --- a/src/jsonapi.js +++ b/src/jsonapi.js @@ -7,7 +7,7 @@ import { updateOrInsertEntitiesIntoState, setIsInvalidatingForExistingEntity } from './state-mutation'; -import { apiRequest, noop, jsonContentTypes } from './utils'; +import { apiRequest, noop, jsonContentTypes, getPaginationUrl } from './utils'; import { API_SET_ENDPOINT_HOST, API_SET_ENDPOINT_PATH, API_SET_ACCESS_TOKEN, API_WILL_CREATE, API_CREATED, API_CREATE_FAILED, API_WILL_READ, API_READ, API_READ_FAILED, API_WILL_UPDATE, API_UPDATED, API_UPDATE_FAILED, API_WILL_DELETE, API_DELETED, API_DELETE_FAILED } from './constants'; @@ -139,7 +139,22 @@ export const readEndpoint = (endpoint, { .then(json => { dispatch(apiRead({ endpoint, ...json })); onSuccess(json); - resolve(json); + + const prevUrl = getPaginationUrl(json, 'prev', apiHost, apiPath); + const nextUrl = getPaginationUrl(json, 'next', apiHost, apiPath); + + const getPrevPage = () => dispatch(readEndpoint(prevUrl)); + const getNextPage = () => dispatch(readEndpoint(nextUrl)); + + const resObj = { + response: json, + pagination: { + getPrevPage: !prevUrl ? null : getPrevPage, + getNextPage: !nextUrl ? null : getNextPage, + } + }; + + resolve(resObj); }) .catch(error => { const err = error; diff --git a/src/utils.js b/src/utils.js index 3dc3dca..b3ffdff 100644 --- a/src/utils.js +++ b/src/utils.js @@ -29,3 +29,29 @@ export const apiRequest = (url, accessToken, options = {}) => { throw e; }); }; + +export const getPaginationUrl = (json, direction, host, path) => { + if (!json.links) { + return null; + } + + if (direction === 'next') { + if (!json.links.next) { + return null; + } + + return json.links.next + .replace(host, '') + .replace(`${path}/`, ''); + } + + if (direction === 'prev') { + if (!json.links.prev) { + return null; + } + + return json.links.prev + .replace(host, '') + .replace(`${path}/`, ''); + } +}; From c6fe0c255b3f92378dae2a5bb8ddbca45ac6543d Mon Sep 17 00:00:00 2001 From: ichi Date: Mon, 23 May 2016 17:19:14 +0900 Subject: [PATCH 002/343] Fixed API_{UPDATE|DELETE}_FAILED reducers. --- src/jsonapi.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/jsonapi.js b/src/jsonapi.js index 67ad317..69ee384 100644 --- a/src/jsonapi.js +++ b/src/jsonapi.js @@ -318,7 +318,7 @@ export const reducer = handleActions({ .toJS(); }, - [API_UPDATE_FAILED]: (rawState, { payload: entity }) => { + [API_UPDATE_FAILED]: (rawState, { payload: { entity } }) => { const { type, id } = entity; const state = Imm.fromJS(rawState); @@ -345,7 +345,7 @@ export const reducer = handleActions({ .toJS(); }, - [API_DELETE_FAILED]: (rawState, { payload: entity }) => { + [API_DELETE_FAILED]: (rawState, { payload: { entity } }) => { const { type, id } = entity; const state = Imm.fromJS(rawState); From e96fc3749c83147c334fe25c8d581a3f6252e4c2 Mon Sep 17 00:00:00 2001 From: Lars Krieger Date: Wed, 8 Jun 2016 15:16:34 +0200 Subject: [PATCH 003/343] Updated .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index e71a6cc..fd19fad 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,4 @@ node_modules .node_repl_history lib +.DS_Store From eb171c191b4cb7cdf44ac5ac5cb9f740a248335d Mon Sep 17 00:00:00 2001 From: Lars Krieger Date: Wed, 8 Jun 2016 15:19:31 +0200 Subject: [PATCH 004/343] Initial update of docs --- README.md | 134 +++++++++++++------------------------- docs/GettingStarted.md | 60 +++++++++++++++++ docs/HowToUse.md | 16 +++++ docs/apis/createEntity.md | 96 +++++++++++++++++++++++++++ docs/apis/deleteEntity.md | 74 +++++++++++++++++++++ docs/apis/readEndpoint.md | 53 +++++++++++++++ docs/apis/updateEntity.md | 94 ++++++++++++++++++++++++++ 7 files changed, 437 insertions(+), 90 deletions(-) create mode 100644 docs/GettingStarted.md create mode 100644 docs/HowToUse.md create mode 100644 docs/apis/createEntity.md create mode 100644 docs/apis/deleteEntity.md create mode 100644 docs/apis/readEndpoint.md create mode 100644 docs/apis/updateEntity.md diff --git a/README.md b/README.md index 0eefd6b..f9f9a3f 100644 --- a/README.md +++ b/README.md @@ -1,93 +1,47 @@ -Redux ❤️ JSON API ----------------- - -Redux actions, action creators and reducers to make life with [JSON API](http://jsonapi.org)s a breeze. - -# Features - -- Automatically maintains a state of all loaded entities -- Provides actions for - - Creating entity - - Reading endpoint - - Updating entity - - Deleting entity -- Automatically keeps reverse relationships up to date upon creation, update and delete - - This applies only to relationships where the name of the foreign key is directly adhered from entity type—but can be both plural or singular - -# Usage - -1. `npm install redux-json-api` -1. Enable JSON API reducer (examples assume that you've connected it to `state.api`) -1. Set up API hostname and path using the actions `setEndpointHost` and `setEndpointPath` -1. Configure access token with `setAccessToken` - -You're now good to go. So have a look the the available actions below. - -# State structure - -```json -{ - "api": { - "users": { - "data": [ - { - "type": "users", - "id": 1, - "attributes": { } - } - ], - "isInvalidating": "IS_DELETING" - }, - "isCreating": 0, - "isReading": 0, - "isUpdating": 0, - "isDeleting": 0, - "endpoint": { - "host": null, - "path": null, - "accessToken": null - } - } -} -``` - -Entity objects are 1-to-1 with the API response. - -# API - -## Options - -Each function accepts an options object with two callbacks: `onSuccess`, `onError`. - -## Create entity - -`createEntity(entity, options)` - -Pass a full resource object to `createEntity`. It will trigger a request to `POST /${entity.type}`. - -Expects the API to return `200 OK` with the newly created resource object in response body. - -## Read endpoint - -`readEndpoint(endpoint, options)` - -Provide the endpoint from where to read. E.g. `users/1/roles`. The module will read each entity and map them from their type specified. - -## Update entity - -`updateEntity(entity, options)` - -Pass your resource object to `updateEntity`. It will trigger a request to `PATCH /${entity.type}/${entity.id}`. - -Expects the API to return `200 OK` with the updated resource object in response body. - -## Delete entity - -`deleteEntity(entity.options)` - -Accept a resource object and triggers a request to `DELETE /${entity.type}/${entity.id}`. - -Expects the API to return `204 No content`. +# Introduction +Welcome to the __Redux JSON API__ we ❤️ JSON and we love simple api's. With this in mind was this libiary born. We strive to keep this libiary as small but as powerfull as possible so it would be easy adaptable into any `JSON API` stack enviroment. + +We would love all of you users, to open disscusions/issues with us, that can make this tool pleasent for all to use, and ther for give a better libiary in the end. And if you build somthing with it, please let us know so we can see the cool stuff you are doing! + +If there is anything that you feel is not documented, or could be refered better to such as things from `redux` let us know aswell. + +## Table of content +1. Introduction +2. Getting Started +3. How To Use +4. Api Overview +5. Good reads +6. Contribute +7. Contributors + +## [Getting Started](http://www.github.com) +## [How to use](http://www.github.com) +## API overview +1. [Read __createEntity()__](http://www.github.com) - Creating new entities +2. [Read __readEndpoint()__](http://www.github.com) - Retrive data from your database +3. [Read __updateEntity()__](http://www.github.com) - Update a given entity's values +4. [Read __deleteEntity()__](http://www.github.com) - Remove entity from your database + +## 5. Good reads +1. [__Redux__](http://www.github.com) - Read about redux and core principles. +2. [__JSON API__](http://www.jsonapi.org/) - Read about the specifications for JSON API. + +## 6. Contribute +The reason for this repository is to keep on a good and healty & simple api for _JSON API_, for Redux applications weahter you use it in _react_ or any other framework of choise. Feel like getting envolved into to this, then get cloning and follow our simple guide lines, if you just want to give feedback or report bug click that [issues](https://github.com/dixieio/redux-json-api/issues) button and lets talk about it. + +### Development Guidelines +We have a few simple guidelines for how to develop on the tool, and how to build and test it locally. +#### Test the code +Beside writing the cases that you might create, there is also a need for you to test the code localy in your project, this can be set up using the `npm link` [How to use npmn link](https://docs.npmjs.com/cli/link), before creating the link you would need to build the code. + +#### Build the code +To build the code for local testing purposed run `npm run build`, this will dist the code make it able to be a part of the node_modules packages in your applications repo. + +#### Create a PR +You have done really cool work, __KUDOS__! 🎉, now you want to contrubute the code and you create a _PR_, we will then review the pull request. + +## 7. Contributors +Made with love from the [Dixie](http://www.dixie.io) team, and our lovely [contributers](https://github.com/dixieio/redux-json-api/graphs/contributors)! * * * diff --git a/docs/GettingStarted.md b/docs/GettingStarted.md new file mode 100644 index 0000000..7530188 --- /dev/null +++ b/docs/GettingStarted.md @@ -0,0 +1,60 @@ +# Getting Started +Getting into using Redux JSON API is fairly simple and requires __3 Steps__ witch we will cover here. + +If you have already setup `redux-json-api` please go to the "How to use Redux JSON API", since this will strictly get the libiary set up. + +## 1. Instalation +To install `redux-json-api` go to your projects root (where your package.json is located) and run: + +`$ npm install redux-json-api --save` + +## 2. Combine reducers +To get data from `redux-json-api` you must reduce our reducer on to your own reducer, by using the `combineReducers` from `redux`. + +```javascript +// rootReducer.js +import { combineReducers } from 'redux'; +import { reducer as api } from 'redux-json-api'; + +export default combineReducers({ + api +}); +``` + +For sanity we have removed all other reducers from the `combineReducers` combined reducers will take an object of reducers, you are able to apply more reducers, such as your own. + +__NB:__ For this to work, its important that your store is setup with the `redux-thunk` middleware, not sure how to set up your store see this guide: "Setting up redux store with redux-thunk middleware" - + +Thanks to [__@justaskz__](https://github.com/justaskz) for pointing this out to us. + +## 3. Initialize redux-json-api +The last step you need to define is using the `setEndpointPath()` & `setEndpointHost()` this will set the `api.endpoint` that `redux-json-api` will use for when dispatchig various call's through the api. + +Its important to note, to do this as early as possible perfable in container that initializes your application so you are ready to call you endpoints when initial bootstrap is done. + +```javascript +// CoreLayout.js +import { setEndpointPath, setEndpointHost } from 'redux-json-api'; + +class CoreLayout extends Component { + + componentWillMount() { + const { dispatch } = this.props; + dispatch(setEndpointHost('my.app/')); + dispatch(setEndpointPath('api/v1/')); + } + + render() { + return ( +
+ ); + } + +} + +export default connect()(CoreLayout); +``` + +In this example are we using the CoreLayout witch is the first component to be rendered, we will before the component mount dispatch our `setEndpointHost` and `setEndpointPath` with strings that defines our api's path. + +__NB:__ A good practise would be to store these as a process enviromental variable. diff --git a/docs/HowToUse.md b/docs/HowToUse.md new file mode 100644 index 0000000..6b810e8 --- /dev/null +++ b/docs/HowToUse.md @@ -0,0 +1,16 @@ +# Introduction +In this section we will go through the simple _CRUD API_. There are 4 simple calls to get `redux-json-api` rocking. + +1. `createEntity(value: { object })` +2. `readEndpoint(value: 'string')` +3. `updateEntity(value: { object })` +4. `deleteEntity(value: { object })` + +__*Lets get cracking with this api*__ 🎈 + +__NB:__ _In the examples are we assuming that we have already set up a store that we can map to the components props through the `redux` `conect` higherOrderComponent, this will enhance our React component to have add the store keys to props, with our overriding your already excisting props._ + +## createEntity(value: { object }) +[Read the createEntity api](http://github.com) +## readEndpoint(value: 'string') +[Read the readEndpoint api](http://github.com) diff --git a/docs/apis/createEntity.md b/docs/apis/createEntity.md new file mode 100644 index 0000000..3c9f54f --- /dev/null +++ b/docs/apis/createEntity.md @@ -0,0 +1,96 @@ +## createEntity(value: { object }) +Dispatching the createEntity function will send a `POST` to the backend, providing it a JSON API compliant object (not sure what this is? head to our "Introduction page"). + +```javascript +const mapStateToProps = ({ CreateTask }) => ({ CreateTask }); + +import { createEntity } from 'redux-json-api' +class CreateTask extends Component { + constructor() { + super(); + + this.state = { + taskListId: 1 + task: 'New task created' + }; + } + + handleSubmit() { + const { dispatch } = this.props; + const entity = { + type: 'tasks', + attributes: { + task: this.state.task + }, + relationships: { + taskList: { + data: { + id: this.state.taskListId, + type: 'taskLists' + } + } + } + } + + dispatch(createEntity(entity)); + } + + render() { + return ( +
+ + +
+ ); + } + +} + +export default connect(mapStateToProps)(CreateTask); +``` + +When submitting the task the `redux-json-api` will dispatch the following actions: + +__API_WILL_CREATE__ +_This tells us what payload have been in the que for creation, and what the `redux-json-api` will ship to the backend_ +```javascript +action: { + payload: { + type: 'tasks', + attributes: { + task: 'New task created' + }, + relationships: { + taskList: { + data: { + id: 1 + type: 'taskLists' + } + } + } + } +} +``` + +__API_CREATED__ +_This tells us the response object that we get back from the sever, where the backend have stored it, given it a ID, and next time we want to call the `readEndpoint`this object will now show up with our tasks._ +```javascript +action: { + payload: { + id: '1' + type: 'tasks', + attributes: { + task: 'New task created', + completed: false + }, + relationships: { + taskList: { + data: { + id: '1', + type: 'taskLists' + } + } + } + } +} +``` diff --git a/docs/apis/deleteEntity.md b/docs/apis/deleteEntity.md new file mode 100644 index 0000000..5ebef33 --- /dev/null +++ b/docs/apis/deleteEntity.md @@ -0,0 +1,74 @@ +## deleteEntity(value: { object }) +Dispatching the deleteEntity function will send a `DELETE` to the backend, providing it a JSON API compliant object (not sure what this is? head to our "Introduction page"). + +```javascript +import { deleteEntity } from 'redux-json-api' +class TasksOverview extends Component { + deleteTask(task) { + const { dispatch } = this.props; + dispatch(deleteEntity(task)); + } + + render() { + return ( +
+
+

This tasks should be deleted

+
+
+
+ ); + } + +} + +export default connect(mapStateToProps)(TasksOverview); +``` + +When submitting the task the `redux-json-api` will dispatch the following actions: + +__API_WILL_DELETE__ +_This tells us what payload have been in the que for deletion, and what the `redux-json-api` will ship to the backend_ +```javascript +action: { + payload: { + type: 'tasks', + attributes: { + task: 'New task created', + completed: false + }, + relationships: { + taskList: { + data: { + id: 1 + type: 'taskLists' + } + } + } + } +} +``` + +__API_CREATED__ +_This tells us the response object that we deleted from the server._ +```javascript +action: { + payload: { + type: 'tasks', + attributes: { + task: 'New task created', + completed: false + }, + relationships: { + taskList: { + data: { + id: 1 + type: 'taskLists' + } + } + } + } +} +``` diff --git a/docs/apis/readEndpoint.md b/docs/apis/readEndpoint.md new file mode 100644 index 0000000..92a9105 --- /dev/null +++ b/docs/apis/readEndpoint.md @@ -0,0 +1,53 @@ +## createEntity(value: { object }) +Great now we just created a new entity in our database using the `createEntity` method, now we would like to display this to our users. + + +```javascript +import { readEndpoint } from 'redux-json-api'; + +const mapStateToProp = ({ + api: tasks +}) => ({ + tasks: (tasks || { data: [] }).data +}); + +class Tasks extends Component { + componentWillMount() { + const { dispatch } = this.props; + dispatch(readEndpoint('tasks')); //<-- + } + + render() { + return ( + {this.props.tasks} + ); + } + +} + +export default connect(mapStateToProp)(Tasks); +``` +For the fastest fetch of data, try to fetch all your data before your components mount, this will ensure that your data is being fetched as your component renders. + +When you have dispatched the `readEndpoint`method the reducer will run following actions: + +__API_WILL_READ__ +_This tells us that the `redux-json-api` will now call your backend with the payload given in this case a simple call to `/tasks´._ +```javascript +action: { + payload: '/tasks' +} +``` + +__API_READ__ +_This tells us what respond the server gave us, and what is being mapped to your `api` key in your redux store, it will tell you what `[data]` is fetched, what `[includes]` and what `endpoint` it came from, and will reduce it all down for you to simple query of your redux store._ +```javascript +action: { + payload: { + endpoint: '/tasks', + data: [{...}, {...}, {...}] + } +} +``` + +__NB:__ In this test case we dont get includes, but in the case where you are including data, they way we will store this in the redux store would be on the entity type key eg: `[{type: 'comments'}]` would be reduced on to your `api.comments` and the tasks that we fetched would be reduced to `api.tasks` diff --git a/docs/apis/updateEntity.md b/docs/apis/updateEntity.md new file mode 100644 index 0000000..3e472a6 --- /dev/null +++ b/docs/apis/updateEntity.md @@ -0,0 +1,94 @@ +## updateEntity(value: { object }) +Dispatching the createEntity function will send a `PATCH` to the backend, providing it a JSON API compliant object (not sure what this is? head to our "Introduction page"). + +```javascript +import { updateEntity } from 'redux-json-api' +class UpdateTask extends Component { + constructor() { + super(); + + this.state = { + taskListId: 1 + }; + } + + handleSubmit() { + const { dispatch } = this.props; + const entity = { + id: '1', + type: 'tasks', + attributes: { + task: 'New task string!' + }, + relationships: { + taskList: { + data: { + id: '1', + type: 'taskLists' + } + } + } + } + + dispatch(updateEntity(entity)); + } + + render() { + return ( +
+ + +
+ ); + } +} + +export default connect()(UpdateTask); +``` + +When updating the task the `redux-json-api` will dispatch the following actions: + +__API_WILL_UPDATE__ +_This tells us what payload have been in the que for update, and what the `redux-json-api` will ship to the backend_ +```javascript +action: { + payload: { + id: '1', + type: 'tasks', + attributes: { + task: 'New task string!' + }, + relationships: { + taskList: { + data: { + id: '1', + type: 'taskLists' + } + } + } + } +} +``` + +__API_UPDATED__ +_This tells us the response object that we get back from the sever, where the backend have updated the single fields we provoided. Be aware that only the `task` key have updaterd and our completed remains the same._ +```javascript +action: { + payload: { + id: '1', + type: 'tasks', + attributes: { + task: 'New task string!', + completed: false, + }, + relationships: { + taskList: { + data: { + id: '1', + type: 'taskLists' + } + } + } + } +} +``` From 2681b7c2610d10e661e3c5cfb0687820d6c2c49b Mon Sep 17 00:00:00 2001 From: Lars Krieger Date: Wed, 8 Jun 2016 15:30:10 +0200 Subject: [PATCH 005/343] Linked TOC --- README.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index f9f9a3f..ffa5af4 100644 --- a/README.md +++ b/README.md @@ -6,13 +6,13 @@ We would love all of you users, to open disscusions/issues with us, that can mak If there is anything that you feel is not documented, or could be refered better to such as things from `redux` let us know aswell. ## Table of content -1. Introduction -2. Getting Started -3. How To Use -4. Api Overview -5. Good reads -6. Contribute -7. Contributors +1. [Introduction](#introduction) +2. [Getting Started](#getting-started) +3. [How To Use](#how-to-use) +4. [Api Overview](#api-overview) +5. [Good reads](#good-reads) +6. [Contribute](#contribute) +7. [Contributors](#contributors) ## [Getting Started](http://www.github.com) ## [How to use](http://www.github.com) From 7c5d8b3c4e8398dd559066bcbf69289a93228265 Mon Sep 17 00:00:00 2001 From: Lars Krieger Date: Wed, 8 Jun 2016 15:30:17 +0200 Subject: [PATCH 006/343] Copy update --- docs/apis/createEntity.md | 2 +- docs/apis/deleteEntity.md | 2 +- docs/apis/updateEntity.md | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/apis/createEntity.md b/docs/apis/createEntity.md index 3c9f54f..d25fd40 100644 --- a/docs/apis/createEntity.md +++ b/docs/apis/createEntity.md @@ -1,5 +1,5 @@ ## createEntity(value: { object }) -Dispatching the createEntity function will send a `POST` to the backend, providing it a JSON API compliant object (not sure what this is? head to our "Introduction page"). +Dispatching the createEntity function will send a `POST` to the backend, providing it a JSON API compliant object (not sure what this is? head to our "Good reads section"). ```javascript const mapStateToProps = ({ CreateTask }) => ({ CreateTask }); diff --git a/docs/apis/deleteEntity.md b/docs/apis/deleteEntity.md index 5ebef33..f4df971 100644 --- a/docs/apis/deleteEntity.md +++ b/docs/apis/deleteEntity.md @@ -1,5 +1,5 @@ ## deleteEntity(value: { object }) -Dispatching the deleteEntity function will send a `DELETE` to the backend, providing it a JSON API compliant object (not sure what this is? head to our "Introduction page"). +Dispatching the deleteEntity function will send a `DELETE` to the backend, providing it a JSON API compliant object (not sure what this is? head to our "Good reads section"). ```javascript import { deleteEntity } from 'redux-json-api' diff --git a/docs/apis/updateEntity.md b/docs/apis/updateEntity.md index 3e472a6..f1b2b4a 100644 --- a/docs/apis/updateEntity.md +++ b/docs/apis/updateEntity.md @@ -1,5 +1,5 @@ ## updateEntity(value: { object }) -Dispatching the createEntity function will send a `PATCH` to the backend, providing it a JSON API compliant object (not sure what this is? head to our "Introduction page"). +Dispatching the createEntity function will send a `PATCH` to the backend, providing it a JSON API compliant object (not sure what this is? head to our "Good reads section"). ```javascript import { updateEntity } from 'redux-json-api' From 989323664421afe1210c53517c22683ce550e24f Mon Sep 17 00:00:00 2001 From: Lars Krieger Date: Wed, 8 Jun 2016 15:33:03 +0200 Subject: [PATCH 007/343] Updated toc links --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index ffa5af4..e0da4a5 100644 --- a/README.md +++ b/README.md @@ -22,11 +22,11 @@ If there is anything that you feel is not documented, or could be refered better 3. [Read __updateEntity()__](http://www.github.com) - Update a given entity's values 4. [Read __deleteEntity()__](http://www.github.com) - Remove entity from your database -## 5. Good reads +## Good reads 1. [__Redux__](http://www.github.com) - Read about redux and core principles. 2. [__JSON API__](http://www.jsonapi.org/) - Read about the specifications for JSON API. -## 6. Contribute +## Contribute The reason for this repository is to keep on a good and healty & simple api for _JSON API_, for Redux applications weahter you use it in _react_ or any other framework of choise. Feel like getting envolved into to this, then get cloning and follow our simple guide lines, if you just want to give feedback or report bug click that [issues](https://github.com/dixieio/redux-json-api/issues) button and lets talk about it. ### Development Guidelines @@ -40,7 +40,7 @@ To build the code for local testing purposed run `npm run build`, this will dist #### Create a PR You have done really cool work, __KUDOS__! 🎉, now you want to contrubute the code and you create a _PR_, we will then review the pull request. -## 7. Contributors +## Contributors Made with love from the [Dixie](http://www.dixie.io) team, and our lovely [contributers](https://github.com/dixieio/redux-json-api/graphs/contributors)! * * * From 096945d31cb8c63f822e46ea452772f5c64ca96d Mon Sep 17 00:00:00 2001 From: Lars Krieger Date: Wed, 8 Jun 2016 15:35:12 +0200 Subject: [PATCH 008/343] Removed prev. footer --- README.md | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/README.md b/README.md index e0da4a5..3c12934 100644 --- a/README.md +++ b/README.md @@ -41,10 +41,4 @@ To build the code for local testing purposed run `npm run build`, this will dist You have done really cool work, __KUDOS__! 🎉, now you want to contrubute the code and you create a _PR_, we will then review the pull request. ## Contributors -Made with love from the [Dixie](http://www.dixie.io) team, and our lovely [contributers](https://github.com/dixieio/redux-json-api/graphs/contributors)! - -* * * - -Made with ❤️ by Team [Dixie][dixie] - - [dixie]: http://dixie.io +Made with ❤️ from the [Dixie](http://www.dixie.io) team, and our lovely [contributers](https://github.com/dixieio/redux-json-api/graphs/contributors)! From 16af2ff13582c9aec9706d0b1d048d57a4881c88 Mon Sep 17 00:00:00 2001 From: Lars Krieger Date: Wed, 8 Jun 2016 15:37:48 +0200 Subject: [PATCH 009/343] Added sosmne relative links --- README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 3c12934..241bd6b 100644 --- a/README.md +++ b/README.md @@ -14,13 +14,13 @@ If there is anything that you feel is not documented, or could be refered better 6. [Contribute](#contribute) 7. [Contributors](#contributors) -## [Getting Started](http://www.github.com) -## [How to use](http://www.github.com) +## [Getting Started](docs/GettingStarted.md) +## [How to use](docs/HowToUse.md) ## API overview -1. [Read __createEntity()__](http://www.github.com) - Creating new entities -2. [Read __readEndpoint()__](http://www.github.com) - Retrive data from your database -3. [Read __updateEntity()__](http://www.github.com) - Update a given entity's values -4. [Read __deleteEntity()__](http://www.github.com) - Remove entity from your database +1. [Read __createEntity()__](docs/apis/createEntity.md) - Creating new entities +2. [Read __readEndpoint()__](docs/apis/readEndpoint.md) - Retrive data from your database +3. [Read __updateEntity()__](docs/apis/updateEntity.md) - Update a given entity's values +4. [Read __deleteEntity()__](docs/apis/deleteEntity.md) - Remove entity from your database ## Good reads 1. [__Redux__](http://www.github.com) - Read about redux and core principles. From a24ba02387ba1039641b4ce830aaac4d9cf615bb Mon Sep 17 00:00:00 2001 From: Lars Krieger Date: Wed, 8 Jun 2016 15:41:27 +0200 Subject: [PATCH 010/343] Added even more realative links --- docs/HowToUse.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/docs/HowToUse.md b/docs/HowToUse.md index 6b810e8..e481274 100644 --- a/docs/HowToUse.md +++ b/docs/HowToUse.md @@ -11,6 +11,10 @@ __*Lets get cracking with this api*__ 🎈 __NB:__ _In the examples are we assuming that we have already set up a store that we can map to the components props through the `redux` `conect` higherOrderComponent, this will enhance our React component to have add the store keys to props, with our overriding your already excisting props._ ## createEntity(value: { object }) -[Read the createEntity api](http://github.com) +[Read the createEntity api](apis/createEntity.md) ## readEndpoint(value: 'string') -[Read the readEndpoint api](http://github.com) +[Read the readEndpoint api](apis/readEndpoint.md) +## updateEntity(value: { object }) +[Read the updateEntity api](apis/updateEntity.md) +## deleteEntity(value: { object }) +[Read the deleteEntity api](apis/deleteEntity.md) From 5440737fa3cc5a03c989b287471d6895cfb3be73 Mon Sep 17 00:00:00 2001 From: Lars Krieger Date: Wed, 8 Jun 2016 15:49:25 +0200 Subject: [PATCH 011/343] Updated copy --- docs/GettingStarted.md | 2 +- docs/HowToUse.md | 2 -- docs/apis/createEntity.md | 19 ++++--------------- docs/apis/deleteEntity.md | 1 - docs/apis/readEndpoint.md | 10 +--------- docs/apis/updateEntity.md | 11 +---------- 6 files changed, 7 insertions(+), 38 deletions(-) diff --git a/docs/GettingStarted.md b/docs/GettingStarted.md index 7530188..75ca819 100644 --- a/docs/GettingStarted.md +++ b/docs/GettingStarted.md @@ -57,4 +57,4 @@ export default connect()(CoreLayout); In this example are we using the CoreLayout witch is the first component to be rendered, we will before the component mount dispatch our `setEndpointHost` and `setEndpointPath` with strings that defines our api's path. -__NB:__ A good practise would be to store these as a process enviromental variable. +__NB:__ A good practise would be to store these as a process enviromental variables. diff --git a/docs/HowToUse.md b/docs/HowToUse.md index e481274..af97ca6 100644 --- a/docs/HowToUse.md +++ b/docs/HowToUse.md @@ -8,8 +8,6 @@ In this section we will go through the simple _CRUD API_. There are 4 simple cal __*Lets get cracking with this api*__ 🎈 -__NB:__ _In the examples are we assuming that we have already set up a store that we can map to the components props through the `redux` `conect` higherOrderComponent, this will enhance our React component to have add the store keys to props, with our overriding your already excisting props._ - ## createEntity(value: { object }) [Read the createEntity api](apis/createEntity.md) ## readEndpoint(value: 'string') diff --git a/docs/apis/createEntity.md b/docs/apis/createEntity.md index d25fd40..586ac07 100644 --- a/docs/apis/createEntity.md +++ b/docs/apis/createEntity.md @@ -2,30 +2,19 @@ Dispatching the createEntity function will send a `POST` to the backend, providing it a JSON API compliant object (not sure what this is? head to our "Good reads section"). ```javascript -const mapStateToProps = ({ CreateTask }) => ({ CreateTask }); - import { createEntity } from 'redux-json-api' class CreateTask extends Component { - constructor() { - super(); - - this.state = { - taskListId: 1 - task: 'New task created' - }; - } - handleSubmit() { const { dispatch } = this.props; const entity = { type: 'tasks', attributes: { - task: this.state.task + task: 'New task name' }, relationships: { taskList: { data: { - id: this.state.taskListId, + id: '1', type: 'taskLists' } } @@ -38,7 +27,7 @@ class CreateTask extends Component { render() { return (
- +
); @@ -46,7 +35,7 @@ class CreateTask extends Component { } -export default connect(mapStateToProps)(CreateTask); +export default connect()(CreateTask); ``` When submitting the task the `redux-json-api` will dispatch the following actions: diff --git a/docs/apis/deleteEntity.md b/docs/apis/deleteEntity.md index f4df971..703735a 100644 --- a/docs/apis/deleteEntity.md +++ b/docs/apis/deleteEntity.md @@ -26,7 +26,6 @@ class TasksOverview extends Component { export default connect(mapStateToProps)(TasksOverview); ``` - When submitting the task the `redux-json-api` will dispatch the following actions: __API_WILL_DELETE__ diff --git a/docs/apis/readEndpoint.md b/docs/apis/readEndpoint.md index 92a9105..e87ae83 100644 --- a/docs/apis/readEndpoint.md +++ b/docs/apis/readEndpoint.md @@ -4,13 +4,6 @@ Great now we just created a new entity in our database using the `createEntity` ```javascript import { readEndpoint } from 'redux-json-api'; - -const mapStateToProp = ({ - api: tasks -}) => ({ - tasks: (tasks || { data: [] }).data -}); - class Tasks extends Component { componentWillMount() { const { dispatch } = this.props; @@ -25,9 +18,8 @@ class Tasks extends Component { } -export default connect(mapStateToProp)(Tasks); +export default connect()(Tasks); ``` -For the fastest fetch of data, try to fetch all your data before your components mount, this will ensure that your data is being fetched as your component renders. When you have dispatched the `readEndpoint`method the reducer will run following actions: diff --git a/docs/apis/updateEntity.md b/docs/apis/updateEntity.md index f1b2b4a..9592324 100644 --- a/docs/apis/updateEntity.md +++ b/docs/apis/updateEntity.md @@ -4,14 +4,6 @@ Dispatching the createEntity function will send a `PATCH` to the backend, provid ```javascript import { updateEntity } from 'redux-json-api' class UpdateTask extends Component { - constructor() { - super(); - - this.state = { - taskListId: 1 - }; - } - handleSubmit() { const { dispatch } = this.props; const entity = { @@ -36,7 +28,7 @@ class UpdateTask extends Component { render() { return (
- +
); @@ -45,7 +37,6 @@ class UpdateTask extends Component { export default connect()(UpdateTask); ``` - When updating the task the `redux-json-api` will dispatch the following actions: __API_WILL_UPDATE__ From ffbcdbf136e6c68f76d30e8ac13e067946506abe Mon Sep 17 00:00:00 2001 From: Lars Krieger Date: Wed, 8 Jun 2016 15:49:57 +0200 Subject: [PATCH 012/343] Changed herader for How To Use MD --- docs/HowToUse.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/HowToUse.md b/docs/HowToUse.md index af97ca6..42042fe 100644 --- a/docs/HowToUse.md +++ b/docs/HowToUse.md @@ -1,4 +1,4 @@ -# Introduction +# How to use In this section we will go through the simple _CRUD API_. There are 4 simple calls to get `redux-json-api` rocking. 1. `createEntity(value: { object })` From 4bc0dacf66136139cc073144ad0c092e59b896dc Mon Sep 17 00:00:00 2001 From: Lars Krieger Date: Wed, 8 Jun 2016 16:24:02 +0200 Subject: [PATCH 013/343] Updated How To use --- docs/HowToUse.md | 5 ----- 1 file changed, 5 deletions(-) diff --git a/docs/HowToUse.md b/docs/HowToUse.md index 42042fe..128c2ec 100644 --- a/docs/HowToUse.md +++ b/docs/HowToUse.md @@ -1,11 +1,6 @@ # How to use In this section we will go through the simple _CRUD API_. There are 4 simple calls to get `redux-json-api` rocking. -1. `createEntity(value: { object })` -2. `readEndpoint(value: 'string')` -3. `updateEntity(value: { object })` -4. `deleteEntity(value: { object })` - __*Lets get cracking with this api*__ 🎈 ## createEntity(value: { object }) From 5d5b410344ea89d5c1f7256faba7b4a6aeefe5da Mon Sep 17 00:00:00 2001 From: Lars Krieger Date: Wed, 8 Jun 2016 17:21:36 +0200 Subject: [PATCH 014/343] Added a npm lint script and a eslintignore --- .eslintignore | 6 ++++++ package.json | 3 ++- 2 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 .eslintignore diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000..bf780f2 --- /dev/null +++ b/.eslintignore @@ -0,0 +1,6 @@ +coverage/** +node_modules/** +dist/** +lib/** +*.spec.js +src/index.html diff --git a/package.json b/package.json index 7ed6b27..3fad1c9 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,8 @@ "scripts": { "build": "rimraf lib && babel ./src -d lib", "test": "mocha --compilers js:babel-core/register --recursive", - "test:watch": "npm test -- --watch" + "test:watch": "npm test -- --watch", + "lint": "eslint . ./" }, "repository": { "type": "git", From fac9791bdc6aad99b50221f6fdcd03beeb06f75e Mon Sep 17 00:00:00 2001 From: Lars Krieger Date: Wed, 8 Jun 2016 17:26:10 +0200 Subject: [PATCH 015/343] Added simple travis file --- .travis.yml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..4273d49 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,5 @@ +language: node_js +node_js: + - "4" +before_install: + - "console.log('Hello World')" From dfd645677ebb3ba4b48862ec9d2b015bbf4df06d Mon Sep 17 00:00:00 2001 From: Lars Krieger Date: Wed, 8 Jun 2016 17:29:01 +0200 Subject: [PATCH 016/343] Test Travis push on branch --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 4273d49..408b694 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,4 +2,4 @@ language: node_js node_js: - "4" before_install: - - "console.log('Hello World')" + - "console.log('Hello World, you are awesome')" From 00a87b8c4c5dbd84ab820648f4ad31cab7b0b8db Mon Sep 17 00:00:00 2001 From: Lars Krieger Date: Wed, 8 Jun 2016 17:30:57 +0200 Subject: [PATCH 017/343] Removed Travis before install --- .travis.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 408b694..63f7b35 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,3 @@ language: node_js node_js: - "4" -before_install: - - "console.log('Hello World, you are awesome')" From 7dbb10768451da7b46b90d5019589de9d9b0a069 Mon Sep 17 00:00:00 2001 From: Lars Krieger Date: Wed, 8 Jun 2016 17:34:52 +0200 Subject: [PATCH 018/343] Added after install npm run lint to travis --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index 63f7b35..0f7a64c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,3 +1,5 @@ language: node_js node_js: - "4" +after_install: + - "npm run lint" From 08c3a10b90d313700383c7f42087429004e3ec23 Mon Sep 17 00:00:00 2001 From: Lars Krieger Date: Wed, 8 Jun 2016 17:41:00 +0200 Subject: [PATCH 019/343] Created Scripts for travis to run after install of npm --- .travis.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 0f7a64c..3bed091 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,6 @@ language: node_js node_js: - - "4" -after_install: + - "4.0.0" +script: - "npm run lint" + - "npm test" From 3485d9614f44c4b7f5c43f34103162fd41100116 Mon Sep 17 00:00:00 2001 From: Lars Krieger Date: Wed, 8 Jun 2016 17:45:09 +0200 Subject: [PATCH 020/343] Fixed Linting error --- src/utils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils.js b/src/utils.js index 3f437f5..b1bd345 100644 --- a/src/utils.js +++ b/src/utils.js @@ -10,7 +10,7 @@ export const apiRequest = (url, accessToken, options = {}) => { headers: { Authorization: `Bearer ${accessToken}`, 'Content-Type': 'application/vnd.api+json', - 'Accept': 'application/vnd.api+json' + Accept: 'application/vnd.api+json' }, ...options }; From 913d824498bfd680b08ed8c63291fbc98de41863 Mon Sep 17 00:00:00 2001 From: Lars Krieger Date: Wed, 8 Jun 2016 17:50:49 +0200 Subject: [PATCH 021/343] Updated Versions of node for travis --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 3bed091..4dd9601 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,7 @@ language: node_js node_js: - - "4.0.0" + - "0.12" + - "iojs" script: - "npm run lint" - "npm test" From 95a64f34fda0b293379c712b3ba35f7b12ffef86 Mon Sep 17 00:00:00 2001 From: Lars Krieger Date: Wed, 8 Jun 2016 17:54:18 +0200 Subject: [PATCH 022/343] Set travis node version to strictly v4 --- .travis.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 4dd9601..187886e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,6 @@ language: node_js node_js: - - "0.12" - - "iojs" + - "4" script: - "npm run lint" - "npm test" From 09529cae95c2e7051587f141b13dfa50c0cc9475 Mon Sep 17 00:00:00 2001 From: Lars Krieger Date: Thu, 9 Jun 2016 09:37:07 +0200 Subject: [PATCH 023/343] Removed not needed quotes and moved lint to before scripts --- .travis.yml | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 187886e..c764b51 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,5 @@ language: node_js node_js: - - "4" -script: - - "npm run lint" - - "npm test" + - 4 +before_script: + - npm run lint From 207f9c5b4110cbc1197cb8148ff315f3c2b9f90f Mon Sep 17 00:00:00 2001 From: Lars Krieger Date: Thu, 9 Jun 2016 10:24:06 +0200 Subject: [PATCH 024/343] Travis ci test linter with exit 0 --- package.json | 2 +- src/utils.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 3fad1c9..6dee119 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ "build": "rimraf lib && babel ./src -d lib", "test": "mocha --compilers js:babel-core/register --recursive", "test:watch": "npm test -- --watch", - "lint": "eslint . ./" + "lint": "eslint . ./; exit 0" }, "repository": { "type": "git", diff --git a/src/utils.js b/src/utils.js index b1bd345..3f437f5 100644 --- a/src/utils.js +++ b/src/utils.js @@ -10,7 +10,7 @@ export const apiRequest = (url, accessToken, options = {}) => { headers: { Authorization: `Bearer ${accessToken}`, 'Content-Type': 'application/vnd.api+json', - Accept: 'application/vnd.api+json' + 'Accept': 'application/vnd.api+json' }, ...options }; From 73ad0adc88ab613aa2cf0b4a23cf350aa80b668f Mon Sep 17 00:00:00 2001 From: Lars Krieger Date: Thu, 9 Jun 2016 10:47:31 +0200 Subject: [PATCH 025/343] Fix Lint test and removed forced exit 0 on lint --- package.json | 2 +- src/utils.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 6dee119..3fad1c9 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ "build": "rimraf lib && babel ./src -d lib", "test": "mocha --compilers js:babel-core/register --recursive", "test:watch": "npm test -- --watch", - "lint": "eslint . ./; exit 0" + "lint": "eslint . ./" }, "repository": { "type": "git", diff --git a/src/utils.js b/src/utils.js index 3f437f5..b1bd345 100644 --- a/src/utils.js +++ b/src/utils.js @@ -10,7 +10,7 @@ export const apiRequest = (url, accessToken, options = {}) => { headers: { Authorization: `Bearer ${accessToken}`, 'Content-Type': 'application/vnd.api+json', - 'Accept': 'application/vnd.api+json' + Accept: 'application/vnd.api+json' }, ...options }; From 16f914f950e34fd4f64fa43a8860fa8cbb256af3 Mon Sep 17 00:00:00 2001 From: Lars Krieger Date: Fri, 10 Jun 2016 16:50:34 +0200 Subject: [PATCH 026/343] Added Travis badge to the Readme --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 0eefd6b..67e39ec 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,6 @@ Redux ❤️ JSON API ---------------- +[![Build Status](https://travis-ci.org/dixieio/redux-json-api.svg?branch=master)](https://travis-ci.org/dixieio/redux-json-api) Redux actions, action creators and reducers to make life with [JSON API](http://jsonapi.org)s a breeze. From e0ecee13491ce6b4675b1dfab563d8ce4772032d Mon Sep 17 00:00:00 2001 From: Lars Krieger Date: Thu, 30 Jun 2016 11:21:18 +0200 Subject: [PATCH 027/343] Updated Red Heart with Purple Heart --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 241bd6b..8d13e10 100644 --- a/README.md +++ b/README.md @@ -41,4 +41,4 @@ To build the code for local testing purposed run `npm run build`, this will dist You have done really cool work, __KUDOS__! 🎉, now you want to contrubute the code and you create a _PR_, we will then review the pull request. ## Contributors -Made with ❤️ from the [Dixie](http://www.dixie.io) team, and our lovely [contributers](https://github.com/dixieio/redux-json-api/graphs/contributors)! +Made with 💜 from the [Dixie](http://www.dixie.io) team, and our lovely [contributers](https://github.com/dixieio/redux-json-api/graphs/contributors)! From 89fc6a1def39dea9401d530fee64c50641399f5a Mon Sep 17 00:00:00 2001 From: Ronni Egeriis Persson Date: Fri, 8 Jul 2016 11:28:35 +0200 Subject: [PATCH 028/343] Add breaking test --- test/jsonapi.js | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/test/jsonapi.js b/test/jsonapi.js index 2f874c4..1416549 100644 --- a/test/jsonapi.js +++ b/test/jsonapi.js @@ -36,7 +36,7 @@ const state = { name: 'John Doe' }, relationships: { - tasks: { + companies: { data: null } } @@ -234,6 +234,30 @@ const responseDataWithSingleEntity = { }] }; +const responseDataWithOneToManyRelationship = { + data: { + type: 'companies', + id: '1', + attributes: { + name: 'Dixie.io', + slug: 'dixie.io', + createdAt: '2016-04-08T08:42:45+0000', + updatedAt: '2016-04-08T08:42:45+0000' + }, + relationships: { + user: { + data: { + type: 'users', + id: '1' + } + } + }, + links: { + self: 'http:\/\/gronk.app\/api\/v1\/companies\/1' + } + } +}; + describe('Creation of new entities', () => { it('should automatically organize new entity in new key on state', () => { const updatedState = reducer(state, apiCreated(taskWithoutRelationship)); @@ -277,6 +301,13 @@ describe('Reading entities', () => { expect(updatedState.users).toBeAn('object'); expect(updatedState.companies).toBeAn('object'); }); + + it('should handle response with a one to many relationship', () => { + const updatedState = reducer(state, apiRead(responseDataWithOneToManyRelationship)); + expect(updatedState.users).toBeAn('object'); + expect(updatedState.companies).toBeAn('object'); + expect(updatedState.users.data[0].relationships.companies.data).toBeAn('array'); + }); }); describe('Updating entities', () => { From d43734a82d4d404de4b61bda88183c31462e9992 Mon Sep 17 00:00:00 2001 From: Ronni Egeriis Persson Date: Fri, 8 Jul 2016 13:43:44 +0200 Subject: [PATCH 029/343] Fix for one-to-many relationships not being registered correctly --- src/state-mutation.js | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/state-mutation.js b/src/state-mutation.js index f052fc3..7c9e493 100644 --- a/src/state-mutation.js +++ b/src/state-mutation.js @@ -15,17 +15,26 @@ const updateReverseRelationship = ( item => item.get('id') === relationship.getIn(['data', 'id']) ), foreignEntity => { - const relCase = [1, 2] - .map(i => pluralize(entity.get('type'), i)) - .find(r => foreignEntity.hasIn(['relationships', r])); + const [singular, plural] = [1, 2].map(i => pluralize(entity.get('type'), i)); + const relCase = [singular, plural].find(r => foreignEntity.hasIn(['relationships', r])); if (!relCase) { return foreignEntity; } - return foreignEntity.setIn( + return foreignEntity.updateIn( ['relationships', relCase, 'data'], - newRelation + relation => { + if (relCase === singular) { + return newRelation; + } + + if (!relation) { + return [newRelation]; + } + + return relation.push(newRelation); + } ); } ); From ad3572d2f1a0654d57d9ca3a8dc31f8909947fff Mon Sep 17 00:00:00 2001 From: Ronni Egeriis Persson Date: Fri, 8 Jul 2016 13:47:30 +0200 Subject: [PATCH 030/343] Bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 3fad1c9..2b79649 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "redux-json-api", - "version": "1.4.1", + "version": "1.4.2", "description": "A bunch of Redux actions, action creators and reducers to integrate with a JSON API", "main": "lib/jsonapi.js", "scripts": { From ecfaebaa9a788d5dfaac586b791f3b22dc44e69f Mon Sep 17 00:00:00 2001 From: Ronni Egeriis Persson Date: Fri, 8 Jul 2016 14:17:59 +0200 Subject: [PATCH 031/343] Update introduction, avoid incrementing numbers in ordered lists --- README.md | 37 ++++++++++++++++++++----------------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 8d13e10..0c78591 100644 --- a/README.md +++ b/README.md @@ -1,30 +1,33 @@ +Make Redux 💜 JSON API +---------------------- + # Introduction -Welcome to the __Redux JSON API__ we ❤️ JSON and we love simple api's. With this in mind was this libiary born. We strive to keep this libiary as small but as powerfull as possible so it would be easy adaptable into any `JSON API` stack enviroment. +This library is intended for use in web applications build on Redux, which consumes data from a [JSON API](http://jsonapi.org/). -We would love all of you users, to open disscusions/issues with us, that can make this tool pleasent for all to use, and ther for give a better libiary in the end. And if you build somthing with it, please let us know so we can see the cool stuff you are doing! +Use _redux-json-api_ to have one simple way of storing resource objects in Redux state along with the CRUD API, which provides easy ways to create, read, update and delete resources. -If there is anything that you feel is not documented, or could be refered better to such as things from `redux` let us know aswell. +Please raise any questions as an [Issue](issues) or submit your contributions as a [Pull Request](pulls). Remember to review our [contributions guidelines](CONTRIBUTING.md). -## Table of content +# Table of contents 1. [Introduction](#introduction) -2. [Getting Started](#getting-started) -3. [How To Use](#how-to-use) -4. [Api Overview](#api-overview) -5. [Good reads](#good-reads) -6. [Contribute](#contribute) -7. [Contributors](#contributors) +1. [Getting Started](#getting-started) +1. [How To Use](#how-to-use) +1. [API Overview](#api-overview) +1. [Good reads](#good-reads) +1. [Contribute](#contribute) +1. [Contributors](#contributors) ## [Getting Started](docs/GettingStarted.md) ## [How to use](docs/HowToUse.md) ## API overview -1. [Read __createEntity()__](docs/apis/createEntity.md) - Creating new entities -2. [Read __readEndpoint()__](docs/apis/readEndpoint.md) - Retrive data from your database -3. [Read __updateEntity()__](docs/apis/updateEntity.md) - Update a given entity's values -4. [Read __deleteEntity()__](docs/apis/deleteEntity.md) - Remove entity from your database +- [Read __createEntity()__](docs/apis/createEntity.md) - Creating new entities +- [Read __readEndpoint()__](docs/apis/readEndpoint.md) - Retrive data from your database +- [Read __updateEntity()__](docs/apis/updateEntity.md) - Update a given entity's values +- [Read __deleteEntity()__](docs/apis/deleteEntity.md) - Remove entity from your database ## Good reads -1. [__Redux__](http://www.github.com) - Read about redux and core principles. -2. [__JSON API__](http://www.jsonapi.org/) - Read about the specifications for JSON API. +- [__Redux__](http://www.github.com) - Read about redux and core principles. +- [__JSON API__](http://www.jsonapi.org/) - Read about the specifications for JSON API. ## Contribute The reason for this repository is to keep on a good and healty & simple api for _JSON API_, for Redux applications weahter you use it in _react_ or any other framework of choise. Feel like getting envolved into to this, then get cloning and follow our simple guide lines, if you just want to give feedback or report bug click that [issues](https://github.com/dixieio/redux-json-api/issues) button and lets talk about it. @@ -41,4 +44,4 @@ To build the code for local testing purposed run `npm run build`, this will dist You have done really cool work, __KUDOS__! 🎉, now you want to contrubute the code and you create a _PR_, we will then review the pull request. ## Contributors -Made with 💜 from the [Dixie](http://www.dixie.io) team, and our lovely [contributers](https://github.com/dixieio/redux-json-api/graphs/contributors)! +Made with 💜 from the [Dixie](http://www.dixie.io) team, and our lovely [contributers](graphs/contributors)! From 999c5f2b6fb1a561be51fb823c1ca6114590e33f Mon Sep 17 00:00:00 2001 From: Ronni Egeriis Persson Date: Fri, 8 Jul 2016 14:19:01 +0200 Subject: [PATCH 032/343] Remove unneeded headline --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 0c78591..74ca81a 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,6 @@ Make Redux 💜 JSON API ---------------------- -# Introduction This library is intended for use in web applications build on Redux, which consumes data from a [JSON API](http://jsonapi.org/). Use _redux-json-api_ to have one simple way of storing resource objects in Redux state along with the CRUD API, which provides easy ways to create, read, update and delete resources. From 9b458d42e518ab7c9bb3ab6b9152542d992f3b3f Mon Sep 17 00:00:00 2001 From: Ronni Egeriis Persson Date: Fri, 8 Jul 2016 14:19:08 +0200 Subject: [PATCH 033/343] Add build status --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 74ca81a..7c5ca1c 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,6 @@ Make Redux 💜 JSON API ---------------------- +[![Build Status](https://travis-ci.org/dixieio/redux-json-api.svg?branch=master)](https://travis-ci.org/dixieio/redux-json-api) This library is intended for use in web applications build on Redux, which consumes data from a [JSON API](http://jsonapi.org/). From 5a1b5154f1e2ccead27c43a93ed9500a6f52f3b0 Mon Sep 17 00:00:00 2001 From: Ronni Egeriis Persson Date: Fri, 8 Jul 2016 14:50:56 +0200 Subject: [PATCH 034/343] Remove link to introduction --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 7c5ca1c..88a2dc6 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,6 @@ Use _redux-json-api_ to have one simple way of storing resource objects in Redux Please raise any questions as an [Issue](issues) or submit your contributions as a [Pull Request](pulls). Remember to review our [contributions guidelines](CONTRIBUTING.md). # Table of contents -1. [Introduction](#introduction) 1. [Getting Started](#getting-started) 1. [How To Use](#how-to-use) 1. [API Overview](#api-overview) From 32139ccb2a4227cc9ec33e9bdc339f3a43dd4ba5 Mon Sep 17 00:00:00 2001 From: Ronni Egeriis Persson Date: Fri, 8 Jul 2016 14:51:07 +0200 Subject: [PATCH 035/343] Update getting started document - Removed words and sentences that wasn't necessary - Made examples less opionionated - Added step regarding required middleware --- docs/GettingStarted.md | 68 ++++++++++++++++++++++-------------------- 1 file changed, 35 insertions(+), 33 deletions(-) diff --git a/docs/GettingStarted.md b/docs/GettingStarted.md index 75ca819..510da14 100644 --- a/docs/GettingStarted.md +++ b/docs/GettingStarted.md @@ -1,18 +1,24 @@ -# Getting Started -Getting into using Redux JSON API is fairly simple and requires __3 Steps__ witch we will cover here. +Set-Up & Configure +------------------ -If you have already setup `redux-json-api` please go to the "How to use Redux JSON API", since this will strictly get the libiary set up. +Getting _redux-json-api_ set up requires __4 steps__ which we will cover here. -## 1. Instalation -To install `redux-json-api` go to your projects root (where your package.json is located) and run: +1. Install through npm +1. Add _redux-json-api_ reducer to _api_ namespace +1. Add required middleware to store +1. Configure API endpoints and access token + +## Install through npm `$ npm install redux-json-api --save` -## 2. Combine reducers -To get data from `redux-json-api` you must reduce our reducer on to your own reducer, by using the `combineReducers` from `redux`. +## Add reducer to _api_ namespace + +The current version of _redux-json-api_ assumes that it's reducer will be attached to the api namespace of your Redux state. + +You can achieve this by using [combineReducers](http://redux.js.org/docs/api/combineReducers.html) from Redux: -```javascript -// rootReducer.js +```js import { combineReducers } from 'redux'; import { reducer as api } from 'redux-json-api'; @@ -21,40 +27,36 @@ export default combineReducers({ }); ``` -For sanity we have removed all other reducers from the `combineReducers` combined reducers will take an object of reducers, you are able to apply more reducers, such as your own. +## Add required middleware to store -__NB:__ For this to work, its important that your store is setup with the `redux-thunk` middleware, not sure how to set up your store see this guide: "Setting up redux store with redux-thunk middleware" - +Since most of _redux-json-api_'s are async it is required to configure your store with the [redux-thunk](https://github.com/gaearon/redux-thunk) middleware. Please see their docs for installation instructions. -Thanks to [__@justaskz__](https://github.com/justaskz) for pointing this out to us. +## Configure API endpoints and access token -## 3. Initialize redux-json-api -The last step you need to define is using the `setEndpointPath()` & `setEndpointHost()` this will set the `api.endpoint` that `redux-json-api` will use for when dispatchig various call's through the api. +As _redux-json-api_ will automatically make request to your API, it requires to know about API host and root path. -Its important to note, to do this as early as possible perfable in container that initializes your application so you are ready to call you endpoints when initial bootstrap is done. +There are one method for each of these, and they should be dispatched before dispatching any CRUD actions. -```javascript -// CoreLayout.js -import { setEndpointPath, setEndpointHost } from 'redux-json-api'; +### `setEndpointHost( hostWithProtocol: string ): object` -class CoreLayout extends Component { +Dispatch the returned action to set endpoint hostname. It requires one argument, which is a full hostname including protocol. - componentWillMount() { - const { dispatch } = this.props; - dispatch(setEndpointHost('my.app/')); - dispatch(setEndpointPath('api/v1/')); - } +```js +dispatch(setEndpointHost('https://api.my-server')); +``` - render() { - return ( -
- ); - } +### `setEndpointPath( rootPath: string ): object` -} +Dispatch the returned action to configure endpoint root path. It requires one argument. -export default connect()(CoreLayout); +```js +dispatch(setEndpointPath('/v1')); ``` -In this example are we using the CoreLayout witch is the first component to be rendered, we will before the component mount dispatch our `setEndpointHost` and `setEndpointPath` with strings that defines our api's path. +Host and path will be concatenated without any validation. Be aware of missing slashes. This will cause an error, due to a missing forward slash: -__NB:__ A good practise would be to store these as a process enviromental variables. +```js +dispatch(setEndpointHost('https://api.my-server')); +dispatch(setEndpointPath('v1')); +// => https://api.my-serverv1 +``` From 8af6d1e645d97ef43778de1c4497abdbca0f7f44 Mon Sep 17 00:00:00 2001 From: Ronni Egeriis Persson Date: Fri, 8 Jul 2016 14:55:04 +0200 Subject: [PATCH 036/343] Made method signatures smaller --- docs/GettingStarted.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/GettingStarted.md b/docs/GettingStarted.md index 510da14..3b0052e 100644 --- a/docs/GettingStarted.md +++ b/docs/GettingStarted.md @@ -37,7 +37,7 @@ As _redux-json-api_ will automatically make request to your API, it requires to There are one method for each of these, and they should be dispatched before dispatching any CRUD actions. -### `setEndpointHost( hostWithProtocol: string ): object` +#### `setEndpointHost( hostWithProtocol: string ): object` Dispatch the returned action to set endpoint hostname. It requires one argument, which is a full hostname including protocol. @@ -45,7 +45,7 @@ Dispatch the returned action to set endpoint hostname. It requires one argument, dispatch(setEndpointHost('https://api.my-server')); ``` -### `setEndpointPath( rootPath: string ): object` +#### `setEndpointPath( rootPath: string ): object` Dispatch the returned action to configure endpoint root path. It requires one argument. From adf7e8880482f97eecf148f01d7abec822cd0e2c Mon Sep 17 00:00:00 2001 From: Ronni Egeriis Persson Date: Fri, 8 Jul 2016 14:56:05 +0200 Subject: [PATCH 037/343] Rename getting started and link directly from toc --- README.md | 3 +-- docs/{GettingStarted.md => set-up-configure.md} | 0 2 files changed, 1 insertion(+), 2 deletions(-) rename docs/{GettingStarted.md => set-up-configure.md} (100%) diff --git a/README.md b/README.md index 88a2dc6..558af6f 100644 --- a/README.md +++ b/README.md @@ -9,14 +9,13 @@ Use _redux-json-api_ to have one simple way of storing resource objects in Redux Please raise any questions as an [Issue](issues) or submit your contributions as a [Pull Request](pulls). Remember to review our [contributions guidelines](CONTRIBUTING.md). # Table of contents -1. [Getting Started](#getting-started) +1. [Set-Up & Configure](docs/set-up-configure.md) 1. [How To Use](#how-to-use) 1. [API Overview](#api-overview) 1. [Good reads](#good-reads) 1. [Contribute](#contribute) 1. [Contributors](#contributors) -## [Getting Started](docs/GettingStarted.md) ## [How to use](docs/HowToUse.md) ## API overview - [Read __createEntity()__](docs/apis/createEntity.md) - Creating new entities diff --git a/docs/GettingStarted.md b/docs/set-up-configure.md similarity index 100% rename from docs/GettingStarted.md rename to docs/set-up-configure.md From fed68d5dabb020c607df9d62cd3db90bf0600595 Mon Sep 17 00:00:00 2001 From: Ronni Egeriis Persson Date: Fri, 8 Jul 2016 15:00:31 +0200 Subject: [PATCH 038/343] Add missing note about access token set-up --- docs/set-up-configure.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/set-up-configure.md b/docs/set-up-configure.md index 3b0052e..371f5c9 100644 --- a/docs/set-up-configure.md +++ b/docs/set-up-configure.md @@ -33,7 +33,7 @@ Since most of _redux-json-api_'s are async it is required to configure your stor ## Configure API endpoints and access token -As _redux-json-api_ will automatically make request to your API, it requires to know about API host and root path. +As _redux-json-api_ will automatically make request to your API, it requires to know about API host, root path and access token. There are one method for each of these, and they should be dispatched before dispatching any CRUD actions. @@ -60,3 +60,7 @@ dispatch(setEndpointHost('https://api.my-server')); dispatch(setEndpointPath('v1')); // => https://api.my-serverv1 ``` + +#### `setAccessToken( accessToken: string ): object` + +Dispatch this action to configure an access token to include in all requests. At the moment, _redux-json-api_ only supports authorizing requests through the `Authorization: Bearer ` header. From 679dee0d3f022a607410960718759bdff000ece9 Mon Sep 17 00:00:00 2001 From: Ronni Egeriis Persson Date: Fri, 8 Jul 2016 15:02:49 +0200 Subject: [PATCH 039/343] Remove redundant How to use section --- README.md | 2 -- docs/HowToUse.md | 13 ------------- 2 files changed, 15 deletions(-) delete mode 100644 docs/HowToUse.md diff --git a/README.md b/README.md index 558af6f..f173b09 100644 --- a/README.md +++ b/README.md @@ -10,13 +10,11 @@ Please raise any questions as an [Issue](issues) or submit your contributions as # Table of contents 1. [Set-Up & Configure](docs/set-up-configure.md) -1. [How To Use](#how-to-use) 1. [API Overview](#api-overview) 1. [Good reads](#good-reads) 1. [Contribute](#contribute) 1. [Contributors](#contributors) -## [How to use](docs/HowToUse.md) ## API overview - [Read __createEntity()__](docs/apis/createEntity.md) - Creating new entities - [Read __readEndpoint()__](docs/apis/readEndpoint.md) - Retrive data from your database diff --git a/docs/HowToUse.md b/docs/HowToUse.md deleted file mode 100644 index 128c2ec..0000000 --- a/docs/HowToUse.md +++ /dev/null @@ -1,13 +0,0 @@ -# How to use -In this section we will go through the simple _CRUD API_. There are 4 simple calls to get `redux-json-api` rocking. - -__*Lets get cracking with this api*__ 🎈 - -## createEntity(value: { object }) -[Read the createEntity api](apis/createEntity.md) -## readEndpoint(value: 'string') -[Read the readEndpoint api](apis/readEndpoint.md) -## updateEntity(value: { object }) -[Read the updateEntity api](apis/updateEntity.md) -## deleteEntity(value: { object }) -[Read the deleteEntity api](apis/deleteEntity.md) From 97ef9f8fcc58a7735a0e8f18fd4883a67e329e2d Mon Sep 17 00:00:00 2001 From: Ronni Egeriis Persson Date: Fri, 8 Jul 2016 15:16:05 +0200 Subject: [PATCH 040/343] Add new API overview --- README.md | 8 +------ docs/api.md | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+), 7 deletions(-) create mode 100644 docs/api.md diff --git a/README.md b/README.md index f173b09..5f2974b 100644 --- a/README.md +++ b/README.md @@ -10,17 +10,11 @@ Please raise any questions as an [Issue](issues) or submit your contributions as # Table of contents 1. [Set-Up & Configure](docs/set-up-configure.md) -1. [API Overview](#api-overview) +1. [API](docs/api.md) 1. [Good reads](#good-reads) 1. [Contribute](#contribute) 1. [Contributors](#contributors) -## API overview -- [Read __createEntity()__](docs/apis/createEntity.md) - Creating new entities -- [Read __readEndpoint()__](docs/apis/readEndpoint.md) - Retrive data from your database -- [Read __updateEntity()__](docs/apis/updateEntity.md) - Update a given entity's values -- [Read __deleteEntity()__](docs/apis/deleteEntity.md) - Remove entity from your database - ## Good reads - [__Redux__](http://www.github.com) - Read about redux and core principles. - [__JSON API__](http://www.jsonapi.org/) - Read about the specifications for JSON API. diff --git a/docs/api.md b/docs/api.md new file mode 100644 index 0000000..879652c --- /dev/null +++ b/docs/api.md @@ -0,0 +1,62 @@ +API +--- + +_redux-json-api_ provides a simple API for all four CRUD actions. + +- Create resource objects using [createEntity](#createEntity) +- Read endpoints using [readEndpoint](#readEndpoint) +- Update using [updateEntity](#updateEntity) +- Delete resources using [deleteEntity](#deleteEntity) + +## Resource objects + +Whenever there's referred to a resource object or entity, it must conform to JSON API specifications. + +## Resource endpoints + +_redux-json-api_ resolves resource objects to endpoints based on their specified type. The following resource will update and delete to _/tasks/1_: + +```json +{ + "id": 1, + "type": "tasks", + "attributes": { + "title": "Lorem ipsum" + } +} +``` + +While dispatching a create action for the following resource will make a request to _/tasks_: + +```json +{ + "type": "tasks", + "attributes": { + "title": "Lorem ipsum" + } +} +``` + +## `createEntity( resource: object ): function` + +Use this action creator to trigger a POST request to your API with the given resource. + +[Examples and details here.](docs/apis/createEntity.md) + +## `readEndpoint( endpoint: string ): function` + +This action creator will trigger a GET request to the specified endpoint. + +[Read more.](docs/apis/readEndpoint.md) + +## `updateEntity( resource: object ): function` + +Update entities using this action creator. It will make a PATCH request to your API. + +[Details and examples.](docs/apis/updateEntity.md) + +## `deleteEntity( resource: object ): function` + +Use this action creator to issue a DELETE request to your API. + +[More details on _deleteEntity_](docs/apis/deleteEntity.md) From 47bdec5cd2609d7563e95e0c7580d8b2ad9ad022 Mon Sep 17 00:00:00 2001 From: Ronni Egeriis Persson Date: Fri, 8 Jul 2016 15:17:10 +0200 Subject: [PATCH 041/343] Add correct anchors to API index --- docs/api.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/api.md b/docs/api.md index 879652c..295e7a4 100644 --- a/docs/api.md +++ b/docs/api.md @@ -3,10 +3,10 @@ API _redux-json-api_ provides a simple API for all four CRUD actions. -- Create resource objects using [createEntity](#createEntity) -- Read endpoints using [readEndpoint](#readEndpoint) -- Update using [updateEntity](#updateEntity) -- Delete resources using [deleteEntity](#deleteEntity) +- Create resource objects using [createEntity](#createentity-resource-object--function) +- Read endpoints using [readEndpoint](#readendpoint-endpoint-string--function) +- Update using [updateEntity](#updateentity-resource-object--function) +- Delete resources using [deleteEntity](#deleteentity-resource-object--function) ## Resource objects From 2edb2f205967dd2dbcf00574a2f8d2c7e87ead63 Mon Sep 17 00:00:00 2001 From: Ronni Egeriis Persson Date: Fri, 8 Jul 2016 15:17:30 +0200 Subject: [PATCH 042/343] Make method signature font size smaller --- docs/api.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/api.md b/docs/api.md index 295e7a4..2937413 100644 --- a/docs/api.md +++ b/docs/api.md @@ -37,25 +37,25 @@ While dispatching a create action for the following resource will make a request } ``` -## `createEntity( resource: object ): function` +#### `createEntity( resource: object ): function` Use this action creator to trigger a POST request to your API with the given resource. [Examples and details here.](docs/apis/createEntity.md) -## `readEndpoint( endpoint: string ): function` +#### `readEndpoint( endpoint: string ): function` This action creator will trigger a GET request to the specified endpoint. [Read more.](docs/apis/readEndpoint.md) -## `updateEntity( resource: object ): function` +#### `updateEntity( resource: object ): function` Update entities using this action creator. It will make a PATCH request to your API. [Details and examples.](docs/apis/updateEntity.md) -## `deleteEntity( resource: object ): function` +#### `deleteEntity( resource: object ): function` Use this action creator to issue a DELETE request to your API. From b4d00192dd971a28871619d8656f9968aebc08cc Mon Sep 17 00:00:00 2001 From: Ronni Egeriis Persson Date: Fri, 8 Jul 2016 15:18:23 +0200 Subject: [PATCH 043/343] Add headline before methods --- docs/api.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/api.md b/docs/api.md index 2937413..57f39fd 100644 --- a/docs/api.md +++ b/docs/api.md @@ -37,6 +37,8 @@ While dispatching a create action for the following resource will make a request } ``` +## API Methods + #### `createEntity( resource: object ): function` Use this action creator to trigger a POST request to your API with the given resource. From e553a3101b549528a7505be65bf6db9977760a84 Mon Sep 17 00:00:00 2001 From: Ronni Egeriis Persson Date: Fri, 8 Jul 2016 15:19:40 +0200 Subject: [PATCH 044/343] Correct links to API pages --- docs/api.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/api.md b/docs/api.md index 57f39fd..4fdbabb 100644 --- a/docs/api.md +++ b/docs/api.md @@ -43,22 +43,22 @@ While dispatching a create action for the following resource will make a request Use this action creator to trigger a POST request to your API with the given resource. -[Examples and details here.](docs/apis/createEntity.md) +[Examples and details here.](apis/createEntity.md) #### `readEndpoint( endpoint: string ): function` This action creator will trigger a GET request to the specified endpoint. -[Read more.](docs/apis/readEndpoint.md) +[Read more.](apis/readEndpoint.md) #### `updateEntity( resource: object ): function` Update entities using this action creator. It will make a PATCH request to your API. -[Details and examples.](docs/apis/updateEntity.md) +[Details and examples.](apis/updateEntity.md) #### `deleteEntity( resource: object ): function` Use this action creator to issue a DELETE request to your API. -[More details on _deleteEntity_](docs/apis/deleteEntity.md) +[More details on _deleteEntity_](apis/deleteEntity.md) From 5cf0ea20b823a86dff864a63fd1182837ec2fbb8 Mon Sep 17 00:00:00 2001 From: Ronni Egeriis Persson Date: Fri, 8 Jul 2016 15:24:26 +0200 Subject: [PATCH 045/343] Kickstart CONTRIBUTING.md --- CONTRIBUTING.md | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..af1f900 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,7 @@ +We 💜 contributions +------------------- + +While we love contributions, we also need to ensure that our library is of great quality. Thus we require you to follow some simple guidelines when you're submitting your contributions. + +1. Write breaking test(s) before fixing bugs or adding new functionality +1. From 2618c12c0ce25c252f351114bf15432ef262ab65 Mon Sep 17 00:00:00 2001 From: Ronni Egeriis Persson Date: Fri, 8 Jul 2016 15:32:28 +0200 Subject: [PATCH 046/343] Add more juice to contributing guidelines --- CONTRIBUTING.md | 52 +++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 50 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index af1f900..06f37db 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -3,5 +3,53 @@ We 💜 contributions While we love contributions, we also need to ensure that our library is of great quality. Thus we require you to follow some simple guidelines when you're submitting your contributions. -1. Write breaking test(s) before fixing bugs or adding new functionality -1. +## Reporting Issues and Asking Questions + +Before opening an issue, please search the [issue tracker](https://github.com/dixieio/redux-json-api/issues) to make sure your issue hasn’t already been reported. + +## Development + +Visit the [issue tracker](https://github.com/dixieio/redux-json-api/issues) to find a list of open issues that need attention. + +Fork, then clone the repo: + +``` +git clone https://github.com/your-username/redux-json-api.git +``` + +### Testing + +To run tests: + +``` +npm run test +``` + +To continuously watch and run tests, run the following: + +``` +npm run test:watch +``` + +### Building + +To build run: + +``` +npm run build +``` + +### Submitting a Pull Request + +For non-trivial changes, please open an issue with a proposal for a new feature or refactoring before starting on the work. We don’t want you to waste your efforts on a pull request that we won’t want to accept. + +On the other hand, sometimes the best way to start a conversation *is* to send a pull request. Use your best judgement! + +1. Open a new issue in the [Issue tracker](https://github.com/dixieio/redux-json-api/issues) +1. Fork the repo +1. Create a new feature branch based off the `master` branch +1. Create breaking test(s) before implementing any fixes or functionality +1. Make your changes +1. Submit a pull request, referencing any issue that it resolves + +Thank you, we 💜 your contributions! From f46e84d5875b5aeec2084defd1527a7a9a294753 Mon Sep 17 00:00:00 2001 From: Matthew Bolanos Date: Sun, 17 Jul 2016 14:29:35 -0500 Subject: [PATCH 047/343] fix relation.push bug for multiple entities --- src/state-mutation.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/state-mutation.js b/src/state-mutation.js index 7c9e493..4542576 100644 --- a/src/state-mutation.js +++ b/src/state-mutation.js @@ -30,7 +30,7 @@ const updateReverseRelationship = ( } if (!relation) { - return [newRelation]; + return new Imm.List([newRelation]); } return relation.push(newRelation); From a063886cdd5c7ca36deb9bf4c022819c1b3fe9b6 Mon Sep 17 00:00:00 2001 From: Matthew Bolanos Date: Sun, 17 Jul 2016 14:31:20 -0500 Subject: [PATCH 048/343] add breaking test --- test/jsonapi.js | 58 ++++++++++++++++++++++++++++++++++--------------- 1 file changed, 41 insertions(+), 17 deletions(-) diff --git a/test/jsonapi.js b/test/jsonapi.js index 1416549..922dd59 100644 --- a/test/jsonapi.js +++ b/test/jsonapi.js @@ -235,29 +235,53 @@ const responseDataWithSingleEntity = { }; const responseDataWithOneToManyRelationship = { - data: { - type: 'companies', - id: '1', - attributes: { - name: 'Dixie.io', - slug: 'dixie.io', - createdAt: '2016-04-08T08:42:45+0000', - updatedAt: '2016-04-08T08:42:45+0000' - }, - relationships: { - user: { - data: { - type: 'users', - id: '1' + data: [ + { + type: 'companies', + id: '1', + attributes: { + name: 'Dixie.io', + slug: 'dixie.io', + createdAt: '2016-04-08T08:42:45+0000', + updatedAt: '2016-04-08T08:42:45+0000' + }, + relationships: { + user: { + data: { + type: 'users', + id: '1' + } } + }, + links: { + self: 'http:\/\/gronk.app\/api\/v1\/companies\/1' } }, - links: { - self: 'http:\/\/gronk.app\/api\/v1\/companies\/1' + { + type: 'companies', + id: '2', + attributes: { + name: 'Dixie.io', + slug: 'dixie.io', + createdAt: '2016-04-08T08:42:45+0000', + updatedAt: '2016-04-08T08:42:45+0000' + }, + relationships: { + user: { + data: { + type: 'users', + id: '1' + } + } + }, + links: { + self: 'http:\/\/gronk.app\/api\/v1\/companies\/2' + } } - } + ] }; + describe('Creation of new entities', () => { it('should automatically organize new entity in new key on state', () => { const updatedState = reducer(state, apiCreated(taskWithoutRelationship)); From 567817e0e8b5c59177b12d2c0b7ffeae10d5c043 Mon Sep 17 00:00:00 2001 From: Alex Antonov Date: Wed, 27 Jul 2016 12:34:37 +0400 Subject: [PATCH 049/343] Add .nvmrc to .gitignore I'm the person who's using node version manager, https://github.com/creationix/nvm . I set up `.nvmrc` file for every js project, but I don't think I have to commit it here... --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index e71a6cc..8dc6958 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,6 @@ node_modules .node_repl_history lib + +# node version manager settings +.nvmrc From 4e2724bee030a1a5979c5f26f4498f3fbf320698 Mon Sep 17 00:00:00 2001 From: Ronni Egeriis Persson Date: Mon, 1 Aug 2016 15:45:39 +0200 Subject: [PATCH 050/343] v1.4.3 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 2b79649..65d2209 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "redux-json-api", - "version": "1.4.2", + "version": "1.4.3", "description": "A bunch of Redux actions, action creators and reducers to integrate with a JSON API", "main": "lib/jsonapi.js", "scripts": { From 36c6a3ba1a2769c90e81a6d521f2266b1c61b6dc Mon Sep 17 00:00:00 2001 From: Ronni Egeriis Persson Date: Thu, 11 Aug 2016 15:41:03 +0200 Subject: [PATCH 051/343] Add broken test for bug-case of wrongly updated reverse relationship --- test/jsonapi.js | 14 +++++ .../withNonMatchingReverseRelationships.json | 57 +++++++++++++++++++ 2 files changed, 71 insertions(+) create mode 100644 test/payloads/withNonMatchingReverseRelationships.json diff --git a/test/jsonapi.js b/test/jsonapi.js index 922dd59..e045f9b 100644 --- a/test/jsonapi.js +++ b/test/jsonapi.js @@ -281,6 +281,7 @@ const responseDataWithOneToManyRelationship = { ] }; +const payloadWithNonMatchingReverseRelationships = require('./payloads/withNonMatchingReverseRelationships.json'); describe('Creation of new entities', () => { it('should automatically organize new entity in new key on state', () => { @@ -332,6 +333,19 @@ describe('Reading entities', () => { expect(updatedState.companies).toBeAn('object'); expect(updatedState.users.data[0].relationships.companies.data).toBeAn('array'); }); + + it('should ignore reverse relationship with no matching entity', () => { + const updatedState = reducer(state, apiRead(payloadWithNonMatchingReverseRelationships)); + + payloadWithNonMatchingReverseRelationships.included + .filter(entity => entity.type === 'reports') + .forEach( + payloadReport => { + const stateReport = updatedState.reports.data.find(r => payloadReport.id === r.id); + expect(stateReport.relationships.file.data.id).toEqual(payloadReport.relationships.file.data.id); + } + ); + }); }); describe('Updating entities', () => { diff --git a/test/payloads/withNonMatchingReverseRelationships.json b/test/payloads/withNonMatchingReverseRelationships.json new file mode 100644 index 0000000..e2352ab --- /dev/null +++ b/test/payloads/withNonMatchingReverseRelationships.json @@ -0,0 +1,57 @@ +{ + "data": [], + "included": [ + { + "type": "reports", + "id": "121", + "attributes": { }, + "relationships": { + "file": { + "data": { + "type": "files", + "id": "9979" + } + } + } + }, + { + "type": "files", + "id": "210", + "attributes": { }, + "relationships": { + "fileable": { + "data": { + "type": "reports", + "id": "13" + } + } + } + }, + { + "type": "reports", + "id": "122", + "attributes": { }, + "relationships": { + "file": { + "data": { + "type": "files", + "id": "9980" + } + } + } + }, + { + "type": "files", + "id": "666", + "attributes": { }, + "relationships": { + "fileable": { + "data": { + "type": "reports", + "id": "16" + } + } + } + } + ] +} From 87e0e34fed3cb5032556284b7502012ed2fcd4f3 Mon Sep 17 00:00:00 2001 From: Ronni Egeriis Persson Date: Thu, 11 Aug 2016 15:51:44 +0200 Subject: [PATCH 052/343] Fix bug in earlier test cases --- test/jsonapi.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/jsonapi.js b/test/jsonapi.js index e045f9b..e03d049 100644 --- a/test/jsonapi.js +++ b/test/jsonapi.js @@ -31,7 +31,7 @@ const state = { data: [ { type: 'users', - id: 1, + id: '1', attributes: { name: 'John Doe' }, @@ -127,7 +127,7 @@ const transactionToDelete = { const updatedUser = { type: 'users', - id: 1, + id: '1', attributes: { name: 'Sir John Doe' }, From 189f9112ca7e4f0d5151d2d96d2d2fc23a2a9828 Mon Sep 17 00:00:00 2001 From: Ronni Egeriis Persson Date: Thu, 11 Aug 2016 15:52:11 +0200 Subject: [PATCH 053/343] Fix issue where an entity may have it's relationship wrongly updated --- src/state-mutation.js | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/state-mutation.js b/src/state-mutation.js index 4542576..d10f5ff 100644 --- a/src/state-mutation.js +++ b/src/state-mutation.js @@ -10,10 +10,16 @@ const updateReverseRelationship = ( } ) => { return (foreignEntities) => { + const idx = foreignEntities.findIndex( + item => item.get('id') === relationship.getIn(['data', 'id']) + ); + + if (idx === -1) { + return foreignEntities; + } + return foreignEntities.update( - foreignEntities.findIndex( - item => item.get('id') === relationship.getIn(['data', 'id']) - ), + idx, foreignEntity => { const [singular, plural] = [1, 2].map(i => pluralize(entity.get('type'), i)); const relCase = [singular, plural].find(r => foreignEntity.hasIn(['relationships', r])); From c284692b6e28a77a144306cdf56f04065ba6c16b Mon Sep 17 00:00:00 2001 From: Ronni Egeriis Persson Date: Thu, 11 Aug 2016 16:25:27 +0200 Subject: [PATCH 054/343] v1.4.4 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 65d2209..ad0d09d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "redux-json-api", - "version": "1.4.3", + "version": "1.4.4", "description": "A bunch of Redux actions, action creators and reducers to integrate with a JSON API", "main": "lib/jsonapi.js", "scripts": { From 7a9b400efe73629e18ad07f7e16a086a360c0cb9 Mon Sep 17 00:00:00 2001 From: Alex Antonov Date: Tue, 26 Jul 2016 09:37:46 +0300 Subject: [PATCH 055/343] Axios implementation --- README.md | 7 +--- package.json | 2 +- src/constants.js | 4 +- src/jsonapi.js | 96 +++++++++++++++++++++++------------------------- src/utils.js | 34 +++++++---------- test/jsonapi.js | 35 ++++++------------ 6 files changed, 73 insertions(+), 105 deletions(-) diff --git a/README.md b/README.md index 67e39ec..71b4bdc 100644 --- a/README.md +++ b/README.md @@ -19,8 +19,7 @@ Redux actions, action creators and reducers to make life with [JSON API](http:// 1. `npm install redux-json-api` 1. Enable JSON API reducer (examples assume that you've connected it to `state.api`) -1. Set up API hostname and path using the actions `setEndpointHost` and `setEndpointPath` -1. Configure access token with `setAccessToken` +1. Set [axios](https://github.com/mzabriskie/axios) config with `setAxiosConfig`. Pay attention to `baseURL` option. You're now good to go. So have a look the the available actions below. @@ -44,9 +43,7 @@ You're now good to go. So have a look the the available actions below. "isUpdating": 0, "isDeleting": 0, "endpoint": { - "host": null, - "path": null, - "accessToken": null + "axiosConfig": {} } } } diff --git a/package.json b/package.json index 65d2209..789279b 100644 --- a/package.json +++ b/package.json @@ -43,8 +43,8 @@ "webpack": "^1.12.12" }, "dependencies": { + "axios": "^0.13.1", "immutable": "^3.7.6", - "isomorphic-fetch": "^2.2.1", "keykey": "^2.1.1", "pluralize": "^1.2.1", "redux-actions": "^0.9.1" diff --git a/src/constants.js b/src/constants.js index aaaf1f0..3d193fb 100644 --- a/src/constants.js +++ b/src/constants.js @@ -1,9 +1,7 @@ import keykey from 'keykey'; export default keykey( - 'API_SET_ENDPOINT_HOST', - 'API_SET_ENDPOINT_PATH', - 'API_SET_ACCESS_TOKEN', + 'API_SET_AXIOS_CONFIG', 'API_WILL_CREATE', 'API_CREATED', 'API_CREATE_FAILED', diff --git a/src/jsonapi.js b/src/jsonapi.js index 69ee384..4de7a31 100644 --- a/src/jsonapi.js +++ b/src/jsonapi.js @@ -1,5 +1,4 @@ import { createAction, handleActions } from 'redux-actions'; -import fetch from 'isomorphic-fetch'; import Imm from 'immutable'; import { @@ -9,7 +8,7 @@ import { } from './state-mutation'; import { apiRequest, noop, jsonContentTypes } from './utils'; import { - API_SET_ENDPOINT_HOST, API_SET_ENDPOINT_PATH, API_SET_ACCESS_TOKEN, API_WILL_CREATE, API_CREATED, API_CREATE_FAILED, API_WILL_READ, API_READ, API_READ_FAILED, API_WILL_UPDATE, API_UPDATED, API_UPDATE_FAILED, API_WILL_DELETE, API_DELETED, API_DELETE_FAILED + API_SET_AXIOS_CONFIG, API_WILL_CREATE, API_CREATED, API_CREATE_FAILED, API_WILL_READ, API_READ, API_READ_FAILED, API_WILL_UPDATE, API_UPDATED, API_UPDATE_FAILED, API_WILL_DELETE, API_DELETED, API_DELETE_FAILED } from './constants'; // Entity isInvalidating values @@ -17,9 +16,7 @@ export const IS_DELETING = 'IS_DELETING'; export const IS_UPDATING = 'IS_UPDATING'; // Action creators -export const setEndpointHost = createAction(API_SET_ENDPOINT_HOST); -export const setEndpointPath = createAction(API_SET_ENDPOINT_PATH); -export const setAccessToken = createAction(API_SET_ACCESS_TOKEN); +export const setAxiosConfig = createAction(API_SET_AXIOS_CONFIG); const apiWillCreate = createAction(API_WILL_CREATE); const apiCreated = createAction(API_CREATED); @@ -48,24 +45,30 @@ export const uploadFile = (file, { } = {}) => { console.warn('uploadFile has been deprecated and will no longer be supported by redux-json-api https://github.com/dixieio/redux-json-api/issues/2'); + if (onSuccess !== noop || onError !== noop) { + console.warn('onSuccess/onError callbacks are deprecated. Please use returned promise: https://github.com/dixieio/redux-json-api/issues/17'); + } + return (dispatch, getState) => { - const accessToken = getState().api.endpoint.accessToken; + const axiosConfig = getState().api.endpoint.axiosConfig; const path = [companyId, fileableType, fileableId].filter(o => !!o).join('/'); - const url = `${__API_HOST__}/upload/${path}?access_token=${accessToken}`; + const endpoint = `${__API_HOST__}/upload/${path}`; const data = new FormData; data.append('file', file); const options = { + ...axiosConfig, method: 'POST', body: data }; - return fetch(url, options) - .then(res => { + return apiRequest(endpoint, options) + .then((res) => { + onSuccess(res.data); if (res.status >= 200 && res.status < 300) { if (jsonContentTypes.some(contentType => res.headers.get('Content-Type').indexOf(contentType) > -1)) { - return res.json(); + return res.data; } return res; @@ -75,9 +78,6 @@ export const uploadFile = (file, { e.response = res; throw e; }) - .then(json => { - onSuccess(json); - }) .catch(error => { onError(error); }); @@ -95,27 +95,29 @@ export const createEntity = (entity, { return (dispatch, getState) => { dispatch(apiWillCreate(entity)); - const { host: apiHost, path: apiPath, accessToken } = getState().api.endpoint; - const endpoint = `${apiHost}${apiPath}/${entity.type}`; + const { axiosConfig } = getState().api.endpoint; + const endpoint = `${axiosConfig.baseURL}/${entity.type}`; + + const options = { + ...axiosConfig, + method: 'POST', + body: JSON.stringify({ data: entity }) + }; return new Promise((resolve, reject) => { - apiRequest(endpoint, accessToken, { - method: 'POST', - body: JSON.stringify({ - data: entity - }) - }).then(json => { - dispatch(apiCreated(json.data)); - onSuccess(json); - resolve(json); - }).catch(error => { - const err = error; - err.entity = entity; + apiRequest(endpoint, options) + .then(json => { + dispatch(apiCreated(json.data)); + onSuccess(json); + resolve(json); + }).catch(error => { + const err = error; + err.entity = entity; - dispatch(apiCreateFailed(err)); - onError(err); - reject(err); - }); + dispatch(apiCreateFailed(err)); + onError(err); + reject(err); + }); }); }; }; @@ -131,11 +133,11 @@ export const readEndpoint = (endpoint, { return (dispatch, getState) => { dispatch(apiWillRead(endpoint)); - const { host: apiHost, path: apiPath, accessToken } = getState().api.endpoint; - const apiEndpoint = `${apiHost}${apiPath}/${endpoint}`; + const { axiosConfig } = getState().api.endpoint; + const apiEndpoint = `${axiosConfig.baseURL}/${endpoint}`; return new Promise((resolve, reject) => { - apiRequest(`${apiEndpoint}`, accessToken) + apiRequest(apiEndpoint, axiosConfig) .then(json => { dispatch(apiRead({ endpoint, ...json })); onSuccess(json); @@ -164,11 +166,11 @@ export const updateEntity = (entity, { return (dispatch, getState) => { dispatch(apiWillUpdate(entity)); - const { host: apiHost, path: apiPath, accessToken } = getState().api.endpoint; - const endpoint = `${apiHost}${apiPath}/${entity.type}/${entity.id}`; + const { axiosConfig } = getState().api.endpoint; + const endpoint = `${axiosConfig.baseURL}/${entity.id}`; return new Promise((resolve, reject) => { - apiRequest(endpoint, accessToken, { + apiRequest(endpoint, { method: 'PATCH', body: JSON.stringify({ data: entity @@ -200,11 +202,11 @@ export const deleteEntity = (entity, { return (dispatch, getState) => { dispatch(apiWillDelete(entity)); - const { host: apiHost, path: apiPath, accessToken } = getState().api.endpoint; - const endpoint = `${apiHost}${apiPath}/${entity.type}/${entity.id}`; + const { axiosConfig } = getState().api.endpoint; + const endpoint = `${axiosConfig.baseURL}/${entity.type}/${entity.id}`; return new Promise((resolve, reject) => { - apiRequest(endpoint, accessToken, { + apiRequest(endpoint, { method: 'DELETE' }).then(() => { dispatch(apiDeleted(entity)); @@ -248,16 +250,8 @@ export const requireEntity = (entityType, endpoint = entityType, { // Reducers export const reducer = handleActions({ - [API_SET_ACCESS_TOKEN]: (state, { payload: accessToken }) => { - return Imm.fromJS(state).setIn(['endpoint', 'accessToken'], accessToken).toJS(); - }, - - [API_SET_ENDPOINT_HOST]: (state, { payload: host }) => { - return Imm.fromJS(state).setIn(['endpoint', 'host'], host).toJS(); - }, - - [API_SET_ENDPOINT_PATH]: (state, { payload: path }) => { - return Imm.fromJS(state).setIn(['endpoint', 'path'], path).toJS(); + [API_SET_AXIOS_CONFIG]: (state, { payload: axiosConfig }) => { + return Imm.fromJS(state).setIn(['endpoint', 'axiosConfig'], axiosConfig).toJS(); }, [API_WILL_CREATE]: (state) => { @@ -362,6 +356,6 @@ export const reducer = handleActions({ endpoint: { host: null, path: null, - accessToken: null + axiosConfig: {} } }); diff --git a/src/utils.js b/src/utils.js index b1bd345..1460fe1 100644 --- a/src/utils.js +++ b/src/utils.js @@ -1,3 +1,6 @@ +import axios from 'axios'; +import Imm from 'immutable'; + export const jsonContentTypes = [ 'application/json', 'application/vnd.api+json' @@ -5,28 +8,17 @@ export const jsonContentTypes = [ export const noop = () => {}; -export const apiRequest = (url, accessToken, options = {}) => { - const allOptions = { - headers: { - Authorization: `Bearer ${accessToken}`, - 'Content-Type': 'application/vnd.api+json', - Accept: 'application/vnd.api+json' - }, - ...options - }; +export const apiRequest = (url, options = {}) => { + const allOptions = Imm.fromJs(options) + .set('url', url) + .setIn(['headers', 'Content-Type'], 'application/vnd.api+json') + .toJS(); - return fetch(url, allOptions) + return axios(allOptions) .then(res => { - if (res.status >= 200 && res.status < 300) { - if (jsonContentTypes.some(contentType => res.headers.get('Content-Type').indexOf(contentType) > -1)) { - return res.json(); - } - - return res; - } - - const e = new Error(res.statusText); - e.response = res; - throw e; + return res.data; + }) + .catch(res => { + throw res; }); }; diff --git a/test/jsonapi.js b/test/jsonapi.js index 922dd59..27fad8a 100644 --- a/test/jsonapi.js +++ b/test/jsonapi.js @@ -6,9 +6,7 @@ import { createAction } from 'redux-actions'; import expect from 'expect'; import { reducer, - setAccessToken, - setEndpointHost, - setEndpointPath, + setAxiosConfig, IS_DELETING, IS_UPDATING } from '../src/jsonapi'; @@ -23,9 +21,7 @@ const apiWillDelete = createAction('API_WILL_DELETE'); const state = { endpoint: { - host: null, - path: null, - accessToken: null + axiosConfig: {} }, users: { data: [ @@ -362,24 +358,15 @@ describe('Delete entities', () => { }); describe('Endpoint values', () => { - it('should update to provided access token', () => { - const at = 'abcdef0123456789'; - expect(state.endpoint.accessToken).toNotEqual(at); - const updatedState = reducer(state, setAccessToken(at)); - expect(updatedState.endpoint.accessToken).toEqual(at); - }); - - it('should update to provided endpoint host and path', () => { - const host = 'https://api.example.com'; - const path = '/api/v1'; - - expect(state.endpoint.host).toNotEqual(host); - const stateWithHost = reducer(state, setEndpointHost(host)); - expect(stateWithHost.endpoint.host).toEqual(host); - - expect(state.endpoint.path).toNotEqual(path); - const stateWithPath = reducer(state, setEndpointPath(path)); - expect(stateWithPath.endpoint.path).toEqual(path); + it('should update to provided axiosConfig', () => { + const config = { + headers: { + Authorization: 'Bearer abcdef0123456789' + } + }; + expect(state.endpoint.axiosConfig).toNotEqual(config); + const updatedState = reducer(state, setAxiosConfig(config)); + expect(updatedState.endpoint.axiosConfig).toEqual(config); }); }); From ec8d55598d0d7387478acf0009739e0c4334dd77 Mon Sep 17 00:00:00 2001 From: Lars Krieger Date: Mon, 22 Aug 2016 09:40:52 +0200 Subject: [PATCH 056/343] Fixed herader for readEndpoint, mistakenly named createEntity --- docs/apis/readEndpoint.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/apis/readEndpoint.md b/docs/apis/readEndpoint.md index e87ae83..add2f47 100644 --- a/docs/apis/readEndpoint.md +++ b/docs/apis/readEndpoint.md @@ -1,4 +1,4 @@ -## createEntity(value: { object }) +## readEndpoint(value: { object }) Great now we just created a new entity in our database using the `createEntity` method, now we would like to display this to our users. From bd9e1a41a1d4bf361f074b3fbf68df22bd7fac90 Mon Sep 17 00:00:00 2001 From: Lars Krieger Date: Mon, 22 Aug 2016 09:50:01 +0200 Subject: [PATCH 057/343] Add note about api method returns promise --- docs/api.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/api.md b/docs/api.md index 4fdbabb..cd0d5e5 100644 --- a/docs/api.md +++ b/docs/api.md @@ -37,6 +37,11 @@ While dispatching a create action for the following resource will make a request } ``` +## API Promises +The `redux-json-api`'s CRUD API methods will all return a single promise. Within this promise you will recive __`response: {object}`__ as first argument, in this `object` you will find key __`data: {object}`__ that contains all data. + +_Note that `redux-json-api` it self will reduce your data on your redux state._ + ## API Methods #### `createEntity( resource: object ): function` From 6511698d269352c16541501ab7e20837ed01e4c9 Mon Sep 17 00:00:00 2001 From: Lars Krieger Date: Mon, 22 Aug 2016 09:52:20 +0200 Subject: [PATCH 058/343] Updated copy for note to promise returned --- docs/api.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/api.md b/docs/api.md index cd0d5e5..29f8be9 100644 --- a/docs/api.md +++ b/docs/api.md @@ -40,7 +40,7 @@ While dispatching a create action for the following resource will make a request ## API Promises The `redux-json-api`'s CRUD API methods will all return a single promise. Within this promise you will recive __`response: {object}`__ as first argument, in this `object` you will find key __`data: {object}`__ that contains all data. -_Note that `redux-json-api` it self will reduce your data on your redux state._ +_Note that `redux-json-api` by it self will reduce your data on your redux state._ ## API Methods From da0883b804aed1e62b9c071280db124731b08552 Mon Sep 17 00:00:00 2001 From: Lars Krieger Date: Mon, 22 Aug 2016 09:53:50 +0200 Subject: [PATCH 059/343] Updated markdown style --- docs/api.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/api.md b/docs/api.md index 29f8be9..df2c76b 100644 --- a/docs/api.md +++ b/docs/api.md @@ -38,7 +38,7 @@ While dispatching a create action for the following resource will make a request ``` ## API Promises -The `redux-json-api`'s CRUD API methods will all return a single promise. Within this promise you will recive __`response: {object}`__ as first argument, in this `object` you will find key __`data: {object}`__ that contains all data. +The _redux-json-api's_ CRUD API methods will all return a single promise. Within this promise you will recive __`response: {object}`__ as first argument, in this `object` you will find key __`data: {object}`__ that contains all data. _Note that `redux-json-api` by it self will reduce your data on your redux state._ From 3f2429ca01b5cc84ed756d48852d6589ed9b5847 Mon Sep 17 00:00:00 2001 From: Lars Krieger Date: Mon, 22 Aug 2016 09:58:18 +0200 Subject: [PATCH 060/343] Removed note about good reads section --- docs/apis/createEntity.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/apis/createEntity.md b/docs/apis/createEntity.md index 586ac07..324fbef 100644 --- a/docs/apis/createEntity.md +++ b/docs/apis/createEntity.md @@ -1,5 +1,5 @@ ## createEntity(value: { object }) -Dispatching the createEntity function will send a `POST` to the backend, providing it a JSON API compliant object (not sure what this is? head to our "Good reads section"). +Dispatching the createEntity function will send a `POST` to the backend, providing it a JSON API compliant object. ```javascript import { createEntity } from 'redux-json-api' From debdada23add4e6c9ad06f34a322325069856ff6 Mon Sep 17 00:00:00 2001 From: Lars Krieger Date: Mon, 22 Aug 2016 09:59:32 +0200 Subject: [PATCH 061/343] Updated demo class for createEntity example removed connect and inseret import Component --- docs/apis/createEntity.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/apis/createEntity.md b/docs/apis/createEntity.md index 324fbef..b3e99dc 100644 --- a/docs/apis/createEntity.md +++ b/docs/apis/createEntity.md @@ -2,6 +2,7 @@ Dispatching the createEntity function will send a `POST` to the backend, providing it a JSON API compliant object. ```javascript +import { Component } from 'react' import { createEntity } from 'redux-json-api' class CreateTask extends Component { handleSubmit() { @@ -35,7 +36,7 @@ class CreateTask extends Component { } -export default connect()(CreateTask); +export default CreateTask; ``` When submitting the task the `redux-json-api` will dispatch the following actions: From 8dd08e6e3aca7c34e33d6bdf09247945b1540d93 Mon Sep 17 00:00:00 2001 From: Lars Krieger Date: Mon, 22 Aug 2016 10:01:04 +0200 Subject: [PATCH 062/343] Removed note about good reads section in the deleteEntity docs --- docs/apis/deleteEntity.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/apis/deleteEntity.md b/docs/apis/deleteEntity.md index 703735a..abe2967 100644 --- a/docs/apis/deleteEntity.md +++ b/docs/apis/deleteEntity.md @@ -1,5 +1,5 @@ ## deleteEntity(value: { object }) -Dispatching the deleteEntity function will send a `DELETE` to the backend, providing it a JSON API compliant object (not sure what this is? head to our "Good reads section"). +Dispatching the deleteEntity function will send a `DELETE` to the backend, providing it a JSON API compliant object. ```javascript import { deleteEntity } from 'redux-json-api' From 5507114d806bc9c4d81ab010085a03f88dab146e Mon Sep 17 00:00:00 2001 From: Lars Krieger Date: Mon, 22 Aug 2016 10:04:11 +0200 Subject: [PATCH 063/343] Updated copy for deleteEntity --- docs/apis/deleteEntity.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/apis/deleteEntity.md b/docs/apis/deleteEntity.md index abe2967..e6d14d2 100644 --- a/docs/apis/deleteEntity.md +++ b/docs/apis/deleteEntity.md @@ -24,9 +24,9 @@ class TasksOverview extends Component { } -export default connect(mapStateToProps)(TasksOverview); +export default TasksOverview; ``` -When submitting the task the `redux-json-api` will dispatch the following actions: +When submitting the deleation the `redux-json-api` will dispatch the following actions: __API_WILL_DELETE__ _This tells us what payload have been in the que for deletion, and what the `redux-json-api` will ship to the backend_ @@ -35,7 +35,7 @@ action: { payload: { type: 'tasks', attributes: { - task: 'New task created', + task: 'Task should be deleted', completed: false }, relationships: { @@ -50,14 +50,14 @@ action: { } ``` -__API_CREATED__ +__API_DELETED__ _This tells us the response object that we deleted from the server._ ```javascript action: { payload: { type: 'tasks', attributes: { - task: 'New task created', + task: 'Task should be deleted', completed: false }, relationships: { From 8681431778d3e5ad7a6b1967fda2ba920c3cb9d2 Mon Sep 17 00:00:00 2001 From: Lars Krieger Date: Mon, 22 Aug 2016 10:04:52 +0200 Subject: [PATCH 064/343] Removed the import of component in the createEntity example --- docs/apis/createEntity.md | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/apis/createEntity.md b/docs/apis/createEntity.md index b3e99dc..daf8763 100644 --- a/docs/apis/createEntity.md +++ b/docs/apis/createEntity.md @@ -2,7 +2,6 @@ Dispatching the createEntity function will send a `POST` to the backend, providing it a JSON API compliant object. ```javascript -import { Component } from 'react' import { createEntity } from 'redux-json-api' class CreateTask extends Component { handleSubmit() { From 2cda1947d479f0d159168fdf961cf1f5b04020f8 Mon Sep 17 00:00:00 2001 From: Lars Krieger Date: Mon, 22 Aug 2016 10:09:23 +0200 Subject: [PATCH 065/343] Added example note how to get the data from the state to the view in the readEnpoint example --- docs/apis/readEndpoint.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/docs/apis/readEndpoint.md b/docs/apis/readEndpoint.md index add2f47..31ad659 100644 --- a/docs/apis/readEndpoint.md +++ b/docs/apis/readEndpoint.md @@ -4,10 +4,13 @@ Great now we just created a new entity in our database using the `createEntity` ```javascript import { readEndpoint } from 'redux-json-api'; +import { connect } from 'react-redux'; + +const mapStateToProps = ({ api: { tasks }}) => ({ tasks }); class Tasks extends Component { componentWillMount() { const { dispatch } = this.props; - dispatch(readEndpoint('tasks')); //<-- + dispatch(readEndpoint('tasks')); } render() { @@ -18,10 +21,11 @@ class Tasks extends Component { } -export default connect()(Tasks); +export default connect(mapStateToProps)(Tasks); ``` +_Note: in this example we use the `react-redux` `connect` to get tasks from our redux state:_ -When you have dispatched the `readEndpoint`method the reducer will run following actions: +When you have dispatched the `readEndpoint`method the reducer will run following actions. __API_WILL_READ__ _This tells us that the `redux-json-api` will now call your backend with the payload given in this case a simple call to `/tasks´._ From 74e2db47c9dab1076d948454422c8632b0169f0a Mon Sep 17 00:00:00 2001 From: Lars Krieger Date: Mon, 22 Aug 2016 10:10:02 +0200 Subject: [PATCH 066/343] Corrected typo in README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index cd25add..caa70f2 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ The reason for this repository is to keep on a good and healty & simple api for ### Development Guidelines We have a few simple guidelines for how to develop on the tool, and how to build and test it locally. #### Test the code -Beside writing the cases that you might create, there is also a need for you to test the code localy in your project, this can be set up using the `npm link` [How to use npmn link](https://docs.npmjs.com/cli/link), before creating the link you would need to build the code. +Beside writing the cases that you might create, there is also a need for you to test the code localy in your project, this can be set up using the `npm link` [How to use npm link](https://docs.npmjs.com/cli/link), before creating the link you would need to build the code. #### Build the code To build the code for local testing purposed run `npm run build`, this will dist the code make it able to be a part of the node_modules packages in your applications repo. From 40443e538b879912cea63db5d034c111314ceb76 Mon Sep 17 00:00:00 2001 From: Lars Krieger Date: Mon, 22 Aug 2016 10:13:20 +0200 Subject: [PATCH 067/343] Updated updateEntity section --- docs/apis/updateEntity.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/docs/apis/updateEntity.md b/docs/apis/updateEntity.md index 9592324..2545854 100644 --- a/docs/apis/updateEntity.md +++ b/docs/apis/updateEntity.md @@ -1,5 +1,5 @@ ## updateEntity(value: { object }) -Dispatching the createEntity function will send a `PATCH` to the backend, providing it a JSON API compliant object (not sure what this is? head to our "Good reads section"). +Dispatching the createEntity function will send a `PATCH` to the backend, providing it a JSON API compliant object. ```javascript import { updateEntity } from 'redux-json-api' @@ -10,7 +10,7 @@ class UpdateTask extends Component { id: '1', type: 'tasks', attributes: { - task: 'New task string!' + completed: true }, relationships: { taskList: { @@ -35,7 +35,7 @@ class UpdateTask extends Component { } } -export default connect()(UpdateTask); +export default UpdateTask; ``` When updating the task the `redux-json-api` will dispatch the following actions: @@ -48,6 +48,7 @@ action: { type: 'tasks', attributes: { task: 'New task string!' + completed: true }, relationships: { taskList: { @@ -70,7 +71,7 @@ action: { type: 'tasks', attributes: { task: 'New task string!', - completed: false, + completed: true, }, relationships: { taskList: { From 04d754d1a5f983094d03c6f9a142b8905726a8ce Mon Sep 17 00:00:00 2001 From: Lars Krieger Date: Mon, 22 Aug 2016 10:15:11 +0200 Subject: [PATCH 068/343] Removed opinonated way of getting data of redux state, and way to render tasks --- docs/apis/readEndpoint.md | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/docs/apis/readEndpoint.md b/docs/apis/readEndpoint.md index 31ad659..2773407 100644 --- a/docs/apis/readEndpoint.md +++ b/docs/apis/readEndpoint.md @@ -4,9 +4,7 @@ Great now we just created a new entity in our database using the `createEntity` ```javascript import { readEndpoint } from 'redux-json-api'; -import { connect } from 'react-redux'; -const mapStateToProps = ({ api: { tasks }}) => ({ tasks }); class Tasks extends Component { componentWillMount() { const { dispatch } = this.props; @@ -14,16 +12,13 @@ class Tasks extends Component { } render() { - return ( - {this.props.tasks} - ); + // render tasks } } -export default connect(mapStateToProps)(Tasks); +export default Tasks; ``` -_Note: in this example we use the `react-redux` `connect` to get tasks from our redux state:_ When you have dispatched the `readEndpoint`method the reducer will run following actions. From d122ea5764eec62673e1d64a350a2a98f59465f2 Mon Sep 17 00:00:00 2001 From: Lars Krieger Date: Mon, 22 Aug 2016 10:16:14 +0200 Subject: [PATCH 069/343] Emptied demo render function --- docs/apis/updateEntity.md | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/docs/apis/updateEntity.md b/docs/apis/updateEntity.md index 2545854..96e8cb2 100644 --- a/docs/apis/updateEntity.md +++ b/docs/apis/updateEntity.md @@ -26,12 +26,7 @@ class UpdateTask extends Component { } render() { - return ( -
- - -
- ); + // render view } } From fd4fd413a767afe363b5c45c8da82987476a1630 Mon Sep 17 00:00:00 2001 From: Lars Krieger Date: Mon, 22 Aug 2016 10:16:50 +0200 Subject: [PATCH 070/343] Empty demo render function for createEntity --- docs/apis/createEntity.md | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/docs/apis/createEntity.md b/docs/apis/createEntity.md index daf8763..9fd353f 100644 --- a/docs/apis/createEntity.md +++ b/docs/apis/createEntity.md @@ -25,12 +25,7 @@ class CreateTask extends Component { } render() { - return ( -
- - -
- ); + // render view } } From 689a008d548d592df9ebfd7081da744e3f7d8fee Mon Sep 17 00:00:00 2001 From: Lars Krieger Date: Mon, 22 Aug 2016 10:17:13 +0200 Subject: [PATCH 071/343] Empty demo render function for deleteEntity --- docs/apis/deleteEntity.md | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/docs/apis/deleteEntity.md b/docs/apis/deleteEntity.md index e6d14d2..6f7c243 100644 --- a/docs/apis/deleteEntity.md +++ b/docs/apis/deleteEntity.md @@ -10,16 +10,7 @@ class TasksOverview extends Component { } render() { - return ( -
-
-

This tasks should be deleted

-
-
-
- ); + // render view } } From 027a471087397c6c84b1b7ea7ba9429a813b4f0e Mon Sep 17 00:00:00 2001 From: Lars Krieger Date: Mon, 22 Aug 2016 10:18:16 +0200 Subject: [PATCH 072/343] Updated copy for api.md toc --- docs/api.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/api.md b/docs/api.md index df2c76b..5deadf2 100644 --- a/docs/api.md +++ b/docs/api.md @@ -5,7 +5,7 @@ _redux-json-api_ provides a simple API for all four CRUD actions. - Create resource objects using [createEntity](#createentity-resource-object--function) - Read endpoints using [readEndpoint](#readendpoint-endpoint-string--function) -- Update using [updateEntity](#updateentity-resource-object--function) +- Update entities using [updateEntity](#updateentity-resource-object--function) - Delete resources using [deleteEntity](#deleteentity-resource-object--function) ## Resource objects From 048b85c0e2ee245659b4c6e6cca4ac5b026a522a Mon Sep 17 00:00:00 2001 From: Lars Krieger Date: Mon, 22 Aug 2016 10:20:00 +0200 Subject: [PATCH 073/343] Linked the resource object specfication to the api.md note about resource objects --- docs/api.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/api.md b/docs/api.md index 5deadf2..a9f3eb1 100644 --- a/docs/api.md +++ b/docs/api.md @@ -10,7 +10,7 @@ _redux-json-api_ provides a simple API for all four CRUD actions. ## Resource objects -Whenever there's referred to a resource object or entity, it must conform to JSON API specifications. +Whenever there's referred to a resource object or entity, it must conform to [JSON API specifications](http://jsonapi.org/format/#document-resource-objects). ## Resource endpoints From c5f02fea2b0b3f0994f8d2e2f4468f213f0ff735 Mon Sep 17 00:00:00 2001 From: Lars Krieger Date: Mon, 22 Aug 2016 10:21:16 +0200 Subject: [PATCH 074/343] Fixed copy recive -> receive --- docs/api.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/api.md b/docs/api.md index a9f3eb1..0e35cfa 100644 --- a/docs/api.md +++ b/docs/api.md @@ -38,7 +38,7 @@ While dispatching a create action for the following resource will make a request ``` ## API Promises -The _redux-json-api's_ CRUD API methods will all return a single promise. Within this promise you will recive __`response: {object}`__ as first argument, in this `object` you will find key __`data: {object}`__ that contains all data. +The _redux-json-api's_ CRUD API methods will all return a single promise. Within this promise you will receive __`response: {object}`__ as first argument, in this `object` you will find key __`data: {object}`__ that contains all data. _Note that `redux-json-api` by it self will reduce your data on your redux state._ From 2cd69e0c7141834df3e11a09fc01e20fbf750363 Mon Sep 17 00:00:00 2001 From: Lars Krieger Date: Mon, 22 Aug 2016 10:24:08 +0200 Subject: [PATCH 075/343] Updated the reducer setup step for set-up-configure --- docs/set-up-configure.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/set-up-configure.md b/docs/set-up-configure.md index 371f5c9..c15e020 100644 --- a/docs/set-up-configure.md +++ b/docs/set-up-configure.md @@ -14,11 +14,12 @@ Getting _redux-json-api_ set up requires __4 steps__ which we will cover here. ## Add reducer to _api_ namespace -The current version of _redux-json-api_ assumes that it's reducer will be attached to the api namespace of your Redux state. +The current version of _redux-json-api_ assumes that it's reducer reduced on to your root reducer under the namespace _api (in this example)_. You can achieve this by using [combineReducers](http://redux.js.org/docs/api/combineReducers.html) from Redux: ```js +// rootReducer.js import { combineReducers } from 'redux'; import { reducer as api } from 'redux-json-api'; From 54dc1e4a51487c57f9a97f3d5fcde047862315a8 Mon Sep 17 00:00:00 2001 From: Lars Krieger Date: Mon, 22 Aug 2016 14:28:14 +0200 Subject: [PATCH 076/343] Remove API for uploadFile --- src/jsonapi.js | 47 ----------------------------------------------- 1 file changed, 47 deletions(-) diff --git a/src/jsonapi.js b/src/jsonapi.js index 69ee384..229e01c 100644 --- a/src/jsonapi.js +++ b/src/jsonapi.js @@ -37,53 +37,6 @@ const apiWillDelete = createAction(API_WILL_DELETE); const apiDeleted = createAction(API_DELETED); const apiDeleteFailed = createAction(API_DELETE_FAILED); -// Actions -export const uploadFile = (file, { - companyId, - fileableType: fileableType = null, - fileableId: fileableId = null -}, { - onSuccess: onSuccess = noop, - onError: onError = noop -} = {}) => { - console.warn('uploadFile has been deprecated and will no longer be supported by redux-json-api https://github.com/dixieio/redux-json-api/issues/2'); - - return (dispatch, getState) => { - const accessToken = getState().api.endpoint.accessToken; - const path = [companyId, fileableType, fileableId].filter(o => !!o).join('/'); - const url = `${__API_HOST__}/upload/${path}?access_token=${accessToken}`; - - const data = new FormData; - data.append('file', file); - - const options = { - method: 'POST', - body: data - }; - - return fetch(url, options) - .then(res => { - if (res.status >= 200 && res.status < 300) { - if (jsonContentTypes.some(contentType => res.headers.get('Content-Type').indexOf(contentType) > -1)) { - return res.json(); - } - - return res; - } - - const e = new Error(res.statusText); - e.response = res; - throw e; - }) - .then(json => { - onSuccess(json); - }) - .catch(error => { - onError(error); - }); - }; -}; - export const createEntity = (entity, { onSuccess: onSuccess = noop, onError: onError = noop From 7ca5e9b45f433d4ffc68797a672615c8cf54bcb6 Mon Sep 17 00:00:00 2001 From: Lars Krieger Date: Mon, 22 Aug 2016 14:31:35 +0200 Subject: [PATCH 077/343] Removed unused dependencies --- src/jsonapi.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/jsonapi.js b/src/jsonapi.js index 229e01c..6da1698 100644 --- a/src/jsonapi.js +++ b/src/jsonapi.js @@ -1,5 +1,4 @@ import { createAction, handleActions } from 'redux-actions'; -import fetch from 'isomorphic-fetch'; import Imm from 'immutable'; import { @@ -7,7 +6,7 @@ import { updateOrInsertEntitiesIntoState, setIsInvalidatingForExistingEntity } from './state-mutation'; -import { apiRequest, noop, jsonContentTypes } from './utils'; +import { apiRequest, noop } from './utils'; import { API_SET_ENDPOINT_HOST, API_SET_ENDPOINT_PATH, API_SET_ACCESS_TOKEN, API_WILL_CREATE, API_CREATED, API_CREATE_FAILED, API_WILL_READ, API_READ, API_READ_FAILED, API_WILL_UPDATE, API_UPDATED, API_UPDATE_FAILED, API_WILL_DELETE, API_DELETED, API_DELETE_FAILED } from './constants'; From 2c4ea2f20ab8630f65fe75b7ca2e762983a27477 Mon Sep 17 00:00:00 2001 From: Lars Krieger Date: Mon, 22 Aug 2016 14:37:05 +0200 Subject: [PATCH 078/343] Removed onError & onSucces from createEntity --- src/jsonapi.js | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/src/jsonapi.js b/src/jsonapi.js index 69ee384..502f390 100644 --- a/src/jsonapi.js +++ b/src/jsonapi.js @@ -84,14 +84,7 @@ export const uploadFile = (file, { }; }; -export const createEntity = (entity, { - onSuccess: onSuccess = noop, - onError: onError = noop -} = {}) => { - if (onSuccess !== noop || onError !== noop) { - console.warn('onSuccess/onError callbacks are deprecated. Please use returned promise: https://github.com/dixieio/redux-json-api/issues/17'); - } - +export const createEntity = (entity) => { return (dispatch, getState) => { dispatch(apiWillCreate(entity)); @@ -106,14 +99,12 @@ export const createEntity = (entity, { }) }).then(json => { dispatch(apiCreated(json.data)); - onSuccess(json); resolve(json); }).catch(error => { const err = error; err.entity = entity; dispatch(apiCreateFailed(err)); - onError(err); reject(err); }); }); From 74ac0f661646e916f080789aec4032df3928d0e6 Mon Sep 17 00:00:00 2001 From: Lars Krieger Date: Mon, 22 Aug 2016 14:37:49 +0200 Subject: [PATCH 079/343] Removed onError & onSucces from readEndpoint --- src/jsonapi.js | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/src/jsonapi.js b/src/jsonapi.js index 502f390..0f65911 100644 --- a/src/jsonapi.js +++ b/src/jsonapi.js @@ -111,14 +111,7 @@ export const createEntity = (entity) => { }; }; -export const readEndpoint = (endpoint, { - onSuccess: onSuccess = noop, - onError: onError = noop -} = {}) => { - if (onSuccess !== noop || onError !== noop) { - console.warn('onSuccess/onError callbacks are deprecated. Please use returned promise: https://github.com/dixieio/redux-json-api/issues/17'); - } - +export const readEndpoint = (endpoint) => { return (dispatch, getState) => { dispatch(apiWillRead(endpoint)); @@ -129,7 +122,6 @@ export const readEndpoint = (endpoint, { apiRequest(`${apiEndpoint}`, accessToken) .then(json => { dispatch(apiRead({ endpoint, ...json })); - onSuccess(json); resolve(json); }) .catch(error => { @@ -137,7 +129,6 @@ export const readEndpoint = (endpoint, { err.endpoint = endpoint; dispatch(apiReadFailed(err)); - onError(err); reject(err); }); }); From 498d3322204a0d5d16d81eb78248e61524625c18 Mon Sep 17 00:00:00 2001 From: Lars Krieger Date: Mon, 22 Aug 2016 14:39:25 +0200 Subject: [PATCH 080/343] Removed onError & onSucces from updateEntity --- src/jsonapi.js | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/src/jsonapi.js b/src/jsonapi.js index 0f65911..93fa856 100644 --- a/src/jsonapi.js +++ b/src/jsonapi.js @@ -135,14 +135,7 @@ export const readEndpoint = (endpoint) => { }; }; -export const updateEntity = (entity, { - onSuccess: onSuccess = noop, - onError: onError = noop -} = {}) => { - if (onSuccess !== noop || onError !== noop) { - console.warn('onSuccess/onError callbacks are deprecated. Please use returned promise: https://github.com/dixieio/redux-json-api/issues/17'); - } - +export const updateEntity = (entity) => { return (dispatch, getState) => { dispatch(apiWillUpdate(entity)); @@ -157,14 +150,12 @@ export const updateEntity = (entity, { }) }).then(json => { dispatch(apiUpdated(json.data)); - onSuccess(json); resolve(json); }).catch(error => { const err = error; err.entity = entity; dispatch(apiUpdateFailed(err)); - onError(err); reject(err); }); }); From a3f157045bcde4c5aa0c51f685a2eb0b03a9bc5a Mon Sep 17 00:00:00 2001 From: Lars Krieger Date: Mon, 22 Aug 2016 14:40:14 +0200 Subject: [PATCH 081/343] Removed onError & onSucces from deleteEntity --- src/jsonapi.js | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/src/jsonapi.js b/src/jsonapi.js index 93fa856..7246aae 100644 --- a/src/jsonapi.js +++ b/src/jsonapi.js @@ -162,14 +162,7 @@ export const updateEntity = (entity) => { }; }; -export const deleteEntity = (entity, { - onSuccess: onSuccess = noop, - onError: onError = noop -} = {}) => { - if (onSuccess !== noop || onError !== noop) { - console.warn('onSuccess/onError callbacks are deprecated. Please use returned promise: https://github.com/dixieio/redux-json-api/issues/17'); - } - +export const deleteEntity = (entity) => { return (dispatch, getState) => { dispatch(apiWillDelete(entity)); @@ -181,14 +174,12 @@ export const deleteEntity = (entity, { method: 'DELETE' }).then(() => { dispatch(apiDeleted(entity)); - onSuccess(); resolve(); }).catch(error => { const err = error; err.entity = entity; dispatch(apiDeleteFailed(err)); - onError(err); reject(err); }); }); From 60d7a293363cf3cc8b70a4974a01b18e58136af6 Mon Sep 17 00:00:00 2001 From: Lars Krieger Date: Mon, 22 Aug 2016 14:41:54 +0200 Subject: [PATCH 082/343] Removed onError & onSucces from requireEntity --- src/jsonapi.js | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/src/jsonapi.js b/src/jsonapi.js index 7246aae..dc5bf5f 100644 --- a/src/jsonapi.js +++ b/src/jsonapi.js @@ -186,23 +186,15 @@ export const deleteEntity = (entity) => { }; }; -export const requireEntity = (entityType, endpoint = entityType, { - onSuccess: onSuccess = noop, - onError: onError = noop -} = {}) => { - if (onSuccess !== noop || onError !== noop) { - console.warn('onSuccess/onError callbacks are deprecated. Please use returned promise: https://github.com/dixieio/redux-json-api/issues/17'); - } - +export const requireEntity = (entityType, endpoint = entityType) => { return (dispatch, getState) => { return new Promise((resolve, reject) => { const { api } = getState(); if (api.hasOwnProperty(entityType)) { resolve(); - return onSuccess(); } - dispatch(readEndpoint(endpoint, { onSuccess, onError })) + dispatch(readEndpoint(endpoint)) .then(resolve) .catch(reject); }); From fb005387877c9b92239212612665418339e0c5d8 Mon Sep 17 00:00:00 2001 From: Ronni Egeriis Persson Date: Mon, 22 Aug 2016 17:08:21 +0200 Subject: [PATCH 083/343] Attempt to make phrasing of use case better --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index caa70f2..7acfea5 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ This library is intended for use in web applications build on Redux, which consumes data from a [JSON API](http://jsonapi.org/). -Use _redux-json-api_ to have one simple way of storing resource objects in Redux state along with the CRUD API, which provides easy ways to create, read, update and delete resources. +Use _redux-json-api_ to have one simple way of storing resource objects in Redux state along with it's CRUD API, which provides easy ways to create, read, update and delete resources. Please raise any questions as an [Issue](issues) or submit your contributions as a [Pull Request](pulls). Remember to review our [contributions guidelines](CONTRIBUTING.md). From b5067b1693ddac98865f2ab6361fbe6d53c9564b Mon Sep 17 00:00:00 2001 From: Lars Krieger Date: Mon, 22 Aug 2016 17:10:21 +0200 Subject: [PATCH 084/343] Added hasOwnProperties to utill's and updated the getPaginationUrl --- src/utils.js | 37 ++++++++++++++++++------------------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/src/utils.js b/src/utils.js index d27bda6..7028fb5 100644 --- a/src/utils.js +++ b/src/utils.js @@ -31,28 +31,27 @@ export const apiRequest = (url, accessToken, options = {}) => { }); }; -export const getPaginationUrl = (json, direction, host, path) => { - if (!json.links) { - return null; +const hasOwnProperties = (obj, propertyTree) => { + if ((obj instanceof Object) === false) { + return false; } - - if (direction === 'next') { - if (!json.links.next) { - return null; + const property = propertyTree[0]; + const hasProperty = obj.hasOwnProperty(property); + if (hasProperty) { + if (propertyTree.length === 1) { + return hasProperty; } - - return json.links.next - .replace(host, '') - .replace(`${path}/`, ''); + return hasOwnProperties(obj[property], propertyTree.slice(1)); } + return false; +}; - if (direction === 'prev') { - if (!json.links.prev) { - return null; - } - - return json.links.prev - .replace(host, '') - .replace(`${path}/`, ''); +export const getPaginationUrl = (response, direction, host, path) => { + if (!response.links || !hasOwnProperties(response, ['links', direction])) { + return null; } + + return response.links[direction] + .replace(host, '') + .replace(`${path}/`, ''); }; From 0331086e4382ec5664278c6abbd6d30a9954bf3a Mon Sep 17 00:00:00 2001 From: Ronni Egeriis Persson Date: Mon, 22 Aug 2016 17:11:01 +0200 Subject: [PATCH 085/343] Link to contributing guidelines and remove section about contrib. in README --- README.md | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/README.md b/README.md index 7acfea5..149c0de 100644 --- a/README.md +++ b/README.md @@ -21,18 +21,7 @@ Please raise any questions as an [Issue](issues) or submit your contributions as - [__JSON API__](http://www.jsonapi.org/) - Read about the specifications for JSON API. ## Contribute -The reason for this repository is to keep on a good and healty & simple api for _JSON API_, for Redux applications weahter you use it in _react_ or any other framework of choise. Feel like getting envolved into to this, then get cloning and follow our simple guide lines, if you just want to give feedback or report bug click that [issues](https://github.com/dixieio/redux-json-api/issues) button and lets talk about it. - -### Development Guidelines -We have a few simple guidelines for how to develop on the tool, and how to build and test it locally. -#### Test the code -Beside writing the cases that you might create, there is also a need for you to test the code localy in your project, this can be set up using the `npm link` [How to use npm link](https://docs.npmjs.com/cli/link), before creating the link you would need to build the code. - -#### Build the code -To build the code for local testing purposed run `npm run build`, this will dist the code make it able to be a part of the node_modules packages in your applications repo. - -#### Create a PR -You have done really cool work, __KUDOS__! 🎉, now you want to contrubute the code and you create a _PR_, we will then review the pull request. +Got any feedback or suggestions? Review our [contribution guidelines](CONTRIBUTING.md). ## Contributors Made with 💜 from the [Dixie](http://www.dixie.io) team, and our lovely [contributers](graphs/contributors)! From d65485a9d0fb85239d3f7e4be5ff444636ee7400 Mon Sep 17 00:00:00 2001 From: Lars Krieger Date: Mon, 22 Aug 2016 17:14:16 +0200 Subject: [PATCH 086/343] readEndpoint now return a new class, that contains loaders for pagination, and response body --- src/jsonapi.js | 36 +++++++++++++++++++++++------------- 1 file changed, 23 insertions(+), 13 deletions(-) diff --git a/src/jsonapi.js b/src/jsonapi.js index 40d9182..b856929 100644 --- a/src/jsonapi.js +++ b/src/jsonapi.js @@ -120,6 +120,27 @@ export const createEntity = (entity, { }; }; +class ApiResponse { + constructor(response, dispatch, nextUrl, prevUrl) { + this.body = response; + this.dispatch = dispatch; + this.nextUrl = nextUrl; + this.prevUrl = prevUrl; + this.loadNext = this.loadNext.bind(this); + this.loadPrev = this.loadPrev.bind(this); + } + + /* eslint-disable */ + loadNext() { + return this.dispatch(readEndpoint(this.nextUrl)); + } + + prevNext() { + return this.dispatch(readEndpoint(this.prevUrl)); + } + /* eslint-enable */ +} + export const readEndpoint = (endpoint, { onSuccess: onSuccess = noop, onError: onError = noop @@ -140,21 +161,10 @@ export const readEndpoint = (endpoint, { dispatch(apiRead({ endpoint, ...json })); onSuccess(json); - const prevUrl = getPaginationUrl(json, 'prev', apiHost, apiPath); const nextUrl = getPaginationUrl(json, 'next', apiHost, apiPath); + const prevUrl = getPaginationUrl(json, 'prev', apiHost, apiPath); - const getPrevPage = () => dispatch(readEndpoint(prevUrl)); - const getNextPage = () => dispatch(readEndpoint(nextUrl)); - - const resObj = { - response: json, - pagination: { - getPrevPage: !prevUrl ? null : getPrevPage, - getNextPage: !nextUrl ? null : getNextPage, - } - }; - - resolve(resObj); + resolve(new ApiResponse(json, dispatch, nextUrl, prevUrl)); }) .catch(error => { const err = error; From bd12d5bf4ede5ccb6a5647efb0c73c5553b8c9d7 Mon Sep 17 00:00:00 2001 From: Ronni Egeriis Persson Date: Tue, 23 Aug 2016 10:59:55 +0200 Subject: [PATCH 087/343] Move italic marker --- docs/api.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/api.md b/docs/api.md index 0e35cfa..871756a 100644 --- a/docs/api.md +++ b/docs/api.md @@ -38,7 +38,7 @@ While dispatching a create action for the following resource will make a request ``` ## API Promises -The _redux-json-api's_ CRUD API methods will all return a single promise. Within this promise you will receive __`response: {object}`__ as first argument, in this `object` you will find key __`data: {object}`__ that contains all data. +The _redux-json-api_'s CRUD API methods will all return a single promise. Within this promise you will receive __`response: {object}`__ as first argument, in this `object` you will find key __`data: {object}`__ that contains all data. _Note that `redux-json-api` by it self will reduce your data on your redux state._ From e2a3c2fa8371bc8fdac863c01eeaf83090b8810e Mon Sep 17 00:00:00 2001 From: Ronni Egeriis Persson Date: Tue, 23 Aug 2016 11:00:05 +0200 Subject: [PATCH 088/343] Remove confusing note --- docs/set-up-configure.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/set-up-configure.md b/docs/set-up-configure.md index c15e020..827cfed 100644 --- a/docs/set-up-configure.md +++ b/docs/set-up-configure.md @@ -14,7 +14,7 @@ Getting _redux-json-api_ set up requires __4 steps__ which we will cover here. ## Add reducer to _api_ namespace -The current version of _redux-json-api_ assumes that it's reducer reduced on to your root reducer under the namespace _api (in this example)_. +The current version of _redux-json-api_ assumes that it's reducer reduced on to your root reducer under the namespace _api_. You can achieve this by using [combineReducers](http://redux.js.org/docs/api/combineReducers.html) from Redux: From 656f2a0d3eaf997f79db96a0421a5c9ae4ccac35 Mon Sep 17 00:00:00 2001 From: Ronni Egeriis Persson Date: Tue, 23 Aug 2016 11:02:47 +0200 Subject: [PATCH 089/343] Register redux-thunk as peerDependency --- package.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/package.json b/package.json index ad0d09d..cb7a6b4 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,9 @@ "url": "https://github.com/dixieio/redux-json-api/issues" }, "homepage": "https://github.com/dixieio/redux-json-api#readme", + "peerDependencies": { + "redux-thunk": "^1.0.0" + }, "devDependencies": { "babel-core": "^6.4.5", "babel-eslint": "^5.0.0-beta6", From f0ce59907dec1ea3570f3323c5f237d4a74350be Mon Sep 17 00:00:00 2001 From: Ronni Egeriis Persson Date: Tue, 23 Aug 2016 11:05:11 +0200 Subject: [PATCH 090/343] Use singular work for createEntity desc as it only supports creation of 1 resource at a time --- docs/api.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/api.md b/docs/api.md index 871756a..7281b60 100644 --- a/docs/api.md +++ b/docs/api.md @@ -3,10 +3,10 @@ API _redux-json-api_ provides a simple API for all four CRUD actions. -- Create resource objects using [createEntity](#createentity-resource-object--function) - Read endpoints using [readEndpoint](#readendpoint-endpoint-string--function) - Update entities using [updateEntity](#updateentity-resource-object--function) - Delete resources using [deleteEntity](#deleteentity-resource-object--function) +- Create resource object using [createEntity](#createentity-resource-object--function) ## Resource objects From 118752ef1891775eb11dcded6bc4c0d9247440e9 Mon Sep 17 00:00:00 2001 From: Ronni Egeriis Persson Date: Tue, 23 Aug 2016 11:05:47 +0200 Subject: [PATCH 091/343] Some phrasing optimizations --- docs/api.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/api.md b/docs/api.md index 7281b60..ddf1872 100644 --- a/docs/api.md +++ b/docs/api.md @@ -3,10 +3,10 @@ API _redux-json-api_ provides a simple API for all four CRUD actions. -- Read endpoints using [readEndpoint](#readendpoint-endpoint-string--function) -- Update entities using [updateEntity](#updateentity-resource-object--function) -- Delete resources using [deleteEntity](#deleteentity-resource-object--function) - Create resource object using [createEntity](#createentity-resource-object--function) +- Read endpoints through [readEndpoint](#readendpoint-endpoint-string--function) +- Update resource with [updateEntity](#updateentity-resource-object--function) +- Delete resource using [deleteEntity](#deleteentity-resource-object--function) ## Resource objects From 58a23bef5271595d4eb48a78b5148fcd5b659805 Mon Sep 17 00:00:00 2001 From: Ronni Egeriis Persson Date: Tue, 23 Aug 2016 11:10:06 +0200 Subject: [PATCH 092/343] Rephrase description of promises and the argument passed to fulfillment handler --- docs/api.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/api.md b/docs/api.md index ddf1872..013e818 100644 --- a/docs/api.md +++ b/docs/api.md @@ -37,10 +37,10 @@ While dispatching a create action for the following resource will make a request } ``` + ## API Promises -The _redux-json-api_'s CRUD API methods will all return a single promise. Within this promise you will receive __`response: {object}`__ as first argument, in this `object` you will find key __`data: {object}`__ that contains all data. +The _redux-json-api_'s CRUD API methods will all return a single promise. The fulfillment handler will receive one argument with the response body. One exception to this is the fulfillment handler from a `deleteEntity` promise, which will not receive any arguments. -_Note that `redux-json-api` by it self will reduce your data on your redux state._ ## API Methods From c4d796bc858dac286bc80728286246d950de2b58 Mon Sep 17 00:00:00 2001 From: Ronni Egeriis Persson Date: Tue, 23 Aug 2016 11:17:56 +0200 Subject: [PATCH 093/343] Update return value docs to Promise and add note --- docs/api.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/docs/api.md b/docs/api.md index 013e818..f21f690 100644 --- a/docs/api.md +++ b/docs/api.md @@ -44,25 +44,27 @@ The _redux-json-api_'s CRUD API methods will all return a single promise. The fu ## API Methods -#### `createEntity( resource: object ): function` +Note: Return values noted below are after dispatch, i.e. `dispatch(createEntity({ ... }))`. + +#### `createEntity( resource: object ): Promise` Use this action creator to trigger a POST request to your API with the given resource. [Examples and details here.](apis/createEntity.md) -#### `readEndpoint( endpoint: string ): function` +#### `readEndpoint( endpoint: string ): Promise` This action creator will trigger a GET request to the specified endpoint. [Read more.](apis/readEndpoint.md) -#### `updateEntity( resource: object ): function` +#### `updateEntity( resource: object ): Promise` Update entities using this action creator. It will make a PATCH request to your API. [Details and examples.](apis/updateEntity.md) -#### `deleteEntity( resource: object ): function` +#### `deleteEntity( resource: object ): Promise` Use this action creator to issue a DELETE request to your API. From c815241563a83b20264a46e1b6b63f9e260c32fa Mon Sep 17 00:00:00 2001 From: Ronni Egeriis Persson Date: Tue, 23 Aug 2016 11:19:02 +0200 Subject: [PATCH 094/343] Streamline action creator docs --- docs/apis/createEntity.md | 2 +- docs/apis/deleteEntity.md | 2 +- docs/apis/readEndpoint.md | 2 +- docs/apis/updateEntity.md | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/apis/createEntity.md b/docs/apis/createEntity.md index 9fd353f..b372ec4 100644 --- a/docs/apis/createEntity.md +++ b/docs/apis/createEntity.md @@ -1,4 +1,4 @@ -## createEntity(value: { object }) +### `createEntity( resource: object ): Promise` Dispatching the createEntity function will send a `POST` to the backend, providing it a JSON API compliant object. ```javascript diff --git a/docs/apis/deleteEntity.md b/docs/apis/deleteEntity.md index 6f7c243..db20327 100644 --- a/docs/apis/deleteEntity.md +++ b/docs/apis/deleteEntity.md @@ -1,4 +1,4 @@ -## deleteEntity(value: { object }) +## `deleteEntity( resource: object ): Promise` Dispatching the deleteEntity function will send a `DELETE` to the backend, providing it a JSON API compliant object. ```javascript diff --git a/docs/apis/readEndpoint.md b/docs/apis/readEndpoint.md index 2773407..518e74b 100644 --- a/docs/apis/readEndpoint.md +++ b/docs/apis/readEndpoint.md @@ -1,4 +1,4 @@ -## readEndpoint(value: { object }) +### `readEndpoint( endpoint: string ): Promise` Great now we just created a new entity in our database using the `createEntity` method, now we would like to display this to our users. diff --git a/docs/apis/updateEntity.md b/docs/apis/updateEntity.md index 96e8cb2..3755c32 100644 --- a/docs/apis/updateEntity.md +++ b/docs/apis/updateEntity.md @@ -1,4 +1,4 @@ -## updateEntity(value: { object }) +### `updateEntity( resource: object ): Promise` Dispatching the createEntity function will send a `PATCH` to the backend, providing it a JSON API compliant object. ```javascript From ad718f2660df5d78d5d5701652dfe283c4cd6fd1 Mon Sep 17 00:00:00 2001 From: Ronni Egeriis Persson Date: Tue, 23 Aug 2016 11:31:56 +0200 Subject: [PATCH 095/343] Update example and description --- docs/apis/createEntity.md | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/docs/apis/createEntity.md b/docs/apis/createEntity.md index b372ec4..21b6792 100644 --- a/docs/apis/createEntity.md +++ b/docs/apis/createEntity.md @@ -1,8 +1,13 @@ ### `createEntity( resource: object ): Promise` -Dispatching the createEntity function will send a `POST` to the backend, providing it a JSON API compliant object. -```javascript +Dispatch function returned from `createEntity` to issue a `POST` request to your API. + +#### Example + +```js +import { connect } from 'react-redux'; import { createEntity } from 'redux-json-api' + class CreateTask extends Component { handleSubmit() { const { dispatch } = this.props; @@ -25,12 +30,11 @@ class CreateTask extends Component { } render() { - // render view + return