1

Angular 1.6 - JSONP throws EXCEPTION despite Response with status: 200 Ok for URL

Im trying to grab some data from a JSONP endpoint. It looks like the data is being returned in the response but Angular nonetheless throws an error.

var url = "https://careers.icims.com/jobs-api/"

var trustedUrl = $sce.trustAsResourceUrl(url);

$http.jsonp(trustedUrl, {jsonpCallbackParam: 'jobs'}).then(function(res){

    console.log(res); // this is never executed :.(

});

I am getting the following error: Uncaught ReferenceError: jobs is not defined at jobs-api?jobs=angular.callbacks._0:1 where jobs refers to my JSONP prefix

Yet the response returns the JSONP script: enter image description here

Why is this exception being thrown and how can it be cleared? I am on Angular 1.6.0

georgeawg
  • 48,608
  • 13
  • 72
  • 95
yevg
  • 1,846
  • 9
  • 34
  • 70
  • 1
    you don't have a function called `jobs` - that API always returns JSONP that calls a function called `jobs` – Jaromanda X Jun 26 '17 at 00:50
  • wouldnt `jobs` be implicitly defined within the scope of `then()`? Nonetheless, in what scope would I define `jobs`. I tried simply defining `function jobs(){}` above the jsonp call but no luck – yevg Jun 26 '17 at 01:21
  • 1
    jobs needs to be global – Jaromanda X Jun 26 '17 at 02:13

1 Answers1

2

Not a Legal JSONP API

The API at that URL is not a legal JSONP API.

It can be gotten with a dangerous service:

app.service("dangerousAPI", function($q) {
  this.get = get;
  
  function get(funcName, url) {
    var dataDefer = $q.defer();
  
    window[funcName] = function(x) {
      dataDefer.resolve(x);
    }

    var tag = document.createElement("script");
    tag.src = url;

    document.getElementsByTagName("head")[0].appendChild(tag);
    
    return dataDefer.promise;
  }
})

Use at your own risk.

The DEMO

angular.module("app",[])
.service("dangerousAPI", function($q) {
  this.get = get;
  
  function get(funcName, url) {
    var dataDefer = $q.defer();
  
    window[funcName] = function(x) {
      dataDefer.resolve(x);
    }

    var tag = document.createElement("script");
    tag.src = url;

    document.getElementsByTagName("head")[0].appendChild(tag);
    
    return dataDefer.promise;
  }
})

.run(function($rootScope, dangerousAPI) {
    var url = "https://careers.icims.com/jobs-api/";
    dangerousAPI.get('jobs',url).then(function(data) {
      $rootScope.data = data;
    })
})
<script src="//unpkg.com/angular/angular.js"></script>
  <body ng-app="app">
    <h1>Dangerous API DEMO</h1>
    <pre>{{data | json}}</pre>
  </body>
Community
  • 1
  • 1
georgeawg
  • 48,608
  • 13
  • 72
  • 95
  • This worked! Thank you! If you would indulge me, what about this API is not legal and dangerous? – yevg Jun 26 '17 at 04:25
  • Standard JSONP accepts a callback parameter to define the name of the padding function. This example code by-passes the browser [Same Origin Policy](https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy) and AngularJS security measures for URL sanitation and other mechanisms that make JSONP calls safer. For more information, see [*Is JSONP safe to use?*](https://stackoverflow.com/questions/613962/is-jsonp-safe-to-use). – georgeawg Jul 12 '17 at 07:27
  • See also [AngularJS $http Service - Security Consideration](https://docs.angularjs.org/api/ng/service/$http#security-considerations). – georgeawg Jul 12 '17 at 07:32
  • See also [AngularJS Developer Guide - Security](https://docs.angularjs.org/guide/security). And [AngularJS Developer Guide - Migrating to V1.6 $http JSONP](https://docs.angularjs.org/guide/migration#migrate1.5to1.6-ng-services-$http). – georgeawg Jul 12 '17 at 07:35