constructor(platform: Platform, public http: Http) {
this.platform = platform;
this.headers = new Headers();
this.headers.append('Content-Type', 'application/x-www-form-urlencoded');
}
send(subject, body)
{
var body = "subject=" + subject + "&body=" + body;
let result = this.http.post('http://172.16.2.115:3004/message',
body,
{
headers: this.headers
});
console.log(body);
console.log(this._apiUrl);
return result;
}
I am trying to post a message to a Ruby on Rails web service using Ionic2 and Angular2 beta.
The web service works just fine, the issue is that the ionic app doest seem to be posting the message.
Does this look right?
You need to subscribe() otherwise no request will be sent
send(subject, body)
{
var body = "subject=" + subject + "&body=" + body;
let result = this.http.post('http://172.16.2.115:3004/message',
body,
{
headers: this.headers
})
.subscribe(res => {
this.comments = res.json();
console.log(body);
console.log(this._apiUrl);
// no effect here
// return result;
});
}
You need to move the code that processes the repsonse into subscribe() otherwise it will be executed before the response arrived.
You can't return the result, you can only return the observable for someone else to subscribe.
send(subject, body)
{
var body = "subject=" + subject + "&body=" + body;
return this.http.post('http://172.16.2.115:3004/message',
body,
{
headers: this.headers
});
.map(res => {
this.comments = res.json();
});
}
this.send.subscribe(res => {
console.log(body);
console.log(this._apiUrl);
});
You need to subscribe to the observable to make it execute since observables are lazy.
If you want to return the result to the caller, you can subscribe within the calling method. Don't forget that the request is executed asynchronously, so you will receive the response data in the callback specified in the subscribe method.
this.service.send(asunto, cuerpo).subscribe((result) => { // <------
// do something with the result
});
In this case, the send method can remain the same:
send(asunto, cuerpo) {
var body = "subject=" + asunto + "&body=" + cuerpo;
return this.http.post(this._apiUrl,
body, {
headers: this.headers
}).map(res => res.json());
}
If you're interested in how to organize your code to interact with an HTTP service, you could have a look at this question:
How to Consume Http Component efficiently in a service in angular 2 beta?
Moreover you could leverage the URLSearchParams class to buld your form content:
let content = new URLSearchParams();
content.set('subject', asunto);
content.set('body', cuerpo);
var inputPayload = content.toString();
Related
I implemented a twitter login authorizer and I put an API route as the callback.
The Lambda function evoked on that route is the following:
const loginTwitterCallback = async (e, context) => {
const fetch = (...args) =>
import("node-fetch").then(({ default: fetch }) => fetch(...args));
const state = e.queryStringParameters.state;
const code = e.queryStringParameters.code;
try {
await fetch(
"https://api.twitter.com/2/oauth2/token?code=" +
code +
"&grant_type=authorization_code&client_id=" +
process.env.TWITTER_CLIENT_ID +
"&code_verifier=jwqoijoiw&redirect_uri=" + MY REDIRECT URI,
{
method: "POST",
headers: {
"Content-type": "application/x-www-form-urlencoded",
},
}
)
.then((res) => {
return res.json();
})
.then(async (data) => {
const accessToken = data.access_token;
return {
headers: {
Location:
"http://127.0.0.1:3000/auth/social?type=twitter&access_token=" +
encodeURIComponent(accessToken),
},
body: null,
statusCode: 302,
};
});
} catch (err) {
console.log(err);
}
};
Basically the user should be re-routed to the front-end where another POST request will be made to the API which will make a request to the Twitter API with the Bearer token and update the database.
The point is, I'm not being redirected to the front-end in the first place and I don't understand how to fix it.
Thanks a lot in advance.
exports.handler = async (event) => {
// TODO implement
const https = require('https');
https.get('https://postman-echo.com/get?' +
'username =' +
'&password =' +
'&date=' +
'&cashSales=' + +
'&creditCardVisa=' +
'&creditCardMaster=' + +
'&creditCardAmex=' +
'&creditCardOthers=0',
res => {
//console.log(res.statusCode);
//console.log(res.headers);
let body = '';
res.on('data', data => {
body += data;
})
res.on('end', () => console.log(body));
})
const response = {
statusCode: 200,
body: JSON.stringify(https.get),
};
return response;
};
I can't seem to output the http request using this function, this can run in node.js but not in aws lambda, even after putting it in response function.
I have restructed the code a bit and wrapped it in a promise. You were not returning anything from the function. see here
const https = require("https");
exports.handler = event => {
return Promise((resolve, reject) => {
https.get(
"https://postman-echo.com/get?" +
"username =" +
"&password =" +
"&date=" +
"&cashSales=" +
+"&creditCardVisa=" +
"&creditCardMaster=" +
+"&creditCardAmex=" +
"&creditCardOthers=0",
resp => {
let data = "";
// A chunk of data has been recieved.
resp.on("data", chunk => {
data += chunk;
});
// The whole response has been received. Print out the result.
resp.on("end", () => {
resolve(data);
});
resp.on("error", error => {
reject(error);
});
}
);
});
};
you were close. But I found two issues.
Your lambda function was not waiting for the http get to finish.
You were returning the incorrect value https.get. you should return the response payload of the https.get call.
I have fixed the issues above.
const https = require("https");
exports.handler = async (event) => {
const httpResponse = await new Promise((resolve, reject) => {
https.get(
"https://postman-echo.com/get?" +
"username =" +
"&password =" +
"&date=" +
"&cashSales=" +
+"&creditCardVisa=" +
"&creditCardMaster=" +
+"&creditCardAmex=" +
"&creditCardOthers=0",
resp => {
let body = '';
// A chunk of data has been recieved.
resp.on("data", chunk => {
body += chunk;
});
// The whole response has been received. Print out the result.
resp.on("end", () => {
resolve(body);
});
resp.on("error", error => {
reject(error);
});
}
);
});
const response = {
statusCode: 200,
body: JSON.stringify(httpResponse),
};
return response;
};
hope this helps.
I think others have already pointed out the problem in your code. You are not waiting for the http get call to complete before returning. Read this article which explains the incorrect handling of Promises in AWS Lambda functions and the solutions for that.
If you use request-promise library (a much more popular one on npm) instead of https and with the new async/await syntax, your code will become very simple.
exports.handler = async function(event) {
const request = require('request-promise');
const res = await request.get('https://postman-echo.com/get', {
params: {
username: '',
password: '',
date: '',
cashSales: '',
creditCardVisa: '',
creditCardMaster: '',
creditCardAmex: '',
creditCardOthers: '0'
}
});
const response = {
statusCode: 200,
body: JSON.stringify(res)
};
return response;
};
I'm pretty new to sinon and proxyquire and I think I've read all the answers here on SO but I'm still not finding out what I need. Anyway, here's a sanitized version of my code.
const fetch = require('node-fetch');
async function deleteID(id, endpoint) {
try {
let url = `${endpoint}/delete/${id}`;
let res = await fetch(url, { method: 'DELETE' });
res = await res.json(); // <---- THIS FAILS WHEN fetch IS MOCKED
// do stuff with res
} catch (err) {
logger.error(`Error: ${JSON.stringify(err)}`);
}
}
It's pretty simple, it uses node-fetch to hit a url and then does stuff if the request succeeds or fails. Here's my test, lets setup the mocking for fetch:
const proxyquire = require('proxyquire').noCallThru();
const sinon = require('sinon');
beforeEach((done) => {
const validResponse = {
status: 200,
data: 'hello, world\n'
};
deleteProxy = proxyquire('./delete', {
'node-fetch': sinon.stub().returns(Promise.resolve(JSON.stringify(validResponse)))
});
});
So the fetch call now returns validResponse instead of hitting the server. And here's my test:
it.only('should delete', async () => {
try {
deleteProxy.deleteID('id', 'endpoint');
} catch (err) {
expect(err.message).to.have.lengthOf.at.least(0);
}
});
This fails since res is just an object with status and data, it is not a proper Response that has a Body etc... The rest of our code uses node-mocks-http but all of the tests using that module hit the url directly, not indirectly, via fetch, like I'm doing above.
How do I either create a mocked Response to fit into the above test or is there a different approach I should be using?
By looking at the code and my experience with sinon I would say as this is not an actual HTTP response so you have to mock json() as well.
In beforeEach method:
const body = {
status: 200,
data: 'hello, world\n'
};
var validResponse = { json: () => { return body } };
deleteProxy = proxyquire('./delete', {
'node-fetch': sinon.stub().returns(Promise.resolve(validResponse))
});
try with out JSON.stringify()
Let me know if it doesn't work.
I am using Angular 2 and Django 1.10.6. I create a post method. after send request from front-end, showing CSRF token missing or incorrect.
user.html
<form #f="ngForm" (ngSubmit)="createUser(f.value, f.valid,f)" novalidate>
....
</form>
Angular2 components
createUser(model: User, isValid: boolean, f: any) {
// check if model is valid
// if valid, call API to save customer
if (isValid) {
this.userCreateService.createUser(model).subscribe(
res => {
this.success = "User Create Success";
this.user = new User();
this.errorMsg=null
},
err => {
this.errorMsg = err;
this.success=null;
});
}
}
This is my Angular2 service
#Injectable()
export class UserCreateService {
constructor(private http: Http) { }
// private instance variable to hold base url
private userCreateUrl = '/api/user/users/';
// Add a new User
createUser(body: Object): Observable<User> {
let bodyString = JSON.stringify(body); // Stringify payload
let headers = new Headers({ 'Content-Type': 'application/json' }); // ... Set content type to JSON
let options = new RequestOptions({ headers: headers }); // Create a request option
return this.http.post(this.userCreateUrl, body, options) // ...using post request
.map(this.extractData) // ...and calling .json() on the response to return data
.catch(this.handleError); //...errors if any
}
After few moment of asking question,I have resolved my issue this way.
created method in angular 2 service.
getCookie(name) {
let value = "; " + document.cookie;
let parts = value.split("; " + name + "=");
if (parts.length == 2)
return parts.pop().split(";").shift();
}
And replace
let headers = new Headers({
'Content-Type': 'application/json'}); // .Set content type to JSON
to
let headers = new Headers({
'Content-Type': 'application/json',
'X-CSRFToken': this.getCookie('csrftoken')
}); // ... Set content type to JSON
in createUser() angular service method.
I'm using Ember-simple-auth and trying to return data from my custom authenticator back into the controller that did the authenticating.
in my authenticator/custom.js:
authenticate(identification, password) {
return new Ember.RSVP.Promise(function (resolve, reject) {
var loginURL = 'https://domain.com/login';
var authObj = Ember.Object.create({"identity":identification,"password":password});
var hash = authObj.getProperties('identity', 'password');
var stringHash = JSON.stringify(hash);
var xhr = new XMLHttpRequest();
xhr.open("post", loginURL);
xhr.onreadystatechange = handler;
xhr.responseType = 'json';
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.setRequestHeader('Format', 'JSON');
xhr.send(stringHash);
function handler() {
if (this.readyState === this.DONE) {
if (this.status === 200) {
console.log('response is: ',this.response); /// <-- returns good response data
resolve(this.response);
} else {
reject( 'failed with status: [' + this.status + ']');
}
}
}
and in my login controller:
authenticate() {
let { identification, password } = this.getProperties('identification', 'password');
var session = this.get('session');
session.authenticate('authenticator:custom', identification, password).then((reason) => {
console.log('failed login',reason);
});
}
},
But I'd really like to be able to handle the resolve function and get it's value payload from the authenticate promise.
If I change the .catch to a .then the response function is successfully called but always has an undefined value as its payload:
session.authenticate('authenticator:custom', identification, password).then(
(response) => {
console.log('response: ',response); //// <---- always 'undefined'
this.setUserWithData(response);
},
(reason) => {
this.set('Login failed: ',reason);
}
);
}
Even if I restructure the promise, rearrange how the function is called, the first function from an RSVP is successfully called, but has an undefined payload. The second function from an RSVP always has a correct payload.
I tried reversing the resolve/reject:
Ember.RSVP.Promise(function (resolve, reject){
to
Ember.RSVP.Promise(function (reject, resolve){
and the function successfully carries the response, but the simple-auth now believes it has failed its authorization.
I'd like to be able to pass the response payload into my controller. Or, if that can't be done, how can I inject data from the response into my session and ember-data store? It didn't seem like good practice to call and insert data into the store from within the authenticate function of the authenticator.
The session's authenticate method doesn't resolve with a value. Check the API docs: http://ember-simple-auth.com/api/classes/SessionService.html#method_authenticate
In order to deal with the response from the authentication route, I used the function sessionAuthenticated to deal with the returned data.
So, the authenticate function in authenticators/custom.js
authenticate(identification, password) {
return new Ember.RSVP.Promise(function (resolve, reject) {
var loginURL = 'https://domain.com/login';
var authObj = Ember.Object.create({"identity":identification,"password":password});
var hash = authObj.getProperties('identity', 'password');
var stringHash = JSON.stringify(hash);
var xhr = new XMLHttpRequest();
xhr.open("post", loginURL);
xhr.onreadystatechange = handler;
xhr.responseType = 'json';
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.setRequestHeader('Format', 'JSON');
xhr.send(stringHash);
function handler() {
if (this.readyState === this.DONE) {
if (this.status === 200) {
console.log('200 response: \r',this.response);
resolve(this.response);
} else {
console.log('failure response',this.response);
reject(this.response);
}
}
}
});
},
With the sessionAuthenticated() event taking place in routes/application.js:
sessionAuthenticated: function(){
var session = this.get('session');
var data = session.get('data');
var response = data.authenticated;
console.log('sessionAuthenticated()',response);
},
sessionInvalidated: function(){
console.log('sessionInvalidated()',response);
},
From the sessionAuthenticated function, the response variable contains all the information passed to it from authenticate(response) inside the authenticator.