AngularJS best practice REST / CRUD

Scheintod picture Scheintod · Apr 7, 2014 · Viewed 20.7k times · Source

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 ..."

Answer

Beyers picture Beyers · Apr 7, 2014

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.