Does anyone have any examples of PUT, POST, DELETE with AngularJs? I've been pulling my hair out with how complicated things seem to set up RestWS and I still can't get any CRUD to work with it. My server is set to to allow any domain as such

Header set Access-Control-Allow-Origin "*"
Header set Access-Control-Allow-Methods "GET, PUT, POST, OPTIONS"
Header set Access-Control-Allow-Credentials "true"
Header set Access-Control-Allow-Headers "Authorization, Origin, Content-Type, X-CSRF-Token"

Everytime I send a PUT or POST to the server I get this response from Drupal:

500 Service unavailable (with message)
Notice: Undefined offset: 1 in restws_basic_auth_init() (line 20 of /home/mcd.principlemcd.com/jalbert/public/drup/www/sites/all/modules/restws/restws_basic_auth/restws_basic_auth.module).

EntityMetadataWrapperException: Invalid data value given. Be sure it matches the required data type and format. in EntityDrupalWrapper->set() (line 736 of /home/mcd.principlemcd.com/jalbert/public/drup/www/sites/all/modules/entity/includes/entity.wrapper.inc).

I'm not sure why its returning 500 nor what the errors mean or how it helps me debug.

If anyone has successfully got angular to work with restws id love to hear about it. Any examples would be great!

Comments

kenianbei’s picture

Hi, just saw this, but thought I'd help out if someone else is looking for some basic code usage.

(function () {
  'use strict';

  angular.module('myApp', [
    'ngResource',
  ])
    .constant('basePath', Drupal.settings.basePath)
    .config(function($httpProvider) {

      // Add Drupal RestWS module specific configuration.
      $httpProvider.defaults.headers.common['X-CSRF-Token'] = Drupal.settings.myApp.restws_csrf_token;
      $httpProvider.defaults.headers.common['Content-Type'] = 'application/json';
    })
}());

(function () {
  'use strict';

  angular.module('myApp')
    .factory('EntityService', function ($resource, basePath) {
      return $resource(
        basePath + ':entity_type/:id',
        {},
        {
          update: {
            method: 'PUT',
            isArray: true
          },
          delete: {
            method: 'DELETE',
            isArray: true
          },
          save: {
            method: 'POST',
            responseType: 'json'
          }
        }
      );
    });
}());

angular.module('myApp')
  .controller('NodesCtrl', function($scope, EntityService) {

    $scope.init = function () {
      var query = {
        entity_type: 'node',
        full: 1
      };
      
      EntityService.get(query).$promise.then(function (data) {
        $scope.nodes = data.list;
      });

    };
  });

Media Crumb’s picture

Thanks so much! I actually ended up building out my angular app after weeks of trying to figure out the REST endpoints. One question I do have however is how you were able to get the delete method to work.

I currently get an error back from angular every time because RESTWS returns an empty array after a successful delete.

Error in resource configuration for action `delete`. Expected response to contain an object but got an array

The odd thing is my service is set up almost idendical to yours and array is set to true.

  .factory('NodeFactory', function($resource) {

    var base = 'URL';

      return $resource(base +'node/:id', {},
      {'query':  {method:'GET', isArray:false}},
      {'update': {method:'PUT'}},
      {'delete': {method:'DELETE', isArray:true}}
    );
  });

And controller is just passing in the id of the node to delete.

  .controller('AlltravelCtrl', function ($scope, allData, NodeFactory) {

    $scope.lists = allData.list;

    $scope.killtravel = function(idx) {
      var delNode = $scope.lists[idx];

      NodeFactory.delete({ id: delNode.nid }, function() {
          $scope.lists.splice(idx, 1);
      });
    };

  });
Media Crumb’s picture

It looks like you can't wrap the other methods in their down object. I don't know why i did that. Totally stupid. All fixed!

kenianbei’s picture

Glad to hear it. This is what I'm using:

EntityService.delete({entity_type:'node', id:nid}).$promise.then(function (data) {
// success
      }, function(error) {
// error
      });
Media Crumb’s picture

Hey @kenianbei,

How did you set up your login on the angular side?

kenianbei’s picture

No special login, just the regular Drupal login. I'm just using the restws_csrf_token, since all of my users must be logged in to view/use the app. It's included in the code I posted earlier.

Media Crumb’s picture

So I'm assuming you're on the same domain then. Wondering how to log in a user from an angular app on another domain. My app lives at www.app.com and the drupal site lives at www.drupalsite.com

kenianbei’s picture

yep... same domain. I haven't had to deal with this since all my apps are drupal modules. You might take a look at the auth module included with restws.

natemow’s picture

@media-crumb: Pretty sure you'd need to pass the XSRF-TOKEN header for http requests between domains. Fwiw, my Angular integration mod does have some XSRF-TOKEN cookie and header stuff if you want to borrow some code: https://www.drupal.org/project/ngapp

Cosy’s picture

Hey kenianbei/natemow,

how did you get hold of the CSRF token in the first place?
I get how to use it in my angular app, but when i post to restws/session/token with header set as
'Content-type': 'text/plain',
'Authorization': base64Login

... I get a preflight 403

btw, I used ngapp for a younger project and was well pleased with its simplicity but now trying to build headless & needed more complexity.

Full issue posted here: https://www.drupal.org/node/2698121

kenianbei’s picture

I'm replying tl;dr style, so maybe I'm not understanding your full issue, sorry in advance. The CSRF token sent from angular is pulled from Drupal JS settings:

$element['app'] = array(
  '#attached' => array(
    'js' => array(
      array(
        'data' => array(
          'myApp' => array(
            'restws_csrf_token' => drupal_get_token('restws'),
          ),
        ),
        'type' => 'setting',
      ),
    ),
  ),
);
kenianbei’s picture

Ahh, I see now you are fully headless... you are querying for the token. I have not done it this way before as we are still using Drupal for HTML rendering.

Cosy’s picture

Thanks for the swift reply Kenianbel

Yeh. As soon as PHP/Drupal is involved, i start to break down ! :)
So I decided my best course of action was to remove myself entirely from the scenario and code what I wanted pure JS.

I've tried ngApp and really enjoyed it but got confused at the crossover between php/js

If I can get drupal to output, then I can always sort it out on the client end !

Did some futher digging and it appears my issue my be as follows, or at least the first stage of it :

(https://www.drupal.org/node/1084144)

The GET /restws/session/token doesn't work for modern browsers. In a cross domain request an OPTIONS request will be fired first. (see https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#Ov...).

As the restws module returns a 403 on the url, the actual GET request is never fired.

Cosy’s picture

It appears my first wall was the OPTIONS request getting sent,

marcus_w circumvented that with his patch - hooraa,

As a result im now executing a POST request as detailed in my issue to session/token but still getting a 403 returned.