This may be a silly question and I am very new to NativeScript. I have a sample project up. Trying to do a simple get request to a local api. This is a website setup on my local dev machine for:
http://test-api.dev/api/v1
I am trying to access an endpoint on my local API and it does not seem to return ANYTHING. But I can change the API endpoint to something that is not a local API and sometimes it return stuff.
The API is a Laravel/PHP api and I can confirm it is infact returning valid json, so I don't think the API is the problem. Here is my file.
var config = require("../../shared/config");
var fetchModule = require("fetch");
//var http = require("http");
var ObservableArray = require("data/observable-array").ObservableArray;
function GroceryListViewModel(items) {
var viewModel = new ObservableArray(items);
viewModel.load = function() {
// http.getJSON(config.apiUrl + "events").then(function(result) {
// console.log(JSON.stringify(result));
// }, function(error) {
// console.error(JSON.stringify(error));
// });
return fetch(config.apiUrl + "events", {
headers: {
//"Authorization": "Bearer " + config.token
"Content-Type": "application/json"
}
})
.then(handleErrors)
.then(function(response) {
console.log(response);
return response.json();
}).then(function(data) {
console.dump(data);
data.forEach(function(event) {
viewModel.push({
name: event.name,
id: event.id
});
});
});
};
viewModel.empty = function() {
while (viewModel.length) {
viewModel.pop();
}
};
return viewModel;
}
function handleErrors(response) {
if (!response.ok) {
console.log(JSON.stringify(response));
throw Error(response.statusText);
}
return response;
}
module.exports = GroceryListViewModel;
Please go easy on me, definitely seeking help on this though. Thank you all in advance.
return fetch(config.apiUrl + "events", { - so the fetch request is expecting the first argument to be a URL. So where config.apiUrl is defined is where the request goes. You can change this to point to the localhost instance of your server you are running.
So I have found the issue, thought I would post it. The problem wasn't my endpoints or my NS install. It is because Android Emulators out of the box cannot reference local sites running on your dev machine without some modification to the hosts settings on the Emulator. This process is explained here but I want to emphasize for anyone having the same issue.
Android emulators do not support access to local machine sites out of the box as explained here: https://developer.android.com/studio/run/emulator-networking.html
It needs to be setup through the device EVERYTIME unless someone has a solution to set this up only once, I would love to see it shared here.
There are serveral solutions outlining similar steps but I have had issues on every single one. Here is one that outlines the gist of the issue:
http://sadhanasiblog.blogspot.in/2012/07/local-environment-setup-for-android.html
Thanks for the help.
Related
I am trying to build a small web app which shows me my name, my schedule and my grades for school.
My school mostly uses the services from Microsoft, which gave me the idea to use their Azure API endpoints (for the schedules and grades) in my project.
I have access to create an app registration in the Azure-portal, so I did that and got it working to login with my student email. Also I tried to fetch the Microsoft Graph API and that works absolutely great.
However, when I try to fetch the Grades endpoint, it returns a 401 Unauthorized error. I'm guessing this has to do with the scopes, but I'm not sure. It turns out that my access token isn't valid for those API endpoints.
So my question is, how do I get an access token that IS valid for those API's? Or is it even possible? Keep in mind that they're separate App registrations in the Azure-portal, and that I can only edit my own one, not the one of my school.
Here is my JavaScript file, with some comments:
const config = {
auth: {
clientId: "my_client_id_is_here",
authority: "https://login.microsoftonline.com/my_tenant_id_is_here",
redirectUri: "localhost"
}
};
async function login() {
console.log("Started..")
var client = new Msal.UserAgentApplication(config);
var request = {
scopes: [ 'User.Read' ]
};
let loginResponse = await client.loginPopup(request);
console.dir(loginResponse);
let tokenResponse = await client.acquireTokenSilent(request);
console.dir(tokenResponse);
// User REQUEST - Here I fetch the Graph API for some profile information, which works fine and writes it to the HTML perfectly.
let req = await fetch("https://graph.microsoft.com/v1.0/me/", {
headers: {
"Authorization": "Bearer " + tokenResponse.accessToken
}
});
let json = await req.json();
console.log(json);
document.write("Logged in as " + json.displayName);
document.write("<br>" + json.mail);
document.write("<br>" + json.jobTitle + " " + json.officeLocation);
// School Grades REQUEST - this is the part where I'm trying to fetch my School Grades, but it's not working since it gives me a 401 error..
let gradesReq = await fetch("https://myschool.azurewebsites.net/API/Grades/GetGrades", {
"headers": {
"authorization": "Bearer " + tokenResponse.accessToken
}
});
try {
let gradesJson = await gradesReq.json();
console.log(gradesJson);
} catch (err) {
document.write("An error occured while trying to get the school grades..")
}
}```
You're correct in your thinking. The reason you're getting this error is because you're using the access token acquired for a different scope (User.Read) with your API.
Fix is rather simple.
What you have to do is protect your API with Azure AD first. You may find this link helpful in implementing this functionality: https://learn.microsoft.com/en-us/azure/active-directory/develop/scenario-protected-web-api-overview.
Once you have done that, all you need to do then is to acquire token for your API. In that case, your scopes code will be something like the following:
var request = {
scopes: [ 'api://<your-application-id>/.default' ]
};
Once you acquire the token for this scope and use it with your API, you should not get 401 exception that you're getting.
I'm writing an AWS Lambda in node.js 6.10 for a school project with Amazon's Alexa software, and I don't have much experience with Javascript and none with JSON. My school has a transportation API for finding if it is up at: https://prtstatus.wvu.edu/api/[TENDIGITTIMESTAMP]/?format=json
If I go there with the stamp, I get "{"status":"7","message":"The PRT is closed.","timestamp":"1494028926","stations":[],"bussesDispatched":"0","duration":[]}"
What I am trying to get is the message and relay it to something else (I've got that part covered). What I don't know is how to break up the JSON response from the URL or write a request in the first place. Can someone help me figure out what to write to use the "message" string in my project?
So far I have:
'getPRTStatus': function() {
var date = Math.round(new Date().getTime()/1000);
//this is the spot where I need help filling in
//var object = JSON.parse('http://prtstatus.wvu.edu/api/'+date+'/?format=json');
this.attributes.speechOutput = this.t(object.message);
this.attributes.repromptSpeech = this.t(object.message);
this.emit(':ask', this.attributes.speechOutput, this.attributes.repromptSpeech);
},
Thanks for your help!
Is it possible for you to post the JSON response here from the URL because that would help a lot to narrow down the issue.
Update
You need to make an http get request to the API endpoint. You won't get a JSON response with,
var url = "http://prtstatus.wvu.edu/api/"+date+"/?format=json"
You can use a package like https://www.npmjs.com/package/request Check out their documentation on how you can make it work.
Something like this,
var options = {
"method": "get",
"url": "http://prtstatus.wvu.edu/api/1501906657/?format=json",
}
request(options, function(err, response, body) {
if (err) {
console.log(err)
} else {
console.log(body);
}
Another Update
You can try something like,
var request = require('request'); //Import the NPM package
var object; //global variable to be used later on to store the response
Then in your function,
'getPRTStatus': function() {
var date = Math.round(new Date().getTime()/1000);
var options = {
'method' : 'get',
'url' : 'http://prtstatus.wvu.edu/api/' + date + '/?format=json'
};
request(options, function(err, response, body){
if(err) {
console.log(err);
}
else {
object = JSON.parse(body); //You got the response parsed & stored in the global variable named object
}
});
this.attributes.speechOutput = this.t(object.message);
this.attributes.repromptSpeech = this.t(object.message);
this.emit(':ask', this.attributes.speechOutput,
this.attributes.repromptSpeech);
}
Just updated my answer according to your question. Hope that helps. For any future API related issues, you should try Postman in chrome. I'll post a link on how to get started with that. You will also get the direct code of your API call in postman.
Link to postman app: https://chrome.google.com/webstore/detail/postman/fhbjgbiflinjbdggehcddcbncdddomop?utm_source=gmail
I'm trying to make work this very simple example of the Microsoft Cognitive Services in JavaScript but it's not working. I don't know why. Can some one help me or provide a working example?
I've tried to make the code work both in node and browser (of course with the right modifications to the code).
I'm getting this error in node:
"statusCode":404,"message":"Resource not found".
While if I run the code example [provided on the website][1] I get this error:
Access Denied (401): Access denied due to invalid subscription key
(which is weird cause I'm copying the precise key that has been provide to my in my account page).
const cognitiveServices = require('cognitive-services');
const computerVision = cognitiveServices.computerVision({
API_KEY: "myAPIkey"
});
const parameters = {
"language": "unk",
"detectOrientation": "true",
"content-type": "application/json"
};
const body = {
"url": "https://upload.wikimedia.org/wikipedia/commons/2/23/Space_Needle_2011-07-04.jpg"
};
computerVision.ocr({
parameters,
body
})
.then((response) => {
console.log('Got response', response);
})
.catch((err) => {
console.error('Encountered error making request:', err);
});
Please download version 0.2.0 and it should work.
I am trying to access an API using AngularJS. I have checked the API functionality with the following node code. This rules out that the fault lies with
var http = require("http");
url = 'http://www.asterank.com/api/kepler?query={"PER":{"$lt":1.02595675,"$gt":0.67125}}&limit=10';
var request = http.get(url, function (response) {
var buffer = ""
response.on("data", function (chunk) {
buffer += chunk;
});
response.on("end", function (err) {
console.log(buffer);
console.log("\n");
});
});
I run my angular app with node http-server, with the following arguments
"start": "http-server --cors -a localhost -p 8000 -c-1"
And my angular controller looks as follows
app.controller('Request', function($scope, $http){
// functional URL = http://www.w3schools.com/website/Customers_JSON.php
$scope.test = "functional";
$scope.get = function(){
$http.get('http://www.asterank.com/api/kepler?query={"PER":{"$lt":1.02595675,"$gt":0.67125}}&limit=10',{
params: {
headers: {
//'Access-Control-Allow-Origin': '*'
'Access-Control-Request-Headers' : 'access-control-allow-origin'
}
}
})
.success(function(result) {
console.log("Success", result);
$scope.result = result;
}).error(function() {
console.log("error");
});
// the above is sending a GET request rather than an OPTIONS request
};
});
The controller can parse the w3schools URL, but it consistently returns the CORS error when passed the asterank URL.
My app avails of other remedies suggested for CORS on this site (below).
Inspecting the GET requests through Firefox shows that the headers are not being added to the GET request. But beyond that I do not know how to remedy this. Help appreciated for someone learning their way through Angular.
I have tried using $http.jsonp(). The GET request executes successfully (over the network) but the angular method returns the .error() function.
var app = angular.module('sliderDemoApp', ['ngSlider', 'ngResource']);
.config(function($httpProvider) {
//Enable cross domain calls
$httpProvider.defaults.useXDomain = true;
delete $httpProvider.defaults.headers.common['X-Requested-With'];
});
You should understand one simple thing: even though those http modules look somewhat similar, they are totally different beasts in regards to CORS.
Actually, the node.js http.get() has nothing to do with CORS. It's your server that makes a request - in the same way as your browser does when you type this URL in its location bar and command to open it. The user agents are different, yes, but the process in general is the same: a client accesses a page lying on an external server.
Now note the difference with angular's $http.get(): a client opens a page that runs a script, and this script attempts to access a page lying on an external server. In other words, this request runs in the context of another page - lying within its own domain. And unless this domain is allowed by the external server to access it in the client code, it's just not possible - that's the point of CORS, after all.
There are different workarounds: JSONP - which basically means wrapping the response into a function call - is one possible way. But it has the same key point as, well, the other workarounds - it's the external server that should allow this form of communication. Otherwise your request for JSONP is just ignored: server sends back a regular JSON, which causes an error when trying to process it as a function call.
The bottom line: unless the external server's willing to cooperate on that matter, you won't be able to use its data in your client-side application - unless you pass this data via your server (which will act like a proxy).
Asterank now allows cross origin requests to their API. You don't need to worry about these workarounds posted above any more. A simple $http.get(http://www.asterank.com/api/kepler?query={"PER":{"$lt":1.02595675,"$gt":0.67125}}&limit=10')
will work now. No headers required.I emailed them about this issue last week and they responded and configured their server to allow all origin requests.
Exact email response from Asterank : "I just enabled CORS for Asterank (ie Access-Control-Allow-Origin *). Hope this helps!"
I was having a similar issue with CORS yesterday, I worked around it using a form, hopefully this helps.
.config(function($httpProvider){
delete $httpProvider.defaults.headers.common['X-Requested-With'];
$httpProvider.defaults.headers.common = {};
$httpProvider.defaults.headers.post = {};
$httpProvider.defaults.headers.put = {};
$httpProvider.defaults.headers.patch = {};
})
.controller('FormCtrl', function ($scope, $http) {
$scope.data = {
q: "test"//,
// z: "xxx"
};
$scope.submitForm = function () {
var filters = $scope.data;
var queryString ='';
for (i in filters){
queryString=queryString + i+"=" + filters[i] + "&";
}
$http.defaults.useXDomain = true;
var getData = {
method: 'GET',
url: 'https://YOUSEARCHDOMAIN/2013-01-01/search?' + queryString,
headers: {
'Content-Type': 'application/json; charset=utf-8'
}
};
console.log("posting data....");
$http(getData).success(function(data, status, headers, config) {
console.log(data);
}).error(function(data, status, headers, config) {
});
}
})
<div ng-controller="FormCtrl">
<form ng-submit="submitForm()">
First names: <input type="text" name="form.firstname">
Email Address: <input type="text" ng-model="form.emailaddress">
<button>bmyutton</button>
</form>
</div>
Seems to work with the url you posted above as well..
ObjectA: 0.017DEC: 50.2413KMAG: 10.961KOI: 72.01MSTAR: 1.03PER: 0.8374903RA: 19.04529ROW: 31RPLANET: 1.38RSTAR: 1T0: 64.57439TPLANET: 1903TSTAR: 5627UPER: 0.0000015UT0: 0.00026
I should also add that in chrome you need the CORS plugin. I didn't dig into the issue quite as indepth as I should for angular. I found a base html can get around these CORS restrictions, this is just a work around until I have more time to understand the issue.
After lots of looking around. The best local solution I found for this is the npm module CORS-anywhere. Used it to create AngularJS AWS Cloudsearch Demo.
We've spent a better part of yesterday trying to get this resolved. So as a last ditch effort i'm posting here.
Our setup is a Node.js / Express backend. With Socket.io on the same port as express.
app.io = io.listen(server);
app.io.set('origin', '*');
app.io.set('log level', '2');
app.io.enable('browser client minification');
app.io.set('transports', [
'websocket',
'flashsocket',
'htmlfile',
'xhr-polling',
'jsonp-polling'
]);
I've explicitly enabled all of the transports. We were hoping either jsonp or flash sockets would play nice on our least favorite browsers...
But, I guess there is a reason that they're our least favorite. ;-)
Client side we've got an Angularjs application with socket.io. Very loosely based on this tutorial
window.WEB_SOCKET_SWF_LOCATION = 'https://api.ourdomain.com/socket.io/static/flashsocket/WebSocketMain.swf';
var socket = io.connect('https://api.ourdomain.com', {
'reconnect' : true,
'reconnection delay' : 1500
});
We've tried adding the SWF location as seen here to get flashsockets working. It is serving up the policy and getting the files.. So no luck on that.
Anyways on ie7-9 when it attempts to connect via jsonp polling we get this error:
Object doesn't support this property or method
Contents of the jsonp message will be something like this:
io.j[1]("1::");
Occasionally with more content in it.
io.j seems to be being set as an array in the main socket.io.js file.
When I put this in the developer tools console, it throws the same error.
I've tried moving all the meta tags before the scripts like suggested here. That didn't change anything.
XHR-polling doesn't seem to work either. We've seen some posts about changing settings in ie.. But obviously we can't require our clients to go and request their IT department to change their browser settings just to visit our site. So we've ditched that method.
Also tried creating a blank page, and connecting.. That works. So what would be interfering?
Hopefully you guys have something?
We were unable to resolve this issue by simply making Socket.io work. I don't know if this is a Socket.io issue or if this is a combo of Angularjs and Socket.io.
We did however resolve this issue by adding our own fallback. In our Socket.io service we check for the existence of a feature present in ie9+ as well as webkit and firefox browsers.
var use_socketIO = true;
/*
I'd like to detect websocket, or jsonp.
But those transport methods themselves work.
Just not reliably enough to actually use
*/
if (typeof(window.atob) === 'undefined') {
console.log('browser appears to be < ie10.');
use_socketIO = false;
}
if (use_socketIO) {
var socket = io.connect('https://api.ourdomain.com', {
'reconnect' : true,
'reconnection delay' : 1500
});
}
// Fall back http method.
function httpReq(method, url, data) {
var defer = $q.defer();
$http({
method: method,
url: '//www.domain.com/api'+url,
data: data
}).success(function (data, status, headers, config) {
defer.resolve(data)
});
return defer.promise;
}
// Socket.io method.
function socketReq(method, url, data) {
var defer = $q.defer();
socket.emit(method, {url: url, data: data}, function (response) {
try {
var data = JSON.parse(response);
defer.resolve(data);
} catch (e) {
$log.error('Failed to parse JSON');
$log.info(response);
defer.reject(e);
}
});
return defer.promise;
}
// Main Request method
function request(method, url, data) {
if (use_socketIO) {
return socketReq(method, url, data || {});
} else {
return httpReq(method, url, data || {});
}
}
Then we simply just call request('get', '/url');
Server side we do some magic to build a req and res object if its Socket.io and then forward it to express to handle, otherwise express just handles it like normal.