Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AngularJS best practice REST / CRUD

Tags:

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

like image 665
Scheintod Avatar asked Apr 07 '14 08:04

Scheintod


2 Answers

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 :)

like image 43
Nate- Avatar answered Oct 05 '22 04:10

Nate-


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.

like image 156
Beyers Avatar answered Oct 05 '22 02:10

Beyers