i want to make a request to a page using request module in node js, but this have a error 500 .
This is part of the json response
{
"readable": false,
"domain": null,
"_maxListeners": 10,
"httpVersion": "1.1",
"complete": true,
"_pendingIndex": 0,
"url": "",
"method": null,
"statusCode": 500,
"_consuming": true,
"_dumped": false,
"httpVersionMajor": 1,
"httpVersionMinor": 1,
"upgrade": false,
"body": "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n<html><head>\n<title>500 Not Found</title>\n</head><body>\n<h1>Not Found</h1>\n<p>The requested\n site HTTP/1.1 is not presently available on\n this web cluster.\n This may be a temporary issue, so please try again in a few\n moments.</p>\n\n</body></html>\n",
"_readableState": {
"highWaterMark": 16384,
"length": 0,
"pipes": null,
"pipesCount": 0,
"flowing": false,
"ended": true,
"endEmitted": true,
"reading": false,
"calledRead": true,
"sync": false,
"needReadable": true,
"emittedReadable": false,
"readableListening": false,
"objectMode": false,
"defaultEncoding": "utf8",
"ranOut": false,
"awaitDrain": 0,
"readingMore": false,
"decoder": null,
"encoding": null,
"buffer": []
},
This is the code that i use for the request
app.get('/', function(req, res){
var options = {
url: 'http://www.metallicabyrequest.com/'
}
request(options, function (error, response, html) {
/*if (!error && response.statusCode == 200) {
res.json(html);
}*/
if(error){
res.json(error);
}else{
res.json(response)
}
});
});
Is there any way to get prevent the error 500? I read that if you change the headers, is probably that the request works, but i don't know how to do ...
That site require 'Host' in request header:
var options = {
url: 'http://www.metallicabyrequest.com/',
headers: {
'Host': 'www.metallicabyrequest.com'
}
}
Related
Axios does not return XML error message from S3 when uploading asset over the size limit.
Environment
Axios Version : 0.24.0
Node.js Version: v14.17.4
OS: Mac OS 12.3
S3 is returning this XML error message when I try to uplaod an asset over teh size limit
UPLOAD FAILED. Status Code: 400. Error message:
<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Error><Code>EntityTooLarge</Code><Message>Your proposed upload exceeds the maximum allowed size</Message><ProposedSize>52432788</ProposedSize><MaxSizeAllowed>52428800</MaxSizeAllowed><RequestId>N8RFYCS0K10GB4FF</RequestId><HostId>2OaG69rf19DMxItXx8J//rscZuSbxU8hJ/93du/a1zaFwAZa6jN2v1xCDebW4MRMgW3Kfuw0n10=</HostId></Error>
But Axios:
does not return it, just returns a generic error message: Request failed with status code 400"
and also breaks when trying to parse it.
This is the code I am running for the upload to S3:
let dataForm = new FormData();
dataForm.append('key', functionParams.uploadData.fields.key);
dataForm.append('bucket', functionParams.uploadData.fields.bucket);
dataForm.append('X-Amz-Algorithm', functionParams.uploadData.fields['X-Amz-Algorithm']);
dataForm.append('X-Amz-Credential', functionParams.uploadData.fields['X-Amz-Credential']);
dataForm.append('X-Amz-Date', functionParams.uploadData.fields['X-Amz-Date']);
dataForm.append('Policy', functionParams.uploadData.fields.Policy);
dataForm.append('X-Amz-Signature', functionParams.uploadData.fields['X-Amz-Signature']);
dataForm.append('file', fs.createReadStream(functionParams.assetFullPath),
{ knownLength: fs.statSync(functionParams.assetFullPath).size }
);
const uploadServiceURL = uploadData.url;
var config = {
method: 'POST',
url: uploadServiceURL,
headers: {
...dataForm.getHeaders(),
'content-length': dataForm.getLengthSync()
},
data: dataForm,
maxContentLength: Infinity,
maxBodyLength: Infinity,
transitional: {
forcedJSONParsing: false,
silentJSONParsing: false,
clarifyTimeoutError: true
}
};
axios(config)
.then(answer => {
resolve(answer);
})
.catch((error) => {
console.log(`Error:`)
console.log(error.toJSON())
reject(error)
})
This is the error I get from Axios:
{
"message": "Request failed with status code 400",
"name": "Error",
"stack": "Error: Request failed with status code 400\n at createError (/Users/vlad/modules/node_modules/axios/lib/core/createError.js:16:15)\n at settle (/Users/vlad/modules/axios/lib/core/settle.js:17:12)\n at IncomingMessage.handleStreamEnd (/Users/vlad/modules/node_modules/axios/lib/adapters/http.js:322:11)\n at IncomingMessage.emit (events.js:412:35)\n at endReadableNT (internal/streams/readable.js:1317:12)\n at processTicksAndRejections (internal/process/task_queues.js:82:21)",
"config": {
"transitional": {
"silentJSONParsing": false,
"forcedJSONParsing": false,
"clarifyTimeoutError": true
},
"transformRequest": [
null
],
"transformResponse": [
null
],
"timeout": 0,
"xsrfCookieName": "XSRF-TOKEN",
"xsrfHeaderName": "X-XSRF-TOKEN",
"maxContentLength": null,
"maxBodyLength": null,
"headers": {
"Accept": "application/json, text/plain, */*",
"Content-Type": "multipart/form-data; boundary=--------------------------913873697821807580301477",
"content-length": 114310407,
"User-Agent": "axios/0.26.0"
},
"method": "post",
"url": "https://s3.us-east-1.amazonaws.com/public-assets.bluescape.com",
"data": {
"_overheadLength": 938,
"_valueLength": 114309413,
"_valuesToMeasure": [],
"writable": false,
"readable": true,
"dataSize": 0,
"maxDataSize": 2097152,
"pauseStreams": true,
"_released": true,
"_streams": [],
"_currentStream": null,
"_insideLoop": false,
"_pendingNext": false,
"_boundary": "--------------------------913873697821807580301477",
"_events": {},
"_eventsCount": 1
},
"axios-retry": {
"retryCount": 0,
"lastRequestTime": 1648080399442
}
},
"status": 400
}
Any idea how can I get back the XML from S3 describing the issue?
I want to present it as the cause of the error.
I have tried using “transformResponse“ to transform the response from remote server, but I cannot make it work and accept a new error message:
var config = {
method: 'POST',
url: uploadServiceURL,
headers: {
...dataForm.getHeaders(),
'content-length': dataForm.getLengthSync()
},
data: dataForm,
maxContentLength: Infinity,
maxBodyLength: Infinity,
transformResponse: [(response, headers) => {
var resp = response;
// Note: A successful upload to S3 will return an empty response, status code 204
if (response) {
console.log(` ---> response for ${functionParams.assetFullPath} : ${JSON.stringify(response, null, ' ')} `)
var resp;
try {
// Detect an error when parsing the answer: XML or something else
resp = JSON.parse(response)
console.log(`==> answer parsed:`)
console.log(JSON.stringify(resp, null, ' '))
} catch (error) {
console.log(` ===> ERROR parsing response for ${functionParams.assetFullPath}: ${JSON.stringify(error, null, ' ')}`)
// Trying to construct an XML response
resp = {
"test message": "manually created error message"
}
}
}
console.log(`----> Response to send back: ${JSON.stringify(resp, null, ' ')}`)
return resp;
}, ...axios.defaults.transformRequest],
transitional: {
forcedJSONParsing: false,
silentJSONParsing: false,
clarifyTimeoutError: true
}
};
Axios cannot automatically parse XML. You can get the response as a string if you use the text response type.
config = {...config, responseType: 'text'}
Then, the response will be included in answer.data as a string. Of course, if you need to do anything smarter than just printing the response, you'll still need to parse it by using the DOMParser, for example.
I have a code like this
let item = { name: 'Roger' }
try {
return await collection.save(item)
}
catch (err) {
}
Now the collection I'm saving to has a Unique index on the field called name. Now during the exception handling the err object would look something like this
{
"isArangoError": true,
"response": {
"_readableState": {
"objectMode": false,
"highWaterMark": 16384,
"buffer": {
"head": null,
"tail": null,
"length": 0
},
"length": 0,
"pipes": [
],
"flowing": true,
"ended": true,
"endEmitted": true,
"reading": false,
"sync": true,
"needReadable": false,
"emittedReadable": false,
"readableListening": false,
"resumeScheduled": false,
"paused": false,
"errorEmitted": false,
"emitClose": true,
"autoDestroy": false,
"destroyed": false,
"defaultEncoding": "utf8",
"awaitDrainWriters": null,
"multiAwaitDrain": false,
"readingMore": true,
"decoder": null,
"encoding": null
},
"body": {
"code": 409,
"error": true,
"errorMessage": "unique constraint violated - in index name_is_unique of type persistent over 'name'; conflicting key: 15816187",
"errorNum": 1210
},
"arangojsHostId": 0
},
"statusCode": 409,
"errorNum": 1210,
"code": 409
}
While the error message is indeed helpful in conveying that name should be unique, wish there is an attribute/field in the error object to grab the conflicted field name.
How to get the field name other than regex parsing from the error message?
I have AWS redis which stores some data. I want to get the stored data using the Redis endpoint URL and nodejs. Below are my code and response which I am getting.
code:
let client = require('redis').createClient('redis://abcbsamv:6379', {no_ready_check: true});
res.send(client)
response from the above code:
{
"_events": {},
"_eventsCount": 1,
"address": "endpoints:6379",
"connection_options": {
"port": 6379,
"host": "endpoints",
"family": 4
},
"connection_id": 0,
"connected": false,
"ready": false,
"should_buffer": false,
"max_attempts": 0,
"command_queue": [],
"offline_queue": [],
"pipeline_queue": [],
"connect_timeout": 3600000,
"enable_offline_queue": true,
"retry_max_delay": null,
"retry_timer": null,
"retry_totaltime": 0,
"retry_delay": 200,
"retry_backoff": 1.7,
"attempts": 1,
"pub_sub_mode": 0,
"subscription_set": {},
"monitoring": false,
"message_buffers": false,
"closing": false,
"server_info": {},
"old_state": null,
"fire_strings": true,
"pipeline": false,
"sub_commands_left": 0,
"times_connected": 0,
"buffers": false,
"options": {
"port": "6379"
}
Please help me.
I found strange behaviour in Google Sheets API (is it issue?):
Firebase functions log doesn't show any error, but the values#batchGet function is ignoring ranges. It returns the entire dataRange of the sheet in first range.
batchGet "Try This API"
I edited my code based on code Github: Sheets API batchGet ranges parameter issue
sheets.spreadsheets.values.batchGet({
// your options
}, function (err, data, response) {
console.log(response.req.res.request.url);
});
Node.js code portion:
const sheets = google.sheets({ version: 'v4', access_token });
// set auth as a global default:
google.options({ auth: jwt });
const request = {
auth: jwt,
spreadsheetId: 'xxxxx', //<---------- "Project Checklist" and "Control" sheets
ranges: [
"'Project Checklist'!B:K",
"Control!A:F"
],
majorDimension: "ROWS",
dateTimeRenderOption: "FORMATTED_STRING",
valueRenderOption: "FORMATTED_VALUE"
}
This is wrapped inside a Promise...
sheets.spreadsheets.values.batchGet(request, (err, data, response) => {
console.log("inside: sheets.spreadsheets.values.batchGet() --------");
if (err) {
console.log('The Sheets API returned an error: ' + err);
//The API returned an error: Error: API key not valid. Please pass a valid API key.
reject(err);
};
try {
console.log("response:-------------------------------");
console.log(JSON.stringify(response));
console.log("data.valueRanges:-------------------------------");
console.log(data.valueRanges);
resolve(JSON.stringify(data.valueRanges));
} catch (err) {
console.log("Error processing Sheets API response: " + err);
reject(err);
}
})
Firebase log:
Function execution took 3822 ms, finished with status code: 200
undefined
data.valueRanges:-------------------------------
undefined
response:-------------------------------
getJwt() --------------- OK
index.js
'use strict'
const functions = require('firebase-functions');
const { google } = require('googleapis');
var serviceAccount = require("./credentials/admin-service-account-key.json");
function getJwt() {
// Define the required scopes.
var scopes = [
'https://www.googleapis.com/auth/spreadsheets'
];
return new google.auth.JWT(
serviceAccount.client_email,
null,
serviceAccount.private_key,
scopes
);
}
function getSpreadsheetData(jwt) {
return new Promise((resolve, reject) => {
jwt.authorize((error, access_token) => {
if (error) {
console.log('Error in jwt.authorize: ' + error);
reject(error);
} else {
// access_token ready to use to fetch data and return to client
const sheets = google.sheets({ version: 'v4', access_token });
// set auth as a global default:
google.options({ auth: jwt }); //<----------------------
const request = {
auth: jwt,
spreadsheetId: 'xxxxxxxxxxxxxxxxxxxx', //<---------- Project Checklist / Control
range: 'Control!A:F', //
}
sheets.spreadsheets.values.get(request, (err, response) => {
console.log("inside: sheets.spreadsheets.values.get() -------------------------------");
if (err) {
console.log('The Sheets API returned an error: ' + err);
//The API returned an error: Error: API key not valid. Please pass a valid API key.
reject(err);
};
try {
var numRows = response.data.values ? response.data.values.length : 0;
console.log('%d rows retrieved.', numRows);
console.log("response.data:-------------------------------");
console.log(response.data.values);
resolve(response.data.values);
} catch (err) {
console.log("Error processing Sheets API response: " + err);
reject(err);
}
})
}
})
})
}
function getSheetBatchData(jwt) {
return new Promise((resolve, reject) => {
jwt.authorize((error, access_token) => {
if (error) {
console.log('Error in jwt.authorize: ' + error);
reject(error);
} else {
// access_token ready to use to fetch data and return to client
const sheets = google.sheets({ version: 'v4', access_token });
// set auth as a global default:
google.options({ auth: jwt }); //<----------------------
const request = {
auth: jwt,
spreadsheetId: 'xxxxxxxxxxxxxxxxxxxxxxxxxx', //<---------- Project Checklist / Control
ranges: [
"Project Checklist!B:K",
"Control!A:F"
],
majorDimension: "ROWS",
dateTimeRenderOption: "FORMATTED_STRING",
valueRenderOption: "FORMATTED_VALUE"
}
/*
sheets.spreadsheets.values.batchGet({
// your options
}, function (err, data, response) {
console.log(response.req.res.request.url);
});
*/
//https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets.values/batchGet
sheets.spreadsheets.values.batchGet(request, (err, data, response) => {
if (err) {
console.log('The Sheets API returned an error: ' + err);
//The API returned an error: Error: API key not valid. Please pass a valid API key.
reject(err);
};
try {
/*
* Returns: Array: data.valueRanges =
* [
* "range": "....",
* "values": []
* ]
*/
console.log("response:-------------------------------");
console.log(JSON.stringify(response));
console.log("data.valueRanges:-------------------------------");
console.log(data.valueRanges);
resolve(JSON.stringify(data.valueRanges));
} catch (err) {
console.log("Error processing Sheets API response: " + err);
reject(err);
}
});
}
})
})
}
/* Working */
exports.getControlSheetData = functions.https.onCall((data, context) => {
console.log("getData()---------------------------");
if (!context.auth) {
throw new functions.https.HttpsError('failed-precondition', 'The function must be called ' + 'while authenticated.');
} else {
console.log("context.auth ------------ OK");
const uid = context.auth.uid;
console.log(uid);
var jwt = getJwt();
console.log("getJwt() --------------- OK");
return getSpreadsheetData(jwt); //<------------ Requested Spreadsheet's Data
}
})
/* Error */
exports.getBatchData = functions.https.onCall((data, context) => {
console.log("getBatchData()---------------------------");
if (!context.auth) {
throw new functions.https.HttpsError('failed-precondition', 'The function must be called ' + 'while authenticated.');
} else {
console.log("context.auth ------------ OK");
const uid = context.auth.uid;
console.log(uid);
var jwt = getJwt();
console.log("getJwt() --------------- OK");
return getSheetBatchData(jwt); //<------------ Requested Spreadsheet's Data
}
})
New test: index.js
'use strict'
const functions = require('firebase-functions');
const { google } = require('googleapis');
var serviceAccount = require("./credentials/admin-service-account-key.json");
function getJwt() {
// Define the required scopes.
var scopes = [
'https://www.googleapis.com/auth/spreadsheets'
];
return new google.auth.JWT(
serviceAccount.client_email,
null,
serviceAccount.private_key,
scopes
);
}
function getDataTest2(jwt) {
jwt.authorize().then(access_token => {
// access_token ready to use to fetch data and return to client
const sheets = google.sheets({ version: 'v4', access_token });
// set auth as a global default:
google.options({ auth: jwt }); //<----------------------
const request = {
auth: jwt,
spreadsheetId: 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
ranges: [
"Project Checklist!B:K",
"Control!A:F"
],
majorDimension: "ROWS",
dateTimeRenderOption: "FORMATTED_STRING",
valueRenderOption: "FORMATTED_VALUE"
}
function callback(data,resp) {
try {
console.log("inside callback-----------");
console.log("returned data:--------------")
console.log(data);
console.log("returned resp:--------------")
console.log(resp);
console.log("expected data.valueRanges------------------------")
console.log(data.valueRanges); //<--------- expected data.valueRanges
return JSON.stringify(data.valueRanges);
} catch(err) {
console.log('The Sheets API returned an error: ' + err);
//The API returned an error: Error: API key not valid. Please pass a valid API key.
return(err);
}
}
sheets.spreadsheets.values.batchGet(request, callback);
}).catch(error => {
console.log('Error in jwt.authorize: ' + error);
reject(error);
})
}
exports.getBatchData = functions.https.onCall((data, context) => {
console.log("getBatchData()---------------------------");
if (!context.auth) {
throw new functions.https.HttpsError('failed-precondition', 'The function must be called ' + 'while authenticated.');
} else {
console.log("context.auth ------------ OK");
const uid = context.auth.uid;
console.log(uid);
var jwt = getJwt();
console.log("getJwt() --------------- OK");
//return getSheetBatchData(jwt); //<------------ Requested Spreadsheet's Data
return getDataTest2(jwt)
}
})
Firebase log:
getJwt()--------------- OK
Function execution took 965 ms, finished with status code: 200
inside callback-----------
returned data: --------------
null
returned resp: --------------
{
status: 200, statusText: 'OK', headers: { 'content-type': 'application/json; charset=UTF-8', vary: 'Origin, X-Origin, Referer', date: 'Tue, 18 Sep 2018 02:28:15 GMT', server: 'ESF', 'cache-control': 'private', 'x-xss-protection': '1; mode=block', 'x-frame-options': 'SAMEORIGIN', 'alt-svc': 'quic=":443"; ma=2592000; v="44,43,39,35"', connection: 'close', 'transfer-encoding': 'chunked' }, config: { adapter: [Function: httpAdapter], transformRequest: { '0': [Function: transformRequest] }, transformResponse: { '0': [Function: transformResponse] }, timeout: 0, xsrfCookieName: 'XSRF-TOKEN', xsrfHeaderName: 'X-XSRF-TOKEN', maxContentLength: 2147483648, validateStatus: [Function], headers: { Accept: 'application/json, text/plain, */*', 'Accept-Encoding': 'gzip', 'User-Agent': 'google-api-nodejs-client/0.2.1 (gzip)', Authorization: 'Bearer ya29.c.ElocBg_A_xxxxxxxxxxxxxxxxxxxx' }, method: 'get', access_token: { access_token: 'ya29.c.ElocBg_A_xxxxxxxxxxxxxxxxxx', token_type: 'Bearer', expiry_date: 1537241286000, id_token: undefined, refresh_token: 'jwt-placeholder' }, url: 'https://sheets.googleapis.com/v4/spreadsheets/xxxxxxxxxxxxxxxxxxxxxxxxxxx/values:batchGet', paramsSerializer: [Function], data: undefined, params: { ranges: [Object], majorDimension: 'ROWS', dateTimeRenderOption: 'FORMATTED_STRING', valueRenderOption: 'FORMATTED_VALUE' } }, request: ClientRequest {
domain: null, _events: { socket: [Function], abort: [Function], aborted: [Function], error: [Function], timeout: [Function], prefinish: [Function: requestOnPrefinish] }, _eventsCount: 6, _maxListeners: undefined, output: [], outputEncodings: [], outputCallbacks: [], outputSize: 0, writable: true, _last: true, upgrading: false, chunkedEncoding: false, shouldKeepAlive: false, useChunkedEncodingByDefault: false, sendDate: false, _removedHeader: { }, _contentLength: 0, _hasBody: true, _trailer: '', finished: true, _headerSent: true, socket: TLSSocket { _tlsOptions: [Object], _secureEstablished: true, _securePending: false, _newSessionPending: false, _controlReleased: true, _SNICallback: null, servername: null, npnProtocol: false, alpnProtocol: false, authorized: true, authorizationError: null, encrypted: true, _events: [Object], _eventsCount: 8, connecting: false, _hadError: false, _handle: null, _parent: null, _host: 'sheets.googleapis.com', _readableState: [Object], readable: false, domain: null, _maxListeners: undefined, _writableState: [Object], writable: false, allowHalfOpen: false, destroyed: true, _bytesDispatched: 563, _sockname: null, _pendingData: null, _pendingEncoding: '', server: undefined, _server: null, ssl: null, _requestCert: true, _rejectUnauthorized: true, parser: null, _httpMessage: [Circular], read: [Function], _consuming: true, write: [Function: writeAfterFIN], _idleNext: null, _idlePrev: null, _idleTimeout: -1 }, connection: TLSSocket {
_tlsOptions: [Object], _secureEstablished: true, _securePending: false, _newSessionPending: false, _controlReleased: true, _SNICallback: null, servername: null, npnProtocol: false, alpnProtocol: false, authorized: true, authorizationError: null, encrypted: true, _events: [Object], _eventsCount: 8, connecting: false, _hadError: false, _handle: null, _parent: null, _host: 'sheets.googleapis.com', _readableState: [Object], readable: false, domain: null, _maxListeners: undefined, _writableState: [Object], writable: false, allowHalfOpen: false, destroyed: true, _bytesDispatched: 563, _sockname: null, _pendingData: null, _pendingEncoding: '', server: undefined, _server: null, ssl: null, _requestCert: true, _rejectUnauthorized: true, parser: null, _httpMessage: [Circular], read: [Function], _consuming: true, write: [Function: writeAfte
...
expected data.valueRanges------------------------
The Sheets API returned an error: TypeError: Cannot read property 'valueRanges' of null
I'm setting up push notification using the outlook api, the server is written in nodejs. This is the post request the client makes for the subscription
POST /api/v2.0/me/subscriptions HTTP/1.1
Host: outlook.office.com
Content-Type: application/json
client-request-id: f7d3812g-dfbz-4eb5-8edg-0f9a3ad716aq
User-Agent: node-outlook/2.0
return-client-request-id: true
X-Anchor-Mailbox: bill_gates#outlook.com
Authorization: Bearer "ACCESS_TOKEN"
Content-Type: application/json
{
"#odata.type":"#Microsoft.OutlookServices.PushSubscription",
"Resource": "https://outlook.office.com/api/v2.0/me/events",
"NotificationURL": "https://mywebsite.azurewebsites.net/push",
"ChangeType": "Created,Deleted,Updated"
}
The nodejs server then responds with the validation token that was generated by the outlook notification service
response.writeHead(200, { 'Content-Type': 'text/plain' });
response.write(validation_token);
response.end();
The client (which sent the original post request) then receives the following response
{
"#odata.context":"https://outlook.office.com/api/v2.0/$metadata#Me/Subscription/$entity",
"#odata.type": "#Microsoft.OutlookServices.PushSubscription",
"#odata.id": "https://outlook.office.com/api/v2.0/Users('00034001-ffef-f16e-0000-000000000000#74df9q7f-e9s6-40ad-b43w-aaaaaaaaaaaa')/Subscriptions('RERFNkJFNGUsNEE1My00RjFFLUExQkMtQkU1NkQ9OTdDOTlBXzAwMDM0MDAxLUZGRUYtZTE2RS0wMDAwLTAwMDAwMDAwMEAwMA==')",
"Id": "RERFNkJFNGUsNEE1My00RjFFLUExQkMtQkU1NkQ9OTdDOTlBXzAwMDM0MDAxLUZGRUYtZTE2RS0wMDAwLTAwMDAwMDAwMEAwMA==",
"Resource": "https://outlook.office.com/api/v2.0/me/messages",
"ChangeType": "Created, Updated, Deleted, Missed",
"NotificationURL": "https://mywebsite.azurewebsites.net/push",
"SubscriptionExpirationDateTime": "2017-03-30T09:35:37.6586596Z",
"ClientState": null
}
This is exactly what the outlook documentation states should happen https://dev.outlook.com/restapi/concepts/webhooks
This process validates the NotificationURL to receive push notifications from outlook. The NotificationURL end point is receiving a response from outlook when an event is created, but not the one I want!!!
I should expect to receive something like this:
{
"value": [
{
"#odata.type": "#Microsoft.OutlookServices.Notification",
"Id": null,
"SubscriptionId": "Mjk3QNERDQQ==",
"SubscriptionExpirationDateTime": "2015-04-23T22:46:13.8805047Z",
"SequenceNumber": 1,
"ChangeType": "Created",
"Resource" : "https://outlook.office.com/api/v2.0/Users('ddfcd489-628b-7d04-b48b-20075df800e5#1717622f-1d94-c0d4-9d74-f907ad6677b4')/Events('AAMkADNkNmAA=')",
"ResourceData": {
"#odata.type": "#Microsoft.OutlookServices.Event",
"#odata.id": "https://outlook.office.com/api/v2.0/Users('ddfcd489-628b-7d04-b48b-20075df800e5#1717622f-1d94-c0d4-9d74-f907ad6677b4')/Events('AAMkADNkNmAA=')",
"Id": "AAMkADNkNmAA="
}
}
]
}
But instead I'm receiving something like this
{
_readableState:
ReadableState {
objectMode: false,
highWaterMark: 16384,
buffer: BufferList { head: null, tail: null, length: 0 },
length: 0,
pipes: null,
pipesCount: 0,
flowing: null,
ended: false,
endEmitted: false,
reading: false,
sync: true,
needReadable: false,
emittedReadable: false,
readableListening: false,
resumeScheduled: false,
defaultEncoding: 'utf8',
ranOut: false,
awaitDrain: 0,
readingMore: true,
decoder: null,
encoding: null }, .......
And this response body goes on for another 600 lines.
I know there is a lot going on there, but any tips or help would be greatly appreciated.
I've just found the solution. When I am reading the request from the outlook notification, I have to switch the stream flowing to on, by default this was set to null (see the ReadableState JSON above).
It's very simple, just chain on to the request body, and use a callback.
More information can be found here: https://www.sandersdenardi.com/readable-writable-transform-streams-node/
So this becomes
request.on('data', function(record) {
console.log('received: ' + record);
});