In my PhoneGap application I need to call a service that uses Basic Auth.
The service works (see postman, the credentials are test:test):
I'm testing the service in Chrome and Android device then I'm getting:
My jQuery code:
function getData(){
var newDataRequest = $.ajax({
type: 'GET',
contentType: 'application/json',
url: 'myurl',
dataType: 'json',
/*username: 'test',
password: 'test',*/
beforeSend: function (xhr) { xhr.setRequestHeader ('Authorization', 'Basic dGVzdDp0ZXN0'); },
timeout: 30000 // timeout after 30 seconds
/*data: { user: "test", psw: "test" }*/
});
newDataRequest.done(function(msg)
{
alert("success");
});
newDataRequest.fail(function(jqXHR, textStatus)
{
alert("ERROR #" + jqXHR.status + " " + jqXHR.responseText);
});
}
How do make it works on Android, IOS and browser(for testing) ?
Related
Total postman noob. I have a script (well I don't I am trying to) to do the drudge tasks of authentication and authorization which takes 2 requests:
console.log("START");
var authenticationToken;
// Identity token
var authenticationTokenRequest = {
url: 'xxxx',
method: 'POST',
timeout: 0,
header: {
"Content-Type": "application/x-www-form-urlencoded",
"Authorization": "Basic xxxxx="
},
body: {
mode: 'urlencoded',
urlencoded: [
{key: "grant_type", value: "password"},
{key:"username", value: "xxxxx"},
{key:"password", value: "xxxx"},
]}
};
pm.sendRequest(authenticationTokenRequest, function (err, res) {
**console.log("01 send first request body");**
var responseJson = res.json();
console.log(responseJson);
pm.environment.set('ACCESS_TOKEN', responseJson['access_token']);
authenticationToken = responseJson['access_token'];
});
**console.log("Authentication token local var: " + authenticationToken);
console.log("Authorization token env var: " + pm.environment.get('ACCESS_TOKEN'));**
var authorizationTokenRequest = {
url: "xxxx",
method: "POST",
header: {
"Content-Type": "application/json",
"Authorization": "Bearer " + authenticationToken,
"Accept": "application/xxx+json"
},
body:{
tenantId: "xxx",
deviceId: "xxx"
}
}
pm.sendRequest(authorizationTokenRequest, function (err, res) {
**console.log("02 second request call");**
var responseJson = res.json();
pm.environment.set('ACCESS_TOKEN', responseJson['access_token']);
});
//
When I run this and look at the console, the console messages of the local vars show undefined. The console message for the second request shows in console before the first request. The second request depends on a value from the first.
What am I doing wrong? Thanks
Hello dear PBI REST API experts, I would appreciate any support on the following issue.
Trying to send data from MongoDB Atlas to Power BI Push Dataset through Rest API.
However I met the following issue, when I'm making more than 5 post http requests to PBI Rest API it says 'Error: connect: exceeded the limit of 5 sockets'.
I found the following link on this website, however seems like solution was not found there: Close socket connection in request.js
function postDataToPowerBi(result) {
...
collection.findOne({"_id": item._id}).then(itemDoc => {
postOne(itemDoc, access_token);
});
...
}
function postOne(itemDoc, access_token){
var postData = JSON.stringify({
"rows": [
{
"Name": itemDoc.Name,
"name.1": itemDoc.name
}
]
});
// request option
var options = {
host: 'api.powerbi.com' ,
port: 443,
method: 'POST',
path: '/v1.0/myorg/groups/' + group_id + '/datasets/' + dataset_id + '/tables/' + table_name + '/rows',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + access_token,
// 'Content-Length': postData.length,
'Connection': 'Close'
}
};
// request object
var req = https.request(options, function (res) {
var result = '';
res.on('data', function (chunk) {
result += chunk;
});
res.on('end', function () {
console.log(res.statusCode);
});
res.on('error', function (err) {
console.log(err);
});
});
// req error
req.on('error', function (err) {
console.log(err);
});
req.on('close', function () {
console.log("request closed");
});
//send request witht the postData form
req.write(postData);
req.end();
}
Found explanation for the question posted. Power BI has 5 max pending POST rows requests per dataset for push datasets. More information here: https://learn.microsoft.com/en-us/power-bi/developer/embedded/push-datasets-limitations Hence the only and much better approach is to post rows in bulk instead of line by line. Example below:
function postBulk(docs, access_token, firstRun){
if(firstRun){
deleteRows(access_token);
}
var postData = '{"rows": ' + JSON.stringify(docs) + '}';
// console.log(postData);
// request option
var options = {
host: 'api.powerbi.com' ,
port: 443,
method: 'POST',
path: '/v1.0/myorg/groups/' + group_id + '/datasets/' + dataset_id + '/tables/' + table_name + '/rows',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + access_token,
// 'Content-Length': postData.length,
// 'Connection': 'Close'
}
};
// request object
var req = https.request(options, function (res) {
var result = '';
res.on('data', function (chunk) {
result += chunk;
});
res.on('end', function () {
console.log("postBulk: " + res.statusMessage);
});
res.on('error', function (err) {
console.log("postBulk: " + err);
});
});
// req error
req.on('error', function (err) {
console.log("postBulk: " + err);
});
// req.on('close', function () {
// console.log("request closed");
// });
//send request witht the postData form
req.write(postData);
req.end();
}
I was trying GCP API Gateway using Firebase authentication. I can see my request has been processed from the logs and completed with response code 200. However, I am not getting the response back to my client. I am getting the response when I call the function directly (by passing the api gateway) both from client and curl. Am I missing something ?
API Config
swagger: "2.0"
info:
title: API Endpoints
description: API Endpoints
version: 1.0.1
schemes:
- https
produces:
- application/json
securityDefinitions:
firebase:
authorizationUrl: ""
flow: "implicit"
type: "oauth2"
x-google-issuer: "https://securetoken.google.com/my-project"
x-google-jwks_uri: "https://www.googleapis.com/service_accounts/v1/metadata/x509/securetoken#system.gserviceaccount.com"
x-google-audiences: "my-project"
paths:
/hello:
get:
summary: Test link
operationId: hello
x-google-backend:
address: https://us-central1-my-project.cloudfunctions.net/hello
security:
- firebase: []
responses:
"200":
description: A successful response
schema:
type: string
"403":
description: Failed to authenticate
Function
/**
* Responds to any HTTP request.
*
* #param {!express:Request} req HTTP request context.
* #param {!express:Response} res HTTP response context.
*/
exports.helloWorld = (req, res) => {
let message = req.query.message || req.body.message || 'Hello World!';
console.log("I am here inside the app")
res.status(200).send(message);
};
Logs from Cloud Function
Additional Logs
{ insertId: "8c13b49c-2752-4216-8188-d445f4724ef14850908905639612439#a1" jsonPayload: { api_key_state: "NOT CHECKED" api_method: "1.myapi.hello" api_name: "1.myapi" api_version: "1.0.1" client_ip: "999.999.999.999" http_method: "GET" http_response_code: 200 location: "us-central1" log_message: "1.myapi.hello is called" producer_project_id: "myproject" request_latency_in_ms: 161 request_size_in_bytes: 4020 response_size_in_bytes: 579 service_agent: "ESPv2/2.17.0" service_config_id: "myapi-config" timestamp: 1606313914.9804168 url: "/hello" } logName: "projects/myproject/logs/myapi%2Fendpoints_log" receiveTimestamp: "2020-11-25T14:18:36.521292489Z" resource: { labels: { location: "us-central1" method: "1.myapi.hello" project_id: "myproject" service: "myapi" version: "1.0.1" } type: "api" } severity: "INFO" timestamp: "2020-11-25T14:18:34.980416865Z" }
Client Side Code
The client side is written in Flutter - Dart and uses firebase authentication. I am not adding them here as it is pretty standard and in my case proprietary.
import 'package:flutter/material.dart';
import 'package:dio/dio.dart';
import 'package:example/.env.dart';
final _dio = Dio();
class GetAPIWidget extends StatefulWidget {
const GetAPIWidget({Key key}) : super(key: key);
#override
_GetAPIWidgetState createState() => _GetAPIWidgetState();
}
class _GetAPIWidgetState extends State<GetAPIWidget> {
String text = 'No response yet';
#override
void initState() {
// TODO: implement initState
getAPIResponse(endpoint: 'hello').then((value) {
setState(() {
text = value.toString();
});
}).catchError((onError) {
setState(() {
text = onError.toString();
});
});
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Text(text),
),
);
}
}
Future<Map<String, dynamic>> getAPIResponse({
/// Endpoint to our internal API Gateway. For this option to work url should be null
String endpoint,
Map<String, dynamic> queryParameters,
Map<String, dynamic> headers,
}) async {
try {
final Response response = await _dio.get<Map<String, dynamic>>(
'$api_gateway/$endpoint',
queryParameters: queryParameters ?? <String, dynamic>{},
options: Options(
// receiveTimeout: 20,
responseType: ResponseType.json,
contentType: Headers.jsonContentType,
headers: headers ??
<String, dynamic>{
Headers.contentTypeHeader: Headers.jsonContentType,
Headers.acceptHeader: Headers.jsonContentType,
'Authorization': 'Bearer ${idToken from firebase auth}',
}),
);
print(response.statusCode);
print(response.data);
if (response.statusCode == 200) {
return response.data;
} else {
throw response.statusMessage;
}
} on DioError catch (e) {
if (e.type == DioErrorType.CONNECT_TIMEOUT) {
throw ('Connection Timeout');
}
if (e.type == DioErrorType.RECEIVE_TIMEOUT) {
throw ('Session Timeout');
}
}
return <String, dynamic>{};
}
The client side returned {} which is the default return message. Neither of the prints showed up on client side logs.
It was not working because header was missing in the response.
res.setHeader('Content-Type', 'application/json');
My serverless.yml looks like this -
service: books-api-v1
provider:
name: aws
region: eu-west-1
role: arn:aws:iam::298945683355:role/lambda-vpc-role
runtime: nodejs8.10
iamRoleStatements:
- Effect: Allow
Action:
- "ec2:CreateNetworkInterface"
- "ec2:DescribeNetworkInterfaces"
- "ec2:DeleteNetworkInterface"
Resource: "*"
functions:
login:
handler: api/controllers/authController.authenticate
vpc: ${self:custom.vpc}
events:
- http:
path: /v1/users/login
method: post
cors: true
And the actual API function looks this -
'use strict';
var db = require('../../config/db'),
crypt = require('../../helper/crypt.js'),
jwt = require('jsonwebtoken');
exports.authenticate = function(event, context, callback) {
console.log(JSON.parse(event.body));
const data = IsJsonString(event.body) ? JSON.parse(event.body) : event.body;
let myEmailBuff = new Buffer(process.env.EMAIL_ENCRYPTION_KEY);
db.users.find({
where:{
username : crypt.encrypt(data.username)
}
}).then(function(user) {
try {
let res = {
statusCode: 200,
headers: {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Credentials': true,
},
body: JSON.stringify({
message:'ERROR!',
success: false
})
};
if (!user) {
res.body = JSON.stringify({
success: false,
message: 'Authentication failed. User not found.',
authFail:true
});
//res.status(200).json({ success: false, message: 'Authentication failed. User not found.',authFail:true, });
}else if (user) {
// check if password matches
if (crypt.decrypt(user.password) != data.password) {
res.body = JSON.stringify({
success: false,
message: 'Authentication failed. Wrong password.',
authFail:true
});
//res.status(200).json({ success: false, message: 'Authentication failed. Wrong password.',authFail:true, });
} else {
// if user is found and password is right
// create a token with only our given payload
// we don't want to pass in the entire user since that has the password
const payload = {
username: crypt.decrypt(user.username)
};
var token = jwt.sign(payload, process.env.JWT_SIGINING_KEY, {
algorithm: process.env.JWT_ALGORITHM,
expiresIn: 18000,
issuer: process.env.JWT_ISS
});
// return the information including token as JSON
// res.status(200).json({
// success: true,
// message: 'Enjoy your token!',
// token: token
// });
res.body = JSON.stringify({
success: true,
message: 'Enjoy your token!',
token: token
});
}
//callback(null, res);
}
console.log(res);
callback(null, res);
} catch (error) {
console.log('errorsssss: ');
console.log(error);
}
});
};
function IsJsonString(str) {
try {
JSON.parse(str);
} catch (e) {
return false;
}
return true;
}
Works very well on my serverless local, but when I try it on AWS Lambda function, then it gives "Internal server error" Message.
I have looked into my cloudwatch logs and the response looks correct to me. Here is the response that I am sending back to callback.
{
statusCode: 200,
headers: {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Credentials': true
},
body: '{"success":true,"message":"Enjoy your token!","token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6InNhaW1hLm5hc2lyckBnbWFpbC5jb20iLCJpYXQiOjE1NDUwNjE4OTYsImV4cCI6MTU0NTA3OTg5NiwiaXNzIjoiaWFtbm90YWdlZWsuY28udWsifQ.2HyA-wpmkrmbvrYlWOG41W-ezuLCNQnt0Tvrnsy2n3I"}'
}
Any help please?
In this case, it might because of the Api Gateway configurations. Does your api public? Because I have met such problems when the api is not public.
I'm new with ember and I wanted to know if it was possible to push some information that I've got back from my server into the store in ember.
I've tried this :
$.ajax({
url: host,
type: 'POST',
data: data,
accepts: 'application/json',
success: function(data) {
login.reset();
console.log("DEBUG: Login Succeed");
model: function() {
this.store.push() {
id: data.session.user.id,
username: data.session.user.username
}
}
login.transitionTo('home');
},
error: function() {
login.reset();
login.set('loginFailed', true);
console.log("DEBUG: Login Failed");
}
});
But obviously I'm wrong, and I don't really know how to do it :/
thanks for your help !!
EDIT:
Here is the new working code. I just forgot a small thing... such as the name of the model..
$.ajax({
url: host,
type: 'POST',
data: data,
accepts: 'application/json',
success: function(data) {
login.reset();
console.log("DEBUG: Login Succeed");
login.store.push('user', {
id: data.session.user.id,
username: data.session.user.username,
firstname: data.session.user.firstname,
lastname: data.session.user.lastname,
email: data.session.user.email,
domainid: data.session.user.domain,
role: data.session.user.role,
status: data.session.user.status
});
login.transitionTo('home');
},
error: function() {
login.reset();
login.set('loginFailed', true);
console.log("DEBUG: Login Failed");
}
});