I am trying to build a hybrid mobile app with ionic (angular). For this app, I am making an oAuth call which is jQuery dependent so have both libraries loaded, as well as the script for the oAuth and my and my app.
<script src="lib/ionic/js/ionic.bundle.js"></script>
<script src="cordova.js"></script>
<script src="js/jquery-1.11.1.min.js"></script>
<script src="js/auth.js"></script>
<script src="js/app.js"></script>
The call to initiate the authentication is done in the ionic ready event in app.js as shown below:
$ionicPlatform.ready(function(){
oAuthProcess.authorize({
client_id: 'client',
client_secret: 'secret',
scope: 'scope',
redirect_uri: 'fake url'
}).done(function(data){
localStorage.setItem('accessToken', data.access_token);
localStorage.setItem('refreshToken', data.refresh_token);
var accessToken = localStorage.getItem("accessToken");
alert(accessToken);
}).fail(function(data){alert(data.error);});
});
The oAuthProcess function is in the auth.js file which looks like below. It opens the inAppBrowser to perform the authentication and should then close it returning the access token to the app to allow calling APIs:
var oAuthProcess = {
authorize: function(options) {
var deferred = $.Deferred();
var authUrl = 'some url' + $.param({
client_id: options.client_id,
redirect_uri: options.redirect_uri,
response_type: 'code',
scope: options.scope
});
//Open inAppBrowser with authUrl
var authWindow = window.open(authUrl, '_blank', 'location=no,toolbar=no');
authWindow.addEventListener('loadstart', function(e) {
var url = '' + e.url + '';
//Upon opening in
var code = url.match(/\?code=(.+)$/);
var error = url.match(/\?error=(.+)$/);
if (code != null || error != null) {
authWindow.close();
}
if (code) {
$http({
method: 'POST',
url: 'some url',
data: {code: code[1], client_id: options.client_id, client_secret: options.client_secret, redirect_uri: options.redirect_uri, grant_type: 'authorization_code'}
}).success(function(data) {
deferred.resolve(data);
}).error(function(data){
deferred.reject(response.responseJSON);
});
} else if (error) {
deferred.reject({
error: error[1]
});
}
});
return deferred.promise();
}
};
The app is able to load the inAppBrowser and create a token, however the following error is given which stops the token from getting back to the app after the inAppBrowser is closed.
2015-01-09 16:48:04.299 myApp[2146:483400] Error in Success callbackId: InAppBrowser85303841 : ReferenceError: Can't find variable: $http
Any help is resolving this or an alternative approach will be very much appreciated.
Thanks in advance.
I'll just type it here so I can show you the code example rather than comment...
Assuming the example you gave is your entire auth.js file, add that example PSL gave you, so the file now looks like this:
var $http = angular.injector(['ng']).get('$http');
var oAuthProcess = {
authorize: function(options) {
var deferred = $.Deferred();
var authUrl = 'some url' + $.param({
client_id: options.client_id,
redirect_uri: options.redirect_uri,
response_type: 'code',
scope: options.scope
});
//Open inAppBrowser with authUrl
var authWindow = window.open(authUrl, '_blank', 'location=no,toolbar=no');
authWindow.addEventListener('loadstart', function(e) {
var url = '' + e.url + '';
//Upon opening in
var code = url.match(/\?code=(.+)$/);
var error = url.match(/\?error=(.+)$/);
if (code != null || error != null) {
authWindow.close();
}
if (code) {
$http({
method: 'POST',
url: 'some url',
data: {code: code[1], client_id: options.client_id, client_secret: options.client_secret, redirect_uri: options.redirect_uri, grant_type: 'authorization_code'}
}).success(function(data) {
deferred.resolve(data);
}).error(function(data){
deferred.reject(response.responseJSON);
});
} else if (error) {
deferred.reject({
error: error[1]
});
}
});
return deferred.promise();
}
Related
I am using the following controller to import contacts from google account. I got the authorization code after login in gmail. But couldnt able to get the accesstoken by posting the authorization code to the url 'https://accounts.google.com/o/oauth2/token'. I didnt get any response.
angular.module('app',['ngRoute','angular-google-gapi'])
.config(['$routeProvider',function($routeProvider){
$routeProvider
.when('/log-in', {
template: '<button ng-click="logInCtrl.onLogInButtonClick()">Log In</button>',
controller: 'LogInController',
controllerAs: 'logInCtrl'
}).otherwise({
redirectTo:'/log-in'
});
}])
.controller('LogInController',function($scope,$http,GAuth,GApi){
var self = this;
var client_id = clientid;
var client_secret =clientsecretkey;
var redirect_uri ='http://localhost/myapp/oauth2callback';
var grant_type='authorization_code';
var apiKey= myapikey;
var scopes = 'https://www.googleapis.com/auth/userinfo.email https://www.google.com/m8/feeds/contacts/default/full';//to be able to reference to it in a callback, you could use $scope instead
$scope.email = '';
gapi.load('auth2', function() {//load in the auth2 api's, without it gapi.auth2 will be undefined
gapi.auth2.init(
{
client_id: clientid
}
);
var GoogleAuth = gapi.auth2.getAuthInstance();//get's a GoogleAuth instance with your client-id, needs to be called after gapi.auth2.init
self.onLogInButtonClick=function(){//add a function to the controller so ng-click can bind to it
GAuth.login().then(function(user){
$scope.email = user.email;
},function(response){
console.log(error);});
GoogleAuth.grantOfflineAccess({'redirect_uri': 'postmessage'}).then($scope.signInCallback);
};
});
$scope.signInCallback = function(result){
var code = result['code'];
var data = {
code : result['code'],
client_id: clientid,
client_secret:clientsecret,
redirect_uri:'http://localhost/myapp/oauth2callback',
grant_type:'authorization_code'
};
$http.post('https://accounts.google.com/o/oauth2/token',data,{headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}}).then(
function(response){
// success callback
console.log(response);
},
function(response){
// failure call back
console.log(1);
}
);
}
}).run(['GAuth', 'GApi', 'GData', '$rootScope','$http',function(GAuth, GApi, GData, $rootScope,$http) {
// Sends this header with any AJAX request
$http.defaults.headers.common['Access-Control-Allow-Origin'] = '*';
// Send this header only in post requests. Specifies you are sending a JSON object
$http.defaults.headers.post['dataType'] = 'json'
$rootScope.gdata = GData;
var CLIENT = clientid;
var BASE = 'https://myGoogleAppEngine.appspot.com/_ah/api';
GApi.load('http://localhost','v1',BASE);
// GApi.load('calendar','v3'); // for google api (https://developers.google.com/apis-explorer/)
GApi.load('contacts', 'v3');
GApi.load('plus','v1',BASE);
GAuth.setClient(CLIENT);
GAuth.setScope("https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/plus.login");
}]);
I would like to make a POST request to my node.js server (using express) from my angularjs app. I'm having troubles to send the correct {key:value}. Despite hours on researching the solution, I don't know how to write correctly the params to get them back on the server side . My results is : '{"key":"value"}': ''. Where am I wrong ?
Any help appreciated, thanks!
client.js
module.factory("Friends", function($resource) {
return $resource("https://myUrl/:id", {'id': '#id'} ,{
mes: {method: 'POST', headers: {'content-Type': 'application/x-www-form-urlencoded'} , isArray : false }
});
});
module.controller('communityCtrl', ['$scope','$rootScope', 'Friends', function($scope,$rootScope, Friends) {
var value = "aValue";
$scope.getData = function()
{
Friends.mes({id: 'jb'}, {key : 'value'} ).$promise.then(function(data){
console.log(data);
});
}
}]);
server.js
app.post('myUrl/jb', function(req, res) {
console.log("req.body : ", req.body);
res.json({code: 0, message: req.body.msg || ""});
});
output
req.body : { '{"key":"value"}': '' }
Have you tried $http?
Factory definition:
module
.factory('friendsFactory', ['$http', function ($http) {
return {
post: function (id, data) {
return $http.post('https://myUrl/' + id, data);
},
get: function () {
return $http.get('https://myUrl/');
}
};
}]);
From within your controller:
module
.controller('friendsController', ['friendsFactory', function (friendsFactory) {
friendsFactory.post(1, {id: 1})
.then(function (res) {
// success
console.log(res.data);
})
.catch(function (err) {
// there has been an error
console.error(err.data);
});
}]);
Within your node.js API endpoint, req.body will either be a string, or an object.
Note: if it is a string, ensure that you are using the body-parser middleware on express.
On the node server:
var express = require('express')
, bodyParser = require('body-parser')
app = express();
app.use(bodyParser.urlencoded({extended: true});
The body-parser middleware (amongst other things) takes the payload in req.body and replaces it a valid java object representation of that data.
TL;DR Your problem
The issue you have in your code is likely the following line:
Friends.mes({id: 'jb'}, {key : 'value'} ).$promise.then(function(data){
Try changing it to:
Friends.mes({id: 'jb', key: 'value'}).$promise.then(function(data){
Once you've done this, the req.body object on the server route will contain the following {id: 'jb', key: 'value'} instead of { '{"key":"value"}': '' }.
Example $resource application:
I've created a small example of using $resource to GET and POST to an API.
./public/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>title</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.7/angular.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.7/angular-resource.min.js"></script>
<script src="script.js"></script>
</head>
<body ng-app="app" ng-controller="friendController as vm">
<div>
{{vm.friend}}
</div>
<button ng-click="vm.getFriend()">Get User</button>
<button ng-show="vm.friend" ng-click="vm.messageFriend(vm.friend)">Message Friend</button>
</body>
</html>
./public/script.js
angular.module('app', ['ngResource'])
.factory('friendFactory', ['$resource', function ($resource) {
return $resource(
'/api/v1/friends/:id',
{id: '#_id'},
{
mes: {
method: 'POST',
headers: {'content-Type': 'application/x-www-form-urlencoded'},
isArray : false,
params: { message: true }
}
}
);
}])
.controller('friendController', ['friendFactory', function (friendFactory) {
var vm = this;
vm.friend = null;
vm.getFriend = _getFriend;
vm.messageFriend = _messageFriend;
function _getFriend() {
friendFactory.get({id: 1})
.$promise
.then(function (res) {
console.log(res);
vm.friend = res;
});
}
function _messageFriend(friend) {
/* method 1: call $mes on a friend object: */
// vm.friend.$mes({message: 'A message'})
// .then(function (friend) {
// vm.friend = friend;
// });
/* method 2: call mes on the resource: */
friendFactory.mes({_id: 1, message: 'A message'})
.$promise
.then(function (friend) {
vm.friend = friend;
});
}
}]);
index.js - the node.js server hosting the page and exposing a simple api
var express = require('express')
, path = require('path')
, app = express()
, bodyParser = require('body-parser');
app.use(bodyParser.urlencoded({ extended: true, limit: '50mb' }));
app.use(express.static(path.join(__dirname, './public')));
var friends = [
{ _id: 0, name: 'A' },
{ _id: 1, name: 'B' },
{ _id: 2, name: 'C' },
{ _id: 3, name: 'D' }
];
app.get('/api/v1/friends', function (req, res) {
return res.send(friends);
});
app.get('/api/v1/friends/:id', function (req, res) {
for (var i = 0; i < friends.length; i++) {
if (friends[i]._id == req.params.id) return res.send(friends[i]);
}
return res.status(404).send('Not found');
});
app.post('/api/v1/friends/:id', function (req, res) {
for (var i = 0; i < friends.length; i++) {
if (friends[i]._id == req.params.id) {
friends[i].message = req.query.message;
return res.send(friends[i]);
}
}
return res.status(404).send('Not found');
});
app.listen(8080, function () {
console.log('Server running');
});
This example has a simple API that allows you to
GET a list of friends
GET a single friend
POST a message to a friend (I am assuming this is what your mes stands for?). When posting - message will be available as a querystring parameter (req.query.message) or in the body (req.body.message).
In this example, it simple appends 'message' to the friend and returns the object.
Things to note (In friendController):
Calling $mes on an existing friend object returns a promise by default, so no need to chain .$promise.
Calling mes on the resource itself does not return a promise, so $promise is required.
I am implementing Woo Commerce Rest API in my Angular/Ionic project on Cordova Platform. While I am making $http request to get product list or any other data, I am getting error Message. Here is my Service code:
angular.module('services.serverRepo', [])
.service("serverRepo",
['$q','$http','errorHandler','$ionicLoading',function($q,$http,errorHandler,$ionicLoading){
var baseUrl="www.abc.com/wc-api/";
var self=this;
this.products=function(){
var deff=$q.defer();
$http({
method:"GET",
url:baseUrl+"v3/products",
headers: {
"Content-Type":"application/JSON",
"oauth_consumer_key":"gjdfjkbgbdhh645h6bh456b45hbhbgdfhgbdfhgbdfhgbhgbdhfghhfhf",
"consumer_secret":"cs_97d74bbf5e9052ee053a05cbb1a53eec19c0847c"
}
}).then(function(objS){
alert('Success :- '+JSON.stringify(objS));
},function(objE){
alert('error:- '+objE);
errorHandler.serverErrorhandler(objE);
deff.reject("server Error");
});
return deff.promise;
};
}])
.service('errorHandler',['$q',function($q){
this.serverErrorhandler=function(error){
alert("ERROR ::"+JSON.stringify(error));
console.log("ERROR ::"+JSON.stringify(error));
};
}
])
and in my controller.js file code is:
$scope.rentaldeptt = function(){
//$ionicHistory.clearCache();
serverRepo.products().then(function(objS){
},function(err){
});
}
I am calling $scope.rentaldeptt on a button click. In response I am getting error message
{"data":{"errors":[{"code":"woocommerce_api_authentication_error","message":"oauth_timestamp parameter is missing"}]},"status":404,"config":{"method":"GET","transformRequest":[null],"transformResponse":[null],"url":"www.abc.com/v3/products","headers":{"Accept":"application/json, text/plain, /"},"params":{"oauth_consumer_key":"gjdfjkbgbdhh645h6bh456b45hbhbgdfhgbdfhgbdfhgbhgbdhfghhfhf","consumer_secret":"cs_97d74bbf5e9052ee053a05cbb1a53eec19c0847c"}},"statusText":"Not Found"}
Any Idea what I am doing wrong?
Please try to following steps to resolve the isue,
Here, I have Created the service in angularjs to handle the calling of woocommerce api with the oauth,
angular.module('myapp.restservices', [])
.service("serverRepo",['$q','$http','errorHandler','$ionicLoading',function($q,$http,errorHandler,$ionicLoading){
var self=this;
//Request Url and method
var request = {
url: 'http://www.example.com/wc-api/v3/products',
method: 'GET'
};
//OAuth Protocol authentication parameters
var oauth = new OAuth({
consumer: {
//Consumer Public Key
public: 'ck_50xxxx',
//Consumer Secrete Key
secret: 'cs_b4xxxx'
},
//oauth1.0a protocol signature method
signature_method: 'HMAC-SHA1'
});
//Service Function to get products
this.products=function(){
$ionicLoading.show({
template: '<ion-spinner class="light"></ion-spinner>'
});
//OAuth Parameters to call woocommerce api
var oauth_data = {
oauth_consumer_key: oauth.consumer.public,
oauth_nonce: oauth.getNonce(),
oauth_signature_method: oauth.signature_method,
oauth_timestamp: oauth.getTimeStamp()
};
//Oauth signature
oauth_data.oauth_signature = oauthSignature.generate(request.method,request.url,oauth_data,oauth.consumer.secret );
console.log("Params : "+ JSON.stringify(oauth_data));
var deff=$q.defer();
$http({
method:"GET",
url:request.url,
headers: {
"Content-Type":"application/JSON",
},
params: oauth_data
}).then(function(objS){
$ionicLoading.hide();
alert('Success :- '+JSON.stringify(objS));
},function(objE){
$ionicLoading.hide();
alert('error:- '+JSON.stringify(objE));
errorHandler.serverErrorhandler(objE);
deff.reject("server Error");
});
return deff.promise;
};
}])
.service('errorHandler',['$q',function($q){
this.serverErrorhandler=function(error){
alert("ERROR ::"+JSON.stringify(error));
console.log("ERROR ::"+JSON.stringify(error));
};
}
])
Write controller to call the service function as like follows,
angular.module(myapp.categorycontrollers, [])
.controller('MainCtrl', function($scope,woocommerce) {
//Method to get all Products
$scope.getAllProducts = function(){
woocommerce.products().then(function(objS){
},function(err){
});
}
//calling to function
$scope.getAllProducts();
}
Hopes this will help you !
The following approach does not work:
angular.module('myApp.myModule').factory('MyResource', function($resource, $cookies) {
var token = $cookies.get('token');
var user = $cookies.get('username');
console.log ("Token: "+token+" User: "+user);
return $resource(
'http://my-rest-api/whatever/:id',
{
headers: {
'token': token,
'user': user
}
}
)});
Console shows the correct data, but they were not sent..
That's the part somewhere in the related Controller (excerpt):
var getEntryOne = MyResource.get({ id: 1 }, function() {
console.log("Result: "+getEntryOne);
});
I get the "Message: Token invalid", I see the request-http-headers in firebug, they were not setted.
You are setting headers for get request then it should be there in get option of $resource
$resource('http://my-rest-api/whatever/:id',{},{
get:{
method:"GET",
headers:{
'token': token,
'user': user
}
},
});
If you wanted to add this header information to each request, then you could have http inteceptor which will be add header information on each request.
app.service('MyResourceInterceptor', ['$cookies', function($cookies) {
var token = $cookies.get('token'),
user = $cookies.get('username'),
service = this;
service.request = function(config) {
config.headers['token'] = token;
config.headers['user'] = user;
return config;
};
}]);
app.config([ '$httpProvider', function($httpProvider) {
$httpProvider.interceptors.push('MyResourceInterceptor');
}]);
I am trying to do api call from my localhost to a different domain (https://xyz)
my solution:
<script> // ajax prefilter
$.ajaxPrefilter( function( options, originalOptions, jqXHR ) {
options.crossDomain ={
crossDomain: true
};
options.xhrFields = {
withCredentials: true
};
options.url = 'https://xyz' + options.url;
});
</script>
<script> // collection
var KCollection = Backbone.Collection.extend({
url: '/api/s/y/',
});
</script>
<script> // view
var DataAgesView = Backbone.View.extend({
render: function(){
var that = this;
mycollecion = new KCollection();
mycollecion.fetch({
dataType: 'jsonp',
success: function(){
console.log('success!');
},
error: function() { console.log('Uh Oh!'); },
})
}
});
</script>
This will send a GET request to "https://xyz/api/s/y"
and I can see the data came back to my browser by looking at the dev tool/network.
But there is this error: Uncaught SyntaxError: Unexpected token :
I am very new to web and backbone.js. I used jsonp to just be able to call cross domains, and I am open to use any other solutions for that (as long as I understand it).
Note that my server returns "json" and I can not change anything from server side.