GithubHelp home page GithubHelp logo

jamesplease / redux-resource Goto Github PK

View Code? Open in Web Editor NEW
237.0 7.0 36.0 2.3 MB

3kb resource management for Redux

Home Page: https://redux-resource.js.org

License: MIT License

JavaScript 99.65% HTML 0.35%
redux resources database

redux-resource's Introduction

Redux Resource Logo

Redux Resource Travis Builds Redux Resource NPM Package Redux Resource NPM Download Count Redux Resource Code Coverage Redux Resource gzip Size

A tiny but powerful system for managing 'resources': data that is persisted to remote servers.

✓ Removes nearly all boilerplate code for remotely-stored data
✓ Incrementally adoptable
✓ Encourages best practices like normalized state
✓ Works well with APIs that adhere to standardized formats, such as JSON API
✓ Works well with APIs that don't adhere to standardized formats, too
✓ Integrates well with your favorite technologies: HTTP, gRPC, normalizr, redux-observable, redux-saga, and more
✓ Microscopic file size (3kb gzipped!)

Installation

To install the latest version:

npm install --save redux-resource

Documentation

View the documentation at redux-resource.js.org ⇗.

Looking for the v2.4.1 documentation? View it here.

Migration guides to the latest version can be found here.

Quick Start

Follow this guide to get a taste of what it's like to work with Redux Resource.

First, we set up our store with a "resource reducer," which is a reducer that manages the state for one type of resource. In this guide, our reducer will handle the data for our "books" resource.

import { createStore, combineReducers } from 'redux';
import { resourceReducer } from 'redux-resource';

const reducer = combineReducers({
  books: resourceReducer('books')
});

const store = createStore(reducer);

Once we have a store, we can start dispatching actions to it. In this example, we initiate a request to read a book with an ID of 24, then follow it up with an action representing success. There are two actions, because requests usually occur over a network, and therefore take time to complete.

import { actionTypes } from 'redux-resource';
import store from './store';

// This action represents beginning the request to read a book with ID of 24. This
// could represent the start of an HTTP request, for instance.
store.dispatch({
  type: actionTypes.READ_RESOURCES_PENDING,
  resourceType: 'books',
  resources: [24]
});

// Later, when the request succeeds, we dispatch the success action.
store.dispatch({
  type: actionTypes.READ_RESOURCES_SUCCEEDED,
  resourceType: 'books',
  // The `resources` list here is usually the response from an API call
  resources: [{
    id: 24,
    title: 'My Name is Red',
    releaseYear: 1998,
    author: 'Orhan Pamuk'
  }]
});

Later, in your view layer, you can access information about the status of this request. When it succeeds, accessing the returned book is straightforward.

import { getStatus } from 'redux-resource';
import store from './store';

const state = store.getState();
// The second argument to this method is a path into the state tree. This method
// protects you from needing to check for undefined values.
const readStatus = getStatus(store, 'books.meta[24].readStatus');

if (readStatus.pending) {
  console.log('The request is in flight.');
}

else if (readStatus.failed) {
  console.log('The request failed.');
}

else if (readStatus.succeeded) {
  const book = state.books.resources[24];

  console.log('The book was retrieved successfully, and here is the data:', book);
}

This is just a small sample of what it's like working with Redux Resource.

For a real-life webapp example that uses many more CRUD operations, check out the zero-boilerplate-redux webapp ⇗. This example project uses React, although Redux Resource works well with any view layer.

Repository Structure

This repository is a Lerna project. That means it's a single repository that allows us to control the publishing of a number of packages. The source for each package can be found in the ./packages directory.

Package Version Description
redux-resource npm version The main library
redux-resource-xhr npm version A library that exports a powerful HTTP CRUD action creator
redux-resource-plugins npm version A collection of common plugins
redux-resource-prop-types npm version Handy Prop Types to use with Redux Resource
redux-resource-action-creators npm version Unopinionated action creators for Redux Resource (bring your own HTTP request)

Contributing

Thanks for your interest in helping out! Check out the Contributing Guide, which covers everything you'll need to get up and running.

Contributors

(Emoji key)


James, please

💻 🔌 📖 🤔

Stephen Rivas JR

💻 📖 🤔 🔌

Ian Stewart

🤔

Tim Branyen

🤔

Jason Laster

🤔

marlonpp

🤔

Javier Porrero

🤔

Smai Fullerton

📖

vinodkl

🤔

Eric Valadas

📖

Jeremy Fairbank

🚇

Yihang Ho

💻

Bryce Reynolds

💡

Ben Creasy

📖

Guillaume Jasmin

💻 🔌

This project follows the all-contributors specification. Contributions of any kind are welcome!

redux-resource's People

Contributors

brycereynolds avatar chriskwan avatar gamtiq avatar guillaumejasmin avatar ianmstew avatar jamesplease avatar jayphelps avatar jcrben avatar jporry avatar karpov-dn avatar mattvague avatar mistakster avatar obedcorrales avatar smaifullerton-wk avatar whichsteveyp avatar yihangho avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

