A lightweight angular module that helps working with RESTful models. I was researching restangular and didn't like the fact that it was dependant on lodash and the dact that the models weren't configurable.
I liked ng-resources approach, but the implementation is horrible with nested objects.
So here is my solution.
- Removed dependency with ngResource, now this code duplicates $resource's behavior.
- Refactored the entire process, code is much more organized.
- Added support to define a type for a resource which will be accesible on the $$type flag.
- Added better promise behavior.
- Added 'constructor' flag which will allow wrapping of objects in an inner actions.
- Added 'iterator' function to manipulate wrapping of array results.
To use this module you must add the JS file to your HTML and add ngNestedResource
as a dependency to your app:
<!DOCTYPE html>
<html>
<head>
<title></title>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.5/angular.min.js"></script>
<script src="angular-nested-resource.js"></script>
</head>
<body ng-app="app">
...
angular.module("app", ["ngNestedResource"]);
Nested resource is using angular's own resource module as a scaffolding. So you can use the original resource configuration:
var organizations = nestedResource("/api/organizations/", {
getAll: {method: "GET", isArray: true},
create: {method: "POST"}
});
organizations.getAll();
// GET: "/api/organizations/"
organizations.create({name: "Google.com"});
// POST: "/api/organizations/", payload: "{name: 'Google.com'}"
// returns { id:1, name: "Google.com"}
Each method will behave like a regular resource object.
var organizations = nestedResource("/api/organizations/", {
getAll: {method: "GET", isArray: true},
create: {method: "POST"},
get: {
route: "@id/",
method: "GET"
}
});
organizations.get(1);
// GET: "/api/organizations/1/"
// returns { id:1, name: "Google.com"}
organizations.get({id: 1});
// GET: "/api/organizations/1/"
// returns { id:1, name: "Google.com"}
When specifying a route to an action you can add a wildcard (@) which will be replaced with the parameter supplied to the action, or a field name (@id) which will be replaced from the same field name in a supplied object.
var organizations = nestedResource("/api/organizations/", {
get: {
route: "@/",
method: "GET",
nested: {
update: { method: "PUT" },
delete: { method: "DELETE" },
workers: {
method: "GET",
route: "workers/",
isArray: true,
nested: {
update: {
method: "PUT",
route: "@/"
}
}
}
}
}
});
var organization = organizations.get(1);
// GET: "/api/organizations/1/"
// returns { id:1, name: "Google.com"}
organization.$update({name: "Bing.com"});
// PUT: "/api/organizations/1/", payload: "{name: 'Bing.com'}"
// returns { id:1, name: "Bing.com"}
var workers = organization.$workers();
// GET: "/api/organizations/1/workers/"
// returns [...]
workers.$update(264, {name: "Steve Ballmer"});
// PUT: "/api/organizations/1/workers/264/", payload: "{name: 'Steve Ballmer'}"
You can nest objects using the 'nested' property, and just follow the same pattern inside.
var Organizations = nestedResource("/api/organizations/", {
get: {
route: "@id/",
method: "GET",
construct: true,
nested: {
update: { method: "PUT" },
delete: { method: "DELETE" },
workers: {
method: "GET",
route: "workers/",
isArray: true,
nested: {
update: {
method: "PUT",
route: "@/"
}
}
}
}
}
});
var org = {
id: 294,
name: "Google Inc."
}
var orgResource = new Organizations(org);
orgResource.$delete()
// DELETE: "/api/organizations/294/"
A constructor action will use its nested actions to wrap a new object. When defining a constructor action define which property name should be used in the route (@id -> id: 294).
var Organizations = nestedResource("/api/organizations/", {
getAll: {method: "GET", isArray: true},
create: {method: "POST"},
get: {
route: "@/",
isArray: true,
method: "GET"
}
}, "organization");
Organizations.$$type;
// "organization"
var org = Organizations.get(1);
org[0].$$type;
// "organization"
var org = new Organizations();
org.$$type;
// "organization"
A type is added for every nestedResource object.
This module uses $q's promises:
var Organizations = nestedResource("/api/organizations/", {
getAll: {method: "GET", isArray: true},
create: {method: "POST"},
get: {
route: "@/",
isArray: true,
method: "GET"
}
});
Organizations.get(1, onSuccess, onError);
funciton onSuccess(org){
org.id; // 1;
}
function onError(e){
// Something went wrong...
}
A nested action has a maximum of 4 parameters:
Organizations.get(routeParam (string|integer), payloadObject, onSuccess, onError);
All parameters are optional.