redux-flute
What does it do?
Flute is a front-end-only Object Data-store Mapping (ODM) implementation that lets you interact with RESTful APIs. By defining models on the front end and integrating closely with the popular state container, Redux, Flute offers a Ruby-on-Rails-esque, ActiveRecord-ey syntax. Think ActiveRecord for JavaScript. Flute is agnostic to back-end architecture. It's built for APIs which respond to GET/POST/POST/DELETE requests for resources identified by predefined keys, so Rails, Express, Sinatra, CouchDB UNAMEIT! Flute allows you to write syntax like this:
const userAddress = new Address
userAddress.address1 = "1100 Congress Ave"
userAddress.city = "Austin"
userAddress.state = "TX"
userAddress.save()
userAddress.id
userAddress.destroy()
Installation
npm install --save-dev redux-flute
Prerequisites
This library was made to solve problems in my current project stacks (insert buzz words: React/Redux/Webpack/ES6). The only real assumptions are:
- You are using NPM as a package manager
- You are using Redux
The nice-to-haves are:
I'm open to suggestion on making this library more widely supported.
Minimum Setup
In your app
import flute from "redux-flute";
const Story = flute.model("Story"),
const newStory = new Story;
newStory.save().then(savedRecord=>(this.setState({ ...savedRecord }));
Story.create({ title: "A working title", body: "Once upon a time..."})
.then(savedRecord=>(this.setState({ ...savedRecord }));
newStory.updateAttribute("title", "A working title")
newStory.updateAttributes({ title: "A working title", body: "Once upon a time..."})
newStory.destroy()
Story.all()
Story.find("583132c8edc3b79a853b8d69")
Defining Models
import flute, { Model } from "redux-flute";
class Story extends Model {
static schema = {
title: String,
body: String,
isActive: Boolean,
userId: String,
_timestamps: true
}
}
export default flute.model(Story);
In your reducers setup
import { combineReducers } from "redux"
import flute, { reducer as models } from "redux-flute"
flute.setAPI({ prefix: "/api" })
import "models"
export default combineReducers({
models,
});
In your store setup
import { createStore, applyMiddleware, compose } from "redux";
import reducer from "./reducers";
import { middleware as fluteMiddleware } from "redux-flute";
export default createStore(reducer, compose( applyMiddleware(fluteMiddleware )));
Minification
If you are running your build through something like Uglify, or part of a Webpack build, you'll need to exclude the class names of your models. Uglify supports excluding certain keywords from the minification/mangle process. Below is an example configuration for Webpack, in the plugins section of your webpack config.
new webpack.optimize.UglifyJsPlugin({
mangle: {
except: ["BankAccount", "CreditCard","User"]
}
})
Coming Soon!
- Model associations syntax a-la
userAddress.user
with declarations like:
const User = flute.model("User")
class Address extends Model {
static associations = [
{belongsTo: User}
]
}
- Validations, with the ability to exclude local validation like
userAddress.save({validate: false})
, with declarations a-la Mongoose like:
class Address extends Model {
static schema = {
address1: {
type: String,
required: [true, "A street address is required."]
}
zip: {
type: String,
length: {
min: 5,
message: "ZIP codes must be at least 5 numbers."
}
}
}
}
Also planned is the creation of a flute validations API, with the ability to include local and remote validations.
- Scopes and default scope syntax like
orders.completed
- Order and default ordering
cards.orderBy("price", "ASC")
- Custom schema types such as automatic conversions to U.S. dollar