redux-resource's Issues

Babel updates

  • Upgrade to the latest version

  • Drop stage 3

    This is allowing me to use obj spread notation, which is just adding to the filesize of the project. I
    should just use `Object.assign()

  • Specify a browser version with env to reduce what gets transpiled

v1 Todo

This lists everything I need to do before the v1 release is ready.

Documentation

  • Fix the README.md in this directory
  • Update the README with some introductory information about the project
  • Fix CHANGELOG docs
  • Host doc site on gh-pages (this script may help)
  • Get .js.org domain (js-org/js.org#1290)
  • API
    • Example code for setMeta
    • Example code for upsertResources
  • Basic guides
    • Show how to write an action creator
    • Labels
    • Built-in actions
    • Plugins
  • Examples
    • Show how to use the built-in meta to do things
    • Modal form (saving it, closes modal)
    • Form with validation maybe?
    • Bootstrapping page data

Source code

  • Update the source to match the latest API guides
  • Add in single-resource behavior for the bulk action types, now that they're the only ones that there are
  • Add request label support for all reducers
  • Split out replace

Releasing/testing

  • Hook up Travis/add badge
  • Hook up Code Climate
    • add code coverage badge
  • Add more tests
  • Release a new version
  • Migrate one app over to the new version

Provide more integrations with other HTTP tools for action creators

The action creators extension uses a modified xhr library, which I think is the best compromise when it comes to making HTTP requests on the client. I don't expect to convince everyone of that, though, so there should be a way to use other tools with the action creators.

One way would be a hook to replace xhr. Another way would be one extension for each tool that we want to support (i.e.; superagent, axios, etc).

Drop usage of the word "extension"

I should stop calling things "extensions," which makes them sound like some formal Concept©. To reduce the number of Concepts©, I should just update that section of the docs to be called "Ecosystem," then refer to them as libraries that can be used with Resourceful Redux.

Update plugins to always accept the resourceName

Right now, adding a plugin looks like this:

combineReducers({
  books: resourceReducer('books', {
    plugins: [somePlugin('books'), anotherPlugin('books')]
  })
});

That's a lot of "books." If I update it so that the plugin is internally called with the resourceName instead, then the API would be simpler. However, the documentation gets a little more complicated.

Here's what the end-user API would look like:

combineReducers({
  books: resourceReducer('books', {
    plugins: [somePlugin, anotherPlugin]
  })
});

but now the documentation must say that a plugin is a function that accepts the resourceName, and returns a reducer. Maybe that's not so bad?

Update: I think it's better, actually. Get this:

A plugin is a function that gets called with the same arguments that you passed to resourceReducer. You return a reducer function from the plugin.

I think this is even simpler to describe than the current weird system, where resourceName gets merged into the options to be the third arg of the reducing fn.

Deleting resources, and deleting their meta?

Right now, deleting a resource also deletes its meta. Another option for this would be that the meta sticks around with deleteStatus: SUCCEEDED.

This would require plugins, like a select plugin, to manage unselecting the resource when a delete action type is fired.

Update "Core Concepts" requests section to mention labels

The Core Concepts requests section could be updated to mention tracking request status via a labeled request, too. There's probably a way to describe this without getting into the nitty gritty details of how labels work.

What I'm thinking is, I can start by talking about the importance of tracking requests. Then I can say that there are two ways to track requests:

  1. labeling a request
  2. on some resource metadata

Warn if no id is present

Resourceful Redux attempts to merge based off id, and when an id isn't present, simply concats into the resource list. This can lead to unintentional duplication.

Suggestion: Warn when no id is present on a resource if multiple are present.

CLEAR_RESOURCES_LABEL action type

Sometimes, you just want to wipe out the IDs of a label.

{
  type: actionTypes.CLEAR_RESOURCES_LABEL,
  resource: 'books',
  label: 'searchBar'
}

Extension deps aren't installed when main package is

The workaround (for now) is to install xhr and querystringify as deps directly in your app.

I should look to see how Lodash handles this.

Update: Lodash seems to convert all of the files to use local references on the modular build. That seems like quite a bit of work – I wonder if there's an easier way to make this work.

One idea would be to copy over those libs' package.jsons, and then seeing if require('resourceful-redux/extension') would look into the resourceful-redux/extensions/node_modules directory or not.

JSON API extension

It should have JSON API plugins, such as relationships, per-attr updates, meta, and compound documents, plus JSON API-specific action creators.

I'm thinking there will be two parts: a single plugin, and a new action creators lib.

The plugin handles actions like this:

{
  type: 'CREATE_RESOURCES_SUCCEEDED',
  resourceName: 'books',
  resources: [
    {
      id: 2,
      type: 'books',
      attributes: { ... },
      relationships: { ... },
      meta: { ... }
    }
  ],
  included: [{ ... }, { ... }, { ... }]
}

The following will happen:

  1. The meta for each resource will be put on that resource's metadata in the slice.
  2. The attributes will have their updates tracked per-attribute
  3. relationships will be tracked on the resource
  4. included resources will be properly added to their slice

The action creators would just format this stuff as needed. For document-level meta, I suppose I'd just place it on the label, but possibly not on the resource?

404 metadata?

A 404 response for a resource is pretty common. Right now, this lib makes no distinction between general-purpose errors, and not found errors. In other words, all you have to work with is a failed boolean, so any error message you display would just be: "There was an error fetching this resource."

It might make sense to include something to handle this in the library, rather than make a plugin. I'm thinking it'd work like this:

{
  notFound: Boolean
}

false by default, and true whenever a 404 error is returned. Applies to resources as well as labels.

Note that this would require enforcing a standard format for errors, since the reducer would need access to the status code of the response (right now, it doesn't look at those ever). This might be one reason to make it a plugin instead. It could just be a formal plugin (i.e.; resourceful-plugins on npm).

This also makes me think we need a getMeta method, which resolves a path to a meta location, so that you can access this meta more easily.

What do y'all think, @tbranyen @sprjr @marlonpp @ericvaladas ?

Fix code coverage...again

I fixed code coverage when I was running it from the root of this repo, but now that it's in the nested directory, it's not working 😓

Switch to Rollup

I might want to switch to Rollup for more flexibility on how I export this lib. Redux itself has a pretty good setup

Recipe: two types of CRUD requests

There are two categories of CRUD operations that I encounter, and they differ in how you use them in Resourceful.

  1. reads on page load. For these, you use treatNullAsPending: true. Also, you typically never need to reset their status back to NULL.

  2. reads when a user takes action. For these, you use treatNullAsPending: false, and you sometimes do reset the status back to NULL.

Delete removed IDs from every label

The contract of a label's ids is that they are always in the resources array. Therefore, successful deletes require looping every label to remove any IDs.

Add coverage badge to README

I'll need to learn CodeClimate's new way of submitting coverage. I feel like they make giant breaking changes to their API all of the time 😓

Also, since I have 3 coverage reports, I might need to set up 3 different CodeClimates? I'm not too sure about that. Or maybe I'll just report the resourceful-redux report? hmm.

Write custom _.get

_.get does way more than what's needed for this lib, and it comes in at ~6kb minified, which is way too big. I just need a simple while loop.

Action creators: ensure resources when deleting

Sometimes, delete requests do not return the resources that were deleted. This can lead to an undefined resources array being passed into the action.

I should update the action creators to use the resources array passed in if no body is returned.

+ if (body) {
    if (transformData) {
      resources = transformData(body, options);
    } else {
      resources = body;
    }
+ } else {
+   resources = options.resources;
+ }

Rename "NULL" status to "NIL"/“NONE”/“BLANK”/something else

That way, I can use none as the return value from getStatus (null works, but it's confusing, and may not work in some older browsers). Also "none" seems like it'd be read out loud as "no status," which seems more logical than "null status."

Unfortunately "DELETE_RESOURCES_NONE" doesn't sound so good.

Merge `options` in first in action creators

Currently:

dispatch({
  type: actionTypes[`${crudType}_RESOURCES_SUCCEEDED`],
  resources,
  ...options
});

needs to be:

dispatch({
  ...options,
  type: actionTypes[`${crudType}_RESOURCES_SUCCEEDED`],
  resources
});

otherwise, the passed-in resources will override the new resources.

RESET_RESOURCES action type

Resets a slice to the original state, removing all resources, meta, and labels.

Optionally, pass a label to scope the reset to that label.

Consider alternative getStatus API

getStatus([
  books.listMeta.readStatus,
  _.get(books.meta , '23.readStatus'),
  _.get(books.labelMeta, 'dashboard.status')
], true);

Pros:

  • simpler API. no grouping by types
  • no DSL
  • everything is treated equally – listMeta/meta isn't accessible via the DSL, while labels aren't

Cons:

  • Requires _.get for undefined things

One way to get around that con is to build in a mini _.get into the lib:

getStatus(state, [
  'books.listMeta.readStatus',
  'books.meta.23.readStatus',
  'books.labelMeta.dashboard.status'
], true);

Fix coverage report

The update to use Lerna somehow broke the coverage reporting. Maybe now is a good time to finally move off of isparta, which is completely abandoned haha

Add propTypes/actionCreators

I'm thinking I'll want to do dev of all of the core helpers in this repo. Lerna could help out with that. The first two official plugins will be prop types and action creators

resourceful-plugins

This will be a new lib that has some useful plugins for people to use alongside resourceful.

  • httpStatusCodes plugin (and possibly a plugin for unauthorized, too) #83
  • selection plugin (the example from the plugins guide)
  • reset plugin #17
  • httpNetworkErrors plugin
  • attributeUpdates plugin - per-attribute metadata tracking

Possibly others?

More tests

  • Add tests for action creators
  • Add tests for prop types
  • Add more tests for resourceful

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.