I'm trying to make the following tutorial work which simulates a login from here : http://jasonwatmore.com/post/2014/05/26/AngularJS-Basic-HTTP-Authentication-Example.aspx
Here is the AngularJS code:
/* Dummy authentication for testing, uses $timeout to simulate api call
----------------------------------------------*/
$timeout(function(){
var response = { success: username === 'test' && password === 'test' };
if(!response.success) {
response.message = 'Username or password is incorrect';
}
callback(response);
}, 1000);
/* Use this for real authentication
----------------------------------------------*/
//$http.post('/api/authenticate', { username: username, password: password })
// .success(function (response) {
// callback(response);
// });
};
I now want to change it from dummy to the real authentification.
So far I have in the backend:
#CrossOrigin
#RequestMapping(value = "/login", method = RequestMethod.POST)
public String login(#RequestBody Login login) {
if (login.username.equals("test") && login.password.equals("test")) {
//return what?
} else {
//return what?
}
}
You return a normal Java object. The object should automatically be transferred in json format and you can read json format in javascript.
Example:
// java
String name;
int age;
// json format
{"name": "theName", "age": 32}t
// javascript
var myObj = {
name: "theName",
age: 32
};
So in your java you return you simply return your java object. If you look in your dev console of your browser in the network tab you should see the response in json format. Otherwise just $log.log("response", response); to check what object you get from the server.
Related
I'm trying to fetch data from Google search console (GSC) through http request.
I'm using google app Maker with javascript.
For my purpose I'm using a service account, all the scopes are already set up for the account.
I've copied the code provided by #Morfinismo.
/*********** SERVICE ACCOUNT CONFIGURATION USING THE OAUTH LIBRARY ***********
** All of the values are obtained from the .json file that is downloaded at
** the time of the service account creation
** Ref: https://developers.google.com/identity/protocols/OAuth2ServiceAccount
** Ref: https://github.com/googlesamples/apps-script-oauth2
*/
var accessData = {
"private_key" : "-----BEGIN PRIVATE KEY-----THE KEY-----END PRIVATE KEY-----\n",
"client_email" : "searchconsolebot#project-id-xxxxxxxxxxxxxxx.iam.gserviceaccount.com",
"user_email" : "user#domain.com" // Why do we need a user mail ?
};
var scopes = ["https://www.googleapis.com/auth/webmasters", "https://www.googleapis.com/auth/webmasters.readonly"]; //GSC api scope
scopes = scopes.join(" "); //join all scopes into a space separated string
function getOAuthService(user) {
console.log("je passe par getOAuthService");
user = user || accessData.user_email;
console.log("user: " + user);
return OAuth2.createService("GSC_Service_Account")
.setTokenUrl('https://accounts.google.com/o/oauth2/token')
.setPrivateKey(accessData.private_key)
.setIssuer(accessData.client_email)
.setSubject(user)
.setPropertyStore(PropertiesService.getScriptProperties())
.setCache(CacheService.getUserCache())
.setParam('access_type', 'offline')
.setScope(scopes);
}
function reset(user) {
var service = getOAuthService(user);
console.log("service: " + service);
service.reset();
return service;
}
function getToken(userEmail){
var totoken = reset(userEmail).getAccessToken();
console.log(totoken);
return reset(userEmail).getAccessToken();
}
function getGCSUrlData(urlGiven){
var token = getToken();
if(token){
var reqBody = {
startDate: "2019-01-01",
endDate: "2020-01-23"
};
var options = {
method : 'POST',
headers : {
Authorization : 'Bearer ' + token,
},
contentType: 'application/json',
payload: JSON.stringify(reqBody),
muteHttpExceptions: true,
};
var url = "https://www.googleapis.com/webmasters/v3/sites/" + encodeURIComponent(urlGiven) + "/searchAnalytics/query";
var response = UrlFetchApp.fetch(url, options);
console.log(response);
}
}
Using the OAuth library seems really great but it does return me an error
Error: Access not granted or expired. at getToken (Service_Account_Config:46)
Also I noticed that getToken() method requires a param but when calling it we don't give any param is it normal ?
And why do we need a user_email since we are using a service account ?
Which email should I enter for the user_email then ?
I would really appreciate some help about this issue and any advice to understand this kind of issue.
Thanks a lot,
Jacky
Integration with a service account is very easy when using the OAuth2 Library for AppsScript. Here are the steps:
1.) In a server side script add the following:
/*********** SERVICE ACCOUNT CONFIGURATION USING THE OAUTH LIBRARY ***********
** All of the values are obtained from the .json file that is downloaded at
** the time of the service account creation
** Ref: https://developers.google.com/identity/protocols/OAuth2ServiceAccount
** Ref: https://github.com/googlesamples/apps-script-oauth2
*/
var accessData= {
"private_key": "-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----\n",
"client_email": "service-account825#08012018.iam.gserviceaccount.com",
"user_email": "user#domain.com"
};
var scopes = ["https://www.googleapis.com/auth/webmasters", "https://www.googleapis.com/auth/webmasters.readonly"]; //drive api scope
scopes = scopes.join(" "); //join all scopes into a space separated string
function getOAuthService(user) {
user = user || accessData.user_email;
return OAuth2.createService("Service Account")
.setTokenUrl('https://accounts.google.com/o/oauth2/token')
.setPrivateKey(accessData.private_key)
.setIssuer(accessData.client_email)
.setSubject(user)
.setPropertyStore(PropertiesService.getScriptProperties())
.setCache(CacheService.getUserCache())
.setParam('access_type', 'offline')
.setScope(scopes);
}
function reset(user) {
var service = getOAuthService(user);
service.reset();
return service;
}
function getToken(userEmail){
return reset(userEmail).getAccessToken();
}
Then you can simplye call the service you need by doing the following:
function getGCSUrlData(urlGiven){
var token = getToken();
if(token){
var reqBody = {
startDate: "2020-01-01",
endDate: "2020-01-23"
};
var options = {
method : 'POST',
headers : {
Authorization : 'Bearer ' + token,
},
contentType: 'application/json',
payload: JSON.stringify(reqBody),
muteHttpExceptions: true,
};
var url = "https://www.googleapis.com/webmasters/v3/sites/" + encodeURIComponent(urlGiven) + "/searchAnalytics/query";
var response = UrlFetchApp.fetch(url, options);
console.log(response);
}
}
I'm setting up a Booking router in NodeJS, and I have many params in.
Now when I forgot params I return an error like :
500: Need more information
I wonder if it's possible to know which params are missing when I return the error code.
This is for a new API made in NodeJS
Here are the params that I want to retrieve from the front ( made in ReactJS )
let body = {
agentDutyCode: "STRING",
RatePlanCode: params.rateCode,
RoomCode: params.roomCode,
AmountAfterTax: params.amountTax,
Start: params.fromDate,
End: params.toDate,
CardCode: params.cardCode,
CardNumber: params.cardNumber,
ExpireDate: params.expireDate,
SeriesCode: params.cvv,
CardHolderName: params.nameCard,
ChainCode: params.chainCode,
HotelCode: params.hotelCode,
RoomQuantities: params.roomQuantities,
GuestQuantitie: params.numberGuest,
GuestPerRoom: params.guestPerRoom,
LastName: params.lastName,
FirstName: params.firstName,
PhoneNumber: params.phoneNumber,
email: params.email,
FVL_SUBUNIT_7: params.walletAddress
}
And this is my promise :
cdsJson.bookResource(req.body)
.then((response) => {
if (response !== null) {
res.response = {
...response
}
} if (response.hotel.length === 0) {
res.respStatus = 500
res.response = {
sendMsg: "Need more informations"
}
next('route')
}
return response
})
If the request succeeds I got a reservation ID otherwise I got :
Error 500: Need more information
Read the documentation or the source code.
Seriously. If the API response doesn't tell you in the error message, then there is no way to know what parameters it expects programmatically.
try it for a for ... in loop like this:
cdsJson.bookResource(req.body)
.then((response) => {
if (response !== null) {
res.response = {
...response
}
} if (response.hotel.length === 0) {
res.respStatus = 500
let errorStr = "Need more informations"
for(var key in req.body) { // Get all parameters that are not set
if(objects[key] == undefined)
errorStr += "\nParameter ["+key+"] is missing!"
}
res.response = {
sendMsg: errorStr
}
next('route')
}
return response
})
You're trying to do server side validation. In Node a good approach would be to define a JSON Schema for the expected parameters and then in your route handler validate the data sent in the request with a JSON Schema validator. This would help you work out whether a request was valid and help you generate error messages automatically. As a rule it's much better (i.e. simpler and more maintainable) to use tools that enable you to declaratively declare your validation (via a schema) than imperatively write code to manually validate objects.
JSON Schema spec https://json-schema.org/
A validator https://github.com/epoberezkin/ajv
My service code look like belowed :-
data.service('SmartLearnerService', function ($http) {
//Get Single Records
this.get = function (id) {
return $http.get("/api/Category/");
}
});
Here is my controller code for App.js:-
$scope.questionlist = SmartLearnerService.get();
$scope.questionlist.then(function (pl) {
var res = pl.data;
$scope.que = res.QuestionLabel;
},
function (errorPl) {
console.log('failure loading Employee', errorPl);
});
console.log($scope.questionlist);
Here is Controller code for web api controller :-
public class CategoryController : ApiController
{
CommonDb db = new CommonDb();
public JsonResult Get()
{
var Result = db.GetQuestionById().ToList();
string message = "No Data Found";
if (Result.Count() != 0)
{
return new System.Web.Mvc.JsonResult()
{
Data = Result,
JsonRequestBehavior = System.Web.Mvc.JsonRequestBehavior.AllowGet
};
}
else
{
return new System.Web.Mvc.JsonResult()
{
Data = message,
JsonRequestBehavior = System.Web.Mvc.JsonRequestBehavior.AllowGet
};
}
}
}
}
And here is div tag where i want to bind questions from json result using ng-repeat directive.
<div class="question" align="center">{{Questions.QuestionLabel}}</div>
i am facing problem while binding json array in controller's $scope.questionlist and i am successfully getting json result from web api controller.
Ok, if I had to guess (and that's exactly what I'm doing), you want something like this in your controller...
SmartLearnerService.get().success(function(questions) {
$scope.questionList = questions;
});
or, if you're not a fan of the add-on success / error callbacks
SmartLearnerService.get().then(function(response) {
$scope.questionList = response.data;
});
and in your template
<div ng-repeat="question in questionList">
<div class="question" align="center">{{question.QuestionLabel}}</div>
<!-- and so on -->
</div>
This is totally assuming your C# controller returns JSON that looks something like...
[{
"QuestionID": "1",
"QuestionLabel": "Why are mirrors often slightly curved (convex) ?",
"Image": "zibra-crossing.jpg",
"Correct": "two",
"Explaination": "Question one explaination is goes here"
}, {
...
}]
Can you try this?
SmartLearnerService
.get()
.success(function (data, status) {
if (status === 200) {
//your code to process data is here
}else{alert(status)}
})
.error(function (data, status) {
//TODO: Use nice alert.
alert('Server request failed with status ' + status + ' while getting area in the ' + $item.Name);
});
You will get the status code that you are receiving and then you can change the code accordingly.
The approach that I took in my case was to serialize using JsonConvert from NewtonSoft and then return the string of Json object instead of Json object itself to improve the speed.
I'm making an ASP.NET Web API web service, and an HTML/javascript page to test it. The issue I'm having is with passing a complex data parameter and having it come through properly in the web API controller.
I know there are numerous similar questions and I've read them and tried the solutions and haven't solved it. I have also read some JQuery documentation.
Here's my controller:
public class TitleEstimateController : ApiController
{
public IHttpActionResult GetTitleEstimate([FromUri] EstimateQuery query)
{
// All the values in "query" are null or zero
// Do some stuff with query if there were anything to do
}
}
public class EstimateQuery
{
// Various fields
}
The route mapping in WebApiConfig.cs:
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{query}"
);
And the javascript:
var uri = 'api/titleEstimate/';
var query = {
"username": $("#user").val(),
// other fields
};
$.getJSON(uri,query)
.done(function (data) {
$('#product').text("OK");
})
.fail(function (jqXHR, textStatus, err) {
$('#product').text('Error: ' + err);
});
Currently I'm getting a 404. I tried $.getJSON(uri + '/' + query) but that didn't work either. Before I was passing this object I was calling it successfully so I think the routing is generally OK. I tried a type converter, but that didn't help, still a 404. Does anyone see what I'm missing/doing wrong?
Answer
You are using the wrong uri. You need api/titleEstimate/getTitleEstimate. That explains and will resolve your 404.
Answer to Follow Up Question
Everything else you're doing almost works. After you resolve the 404, you'll find that you aren't receiving the value FromUri, and you'll have a follow up question. So, you need to change your route config to this:
config.Routes.MapHttpRoute(
name: "Default",
routeTemplate: "api/{controller}/{action}"
);
Then you'll not only resolve your 404 but also receive the FromUri value that you're sending as query string parameters.
Demo
Here is a fiddle for evidence, which is calling into this controller, which is hosted LIVE here. The only thing I changed in the working version are the uri to resolve the 404 and the route config to make sure you receive the FromUri value. That's all.
HTML
<label>Username:
<input id="user" />
</label>
<button id="submit">Submit</button>
<button id="submit-fail">Submit Fail</button>
<div id="product"></div>
JavaScript
This will succeed.
Note, we only need domain because we doing cross-site scripting here for the demo purpose.
var domain = "https://cors-webapi.azurewebsites.net";
$("#submit").click(function () {
var uri = domain + '/api/titleEstimate/getTitleEstimate';
var query = {
"username": $("#user").val(),
// other fields
};
$.getJSON(uri, query)
.done(function (data) {
$('#product').text(data);
})
.fail(function (jqXHR, textStatus, err) {
$('#product').text('Error: ' + err);
});
});
This will 404.
$("#submit-fail").click(function () {
var uri = domain + '/api/titleEstimate';
var query = {
"username": $("#user").val(),
// other fields
};
$.getJSON(uri, query)
.done(function (data) {
$('#product').text(data);
})
.fail(function (jqXHR, textStatus, err) {
$('#product').text('Error: ' + err);
});
});
Controller
public class TitleEstimateController : ApiController
{
public class EstimateQuery
{
public string username { get; set; }
}
public IHttpActionResult GetTitleEstimate([FromUri] EstimateQuery query)
{
// All the values in "query" are null or zero
// Do some stuff with query if there were anything to do
if(query != null && query.username != null)
{
return Ok(query.username);
}
else
{
return Ok("Add a username!");
}
}
}
You can read more details about WebApi routing here. From reading it you can probably come up with an alternative solution within your route config. There are also lots of terrific examples in this blog post.
First, I would try to use the attribute routing feature of web.api like this:
[RoutePrefix("api/titleestimate")]
public class TitleEstimateController : ApiController
{
[HttpGet]
public IHttpActionResult GetTitleEstimate([FromUri] EstimateQuery query)
{
// All the values in "query" are null or zero
// Do some stuff with query if there were anything to do
}
}
It would also be helpful to see the request in your dev tools. I disagree with Colin that you should make this a POST, because HTTP POST is supposed to be used to create new items. You are trying to get information so HTTP GET makes sense.
I think Web.Api assumes methods are GETs by default, but declarating it with the HttpGet attribute will for sure take care of that.
For complex objects, I usually send them in the message body rather than the URL.
Would you have any objection to an approach similar to the answer of this question?
How to pass json POST data to Web API method as object
It seems like the more straightforward/natural approach.
Something like (untested, but should be close):
[RoutePrefix("api/titleestimate")]
public class TitleEstimateController : ApiController
{
[HttpGet]
public IHttpActionResult GetTitleEstimate([FromBody] EstimateQuery query)
{
// All the values in "query" are null or zero
// Do some stuff with query if there were anything to do
}
}
public class EstimateQuery
{
public string QueryName{ get; set; }
public string Whatever{ get; set; }
}
$(function () {
var query = {QueryName:"My Query",Whatever:"Blah"};
$.ajax({
type: "GET",
data :JSON.stringify(query),
url: "api/titleEstimate",
contentType: "application/json"
})
.done(function (data) {
$('#product').text("OK");
})
.fail(function (jqXHR, textStatus, err) {
$('#product').text('Error: ' + err);
});
});
Code
MyClass = Backbone.Model.extend({
url: '/apiurl/'+sessionValue+'',
defaults: {
data1: '',
data2: 1
}
});
var myobj = new MyClass ();
var myobjvalue = {
data1: "myvalue"
};
myobj.save(myobjvalue , {
success: function (myobj , response) {
alert("success");
},
error : function (myobj , response) {
var data = JSON.stringify(response);
console.log(data);
}
})
in the above code, save function successfully calls the REST api. (200 OK). However even after that it enters in error block.
value printed in console
{"readyState":4,"responseText":"Success","status":200,"statusText":"OK"}
What should I be doing?
===================================
What worked
Instead of string, I had to return actual object as part of REST API. apprently, backbone expects class object along with HTTP status. so responseText contained full myobj.
What worked
Instead of string, I had to return actual object as part of REST API. apprently, backbone expects class object along with HTTP status. so responseText contained full myobj.