Scheintod
Scheintod

Reputation: 8105

AngularJS best practice REST / CRUD

What is the best practice of doing CRUD operations via REST with AngularJS?

Specially what is the Angular-Way here. By this I mean the way using the least code and the most default angular settings to achive this.

I know $resource and it's default operations. Where I'm not sure is how to implement/name the endpoints and which controllers to use.

For this example I would like to implement a simple user-management system which creates / updates /deletes / lists users. Since I'm implementing the Server-Endpoints by myself I'm completely free in doing it in the most angular friendly way.

What I like as answer is something like:

Server-Endpoints:

GET /service/users -> array of users
GET /service/user/new -> return an empty user with default values which has no id
POST /service/user/new -> store a new user and create an id. return the saved user.
POST /service/user/:ID -> save an existing user. Return the saved user
DELETE /service/user/:ID -> delete an existing user

Angular-Services:

.factory( 'User', [ '$resource', function( $resource ){

    return $resource( '/service/user/:userId', { userId: '@id' } )
    [...]

}])

Routing:

.when( '/users', {
    templateUrl: BASE + 'partials/user-list.html',
    controller: 'UserListCtrl' } )

.when( '/user/new', {
    templateUrl: BASE + 'partials/user-edit.html',
    controller: 'UserNewCtrl' } )

.when( '/user/:userId', {
    templateUrl: BASE + 'partials/user-edit.html',
    controller: 'UserEditCtrl' } )
...

Controllers:

UserListCtrl:

    $scope.data = User.get(...)

UserNewCtrl:

    $scope.user = User.get( { userId: "new" } )

...

Note that I'm not interessted in opinion what is the best (tm) way to do this but I'd like to know what is the Angular intended way (which I think should produce the least code because it can use the most default).

EDIT:

I'm looking for the whole picture. What I would love would be an answer like e.g.: "You can do this using online 3 Endpoints [...], 2 routes [...] and 2 controllers [...] if you do it this way using that defaults ..."

Upvotes: 21

Views: 20870

Answers (4)

Nate-
Nate-

Reputation: 147

My research into a similar quest has lead me to this project "angular-schema-form" https://github.com/Textalk/angular-schema-form.

For this approach... You make a JSON-Schema that describes your data. Then augment it with another little JSON-struct that describes a "form" (ie. view specific info that does not belong in the data schema) and it makes a UI (form) for you.

One cool advantage is that the Schema is also useful in validating the data (client and server side), so that is a bonus.

You have to figure out what events should fire off GET/POST/... back to your API. but that would be your preference, eg. Hit the API for every key stroke OR the classic [Submit] button POST back style OR something in between with a timed Auto Save.

To keep this idea going, I think that it is possible to use StrongLoop to make a quick API, which (again) uses your data's schema (augmented with some storage details) to define the API.

no <3 uses of that schema, see [http://json-schema.org/] which is central to this approach.

(read: no less than three :)

Upvotes: 3

Eran Witkon
Eran Witkon

Reputation: 4092

I think what you are looking for can be found in http://www.synthjs.com/

  • Easily create new RESTful API resources by just creating folders and naming functions a certain way.
  • Return data or promises from these functions and they'll be rendered to the client as JSON.
  • Throw an error, and it'll be logged. If running in dev mode, the error will also be returned to the client.
  • Preload angular model data on page load (saving an extra roundtrip).
  • Preload html view on page load (saving another extra roundtrip!)
  • A simplified project structure where front-end code (angular code, html, css, bower packages, etc) is in the 'front' folder and back-end code (node code and node packages) are in the 'back' folder.
  • A command-line tool for installing third party packages, using npm + bower, that auto-updates manifest files.
  • Auto compilation of assets on request for dev, and pre-compilation for prod (including minification and ngmin). Auto-restarts the server when changes are detected.
  • Support for various back-end and front-end templates to help get a new project going quickly.

Upvotes: -2

Beyers
Beyers

Reputation: 9108

There is no Angular prescribed way for what you are asking. It's up to you to determine the implementation detail.

Typically I only use two controllers and templates per resource:

  1. ListController
  2. FormController

The Form controller is used for both Edit and Create operations. Use the resolve option in your route definitions to pass in either User.get() or User.new() and a flag indicating if this is an edit or create operation. This flag can then be used inside your FormController to decide which save method to call. Here's a simple example:

.when( '/users', {
  templateUrl: BASE + 'partials/user-list.html',
  controller: 'UserListCtrl' } )
.when( '/user/new', {
  templateUrl: BASE + 'partials/user-form.html',
  resolve: {
    data: ['User', function(User) { return User.new(); }],
    operation: 'create'
  }
  controller: 'UserFormCtrl' } )
.when( '/user/:userId', {
  templateUrl: BASE + 'partials/user-form.html',
  resolve: {
    data: ['User', '$route', function(User, $route) { return User.get($route.current.params.userId); }],
    operation: 'edit'
  }
  controller: 'UserFormCtrl' } )

And your form controller:

app.controller('UserFormCtrl', ['$scope', 'data', 'operation', function($scope, data, operation){
  $scope.data = data;
  $scope.save = function() {
    if (operation === 'edit') {
      // Do you edit save stuff
    } else {
      // Do you create save stuff
    }
  }
}]);

You can go a step further and create a base list and form controller to move stuff like error handling, server-side validation notifications etc. In fact for the majority of CRUD operations you can even move the save logic to this base controller.

Upvotes: 21

Chandermani
Chandermani

Reputation: 42669

You maybe mixing things up. CRUD operations at API level are done using $resource and these may or may not map to UI. So using $resouce if you define resource as

var r = $resource('/users/:id',null,   {'update': { method:'PUT' }});
r.query()  //does GET on /users and gets all users
r.get({id:1}) // does GET on /users/1 and gets a specific user
r.save(userObject)  // does a POST to /users to save the user
r.update({ id:1 }, userObject) // Not defined by default but does PUT to /users/1 with user object.

As you see the API is resource full but is in no way linked to any UI view.

For view you can use the convention you have defined, but nothing specific is provided by Angular.

Upvotes: 1

Related Questions