How to access final GraphQL-Reponse in nest.js with interceptor - node.js

I have implemented a LoggingInterceptor which should be able to access the final GraphQL-Response with its data- and error properties + the original request body and the authenticated user, which has been added to the request by AuthGuard before.(EDIT: Partially solved by #jay-mcdoniel: user and body are accessible through GqlExecutionContext.create(context).getContext())
Indeed the Interceptor just provides one fully resolved GraphQL-Object.
#Injectable()
export class LoggingInterceptor implements NestInterceptor {
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
return next.handle().pipe(tap(
(allData) => console.log(allData),
(error)=> console.log(error)));
}
}
This is my Interceptor-Class. It's just calling the RxJS-Operator tap to log the current values of the observable.
If I run the following GraphQL-Request...
mutation {
login(data: { username: "admin", password: "123456" }) {
id
username
token
}
}
... my server answers correctly with the following response-body:
{
"data": {
"login": {
"id": "6f40be3b-cda9-4e6d-97ce-ced3787e9974",
"username": "admin",
"token": "someToken"
}
}
}
But the content of allData which get's logged to console by my interceptor is the following:
{
id: '6f40be3b-cda9-4e6d-97ce-ced3787e9974',
isAdmin: true,
username: 'admin',
firstname: null,
lastname: null,
email: null,
created: 2019-07-05T15:11:31.606Z,
token: 'someToken'
}
Instead I would like to see the information of the real response-body.
I have additionally tried to access the HttpResponse by context.switchToHttp().getResponse(). But this only contains the parameters of the mutation-login-method:
{
data: [Object: null prototype] { username: 'admin', password: '123456' }
}
EDIT:
console.log(GqlExecutionContext.create(context).getContext());
prints (still no GraphQL-ResponseBody):
{
headers: {
/*...*/
},
user: /*...*/,
body: {
operationName: null,
variables: {},
query: 'mutation {\n login(data: {username: "admin", password: ' +
'"123456"}) {\n token\n id\n username\n isAdmin\n }\n' +
'}\n'
},
res: ServerResponse {
_events: [Object: null prototype] { finish: [Function: bound resOnFinish] },
_eventsCount: 1,
_maxListeners: undefined,
outputData: [],
outputSize: 0,
writable: true,
_last: false,
chunkedEncoding: false,
shouldKeepAlive: true,
useChunkedEncodingByDefault: true,
sendDate: true,
_removedConnection: false,
_removedContLen: false,
_removedTE: false,
_contentLength: null,
_hasBody: true,
_trailer: '',
finished: false,
_headerSent: false,
socket: Socket {
connecting: false,
_hadError: false,
_parent: null,
_host: null,
_readableState: [ReadableState],
readable: true,
_events: [Object],
_eventsCount: 8,
_maxListeners: undefined,
_writableState: [WritableState],
writable: true,
allowHalfOpen: true,
_sockname: null,
_pendingData: null,
_pendingEncoding: '',
server: [Server],
_server: [Server],
timeout: 120000,
parser: [HTTPParser],
on: [Function: socketOnWrap],
_paused: false,
_httpMessage: [Circular],
[Symbol(asyncId)]: 566,
[Symbol(kHandle)]: [TCP],
[Symbol(lastWriteQueueSize)]: 0,
[Symbol(timeout)]: Timeout {
/*...*/
},
[Symbol(kBytesRead)]: 0,
[Symbol(kBytesWritten)]: 0
},
connection: Socket {
connecting: false,
_hadError: false,
_parent: null,
_host: null,
_readableState: [ReadableState],
readable: true,
_events: [Object],
_eventsCount: 8,
_maxListeners: undefined,
_writableState: [WritableState],
writable: true,
allowHalfOpen: true,
_sockname: null,
_pendingData: null,
_pendingEncoding: '',
server: [Server],
_server: [Server],
timeout: 120000,
parser: [HTTPParser],
on: [Function: socketOnWrap],
_paused: false,
_httpMessage: [Circular],
[Symbol(asyncId)]: 566,
[Symbol(kHandle)]: [TCP],
[Symbol(lastWriteQueueSize)]: 0,
[Symbol(timeout)]: Timeout {
_idleTimeout: 120000,
_idlePrev: [TimersList],
_idleNext: [TimersList],
_idleStart: 3273,
_onTimeout: [Function: bound ],
_timerArgs: undefined,
_repeat: null,
_destroyed: false,
[Symbol(refed)]: false,
[Symbol(asyncId)]: 567,
[Symbol(triggerId)]: 566
},
[Symbol(kBytesRead)]: 0,
[Symbol(kBytesWritten)]: 0
},
_header: null,
_onPendingData: [Function: bound updateOutgoingData],
_sent100: false,
_expect_continue: false,
req: IncomingMessage {
/*...*/
},
locals: [Object: null prototype] {},
[Symbol(isCorked)]: false,
[Symbol(outHeadersKey)]: [Object: null prototype] {
'x-powered-by': [Array],
'access-control-allow-origin': [Array]
}
},
_extensionStack: GraphQLExtensionStack { extensions: [ [CacheControlExtension] ] }
}

That's how I did that in my Logging Interceptor
#Injectable()
export class LoggingInterceptor implements NestInterceptor {
constructor(private readonly logger: Logger) {}
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
// default REST Api
if (context.getType() === 'http') {
...
...
}
// Graphql
if (context.getType<GqlContextType>() === 'graphql') {
const gqlContext = GqlExecutionContext.create(context);
const info = gqlContext.getInfo();
const res: Response = gqlContext.getContext().res;
// Get user that sent request
const userId = context.getArgByIndex(2).req.user.userId;
const parentType = info.parentType.name;
const fieldName = info.fieldName;
const body = info.fieldNodes[0]?.loc?.source?.body;
const message = `GraphQL - ${parentType} - ${fieldName}`;
// Add request ID,so it can be tracked with response
const requestId = uuidv4();
// Put to header, so can attach it to response as well
res.set('requestId', requestId);
const trace = {
userId,
body
};
this.logger.info(`requestId: ${requestId}`, {
context: message,
trace
});
return next.handle().pipe(
tap({
next: (val: unknown): void => {
this.logNext(val, context);
}
})
);
}
return next.handle();
}
/**
* Method to log response message
*/
private logNext(body: unknown, context: ExecutionContext): void {
// default REST Api
if (context.getType() === 'http') {
...
...
}
if (context.getType<GqlContextType>() === 'graphql') {
const gqlContext = GqlExecutionContext.create(context);
const info = gqlContext.getInfo();
const parentType = info.parentType.name;
const fieldName = info.fieldName;
const res: Response = gqlContext.getContext().res;
const message = `GraphQL - ${parentType} - ${fieldName}`;
// Remove secure fields from request body and headers
const secureBody = secureReqBody(body);
const requestId = res.getHeader('requestId');
// Log trace message
const trace = {
body: { ...secureBody }
};
this.logger.info(`requestId: ${requestId}`, {
context: message,
trace
});
}
}
}

The interceptor is actually called before and after the response, or it should be at least, so that you can have pre-request logic (request in) and post-request logic (response out). You should be able to do all pre-request processing before you call next.hanlde() and then you should be able to use the RxJS Observable operators such as tap or map after a pipe() call. Your allData variable should have all the information from the request/response, and you can even use the context variable for getting even more information.
What does allData currently print for you? Have you tried GqlExecutionContext.create(context).getContext().req or GqlExecutionContext.create(context).getContext().res? These are shown being used in the Guards documentation to get the request and response objects like you would with a normal HTTP call.

Related

401 Unauthorized when consuming Business Central OData Web Service in NodeJs

I have been trying to connect and retrieve a list of data from Business Central.
The Web Service has been exposed from BC and the OData link works and displays the JSON for the data in "Articles".
I'm trying to consumer that Service with NodeJS using NTLM (i also tried basic authentication and the same issue persists.
Please find below the file responsible for consuming the BC Web Service followed by the 401 error.
I have already stored all the information needed for NTLM config in my .env file, I did try to hardcode them and the same issue
const express = require("express");
const axios = require("axios");
const router = express.Router();
const ntlm = require("express-ntlm");
//const Article = require("../models/Articles.js");
const domain = process.env.DOMAIN;
const username = process.env.USERNAME;
const password = process.env.PASSWORD;
// Define auth function
const auth = ntlm({
debug: console.log,
domain,
username,
password,
ntlm_version: 2,
reconnect: true,
send_401: function (res) {
res.sendStatus(401);
},
badrequest: function (res) {
res.sendStatus(400);
},
});
// Get customer data from Business Central
async function getArticlesFromBC() {
try {
const options = {
auth: {
username,
password,
workstation: process.env.WORKSTATION,
domain,
},
};
const companyId = "CRONUS France S.A.";
const encodedCompanyId = encodeURIComponent(companyId);
const url = `http://${process.env.SERVER}:7048/BC210/ODataV4/Company('${encodedCompanyId}')/ItemListec`;
const response = await axios.get(url, options);
return response.data;
} catch (error) {
console.error(error);
throw new Error("Error retrieving articles data from Business Central");
}
}
// Route to get article data
router.get("/", auth, async (req, res) => {
try {
const user = req.ntlm;
console.log(user);
let articles = await getArticlesFromBC();
res.json(articles);
} catch (error) {
console.error(error);
res
.status(500)
.send("Error retrieving articles data from Business Central");
}
});
module.exports = router;
Explanation
This is the auth function that will use the variables set in .env to authenticate the user in order to access the BC endpoint
// Define auth function
const auth = ntlm({
debug: console.log,
domain,
username,
password,
ntlm_version: 2,
reconnect: true,
send_401: function (res) {
res.sendStatus(401);
},
badrequest: function (res) {
res.sendStatus(400);
},
});
This is the function that connects to the endpoint URL and returns the JSON file, this is where the error triggers
// Get article data from Business Central
async function getArticlesFromBC() {
try {
const options = {
auth: {
username,
password,
workstation: process.env.WORKSTATION,
domain,
},
};
const companyId = "CRONUS France S.A.";
const encodedCompanyId = encodeURIComponent(companyId);
const url = `http://${process.env.SERVER}:7048/BC210/ODataV4/Company('${encodedCompanyId}')/ItemListec`;
const response = await axios.get(url, options);
return response.data;
} catch (error) {
console.error(error);
throw new Error("Error retrieving articles data from Business Central");
}
}
This is the route to access the nodejs api
// Route to get article data
router.get("/", auth, async (req, res) => {
try {
const user = req.ntlm;
console.log(user);
let articles = await getArticlesFromBC();
res.json(articles);
} catch (error) {
console.error(error);
res
.status(500)
.send("Error retrieving articles data from Business Central");
}
});
This is the 401 error json, you can see at the beginning that NTLM authenticates successfully but then it throws the catch block in the get function
[express-ntlm] No Authorization header present
[express-ntlm] No domaincontroller was specified, all Authentication messages are valid.
{
DomainName: 'DESKTOP-1EF91E4',
UserName: 'ahmed',
Workstation: 'DESKTOP-1EF91E4',
Authenticated: true
}
AxiosError: Request failed with status code 401
at settle (D:\ESPRIT\5eme\PFE\B2B-ERP-MERN-App\node_modules\axios\dist\node\axios.cjs:1900:12)
at IncomingMessage.handleStreamEnd (D:\ESPRIT\5eme\PFE\B2B-ERP-MERN-App\node_modules\axios\dist\node\axios.cjs:2944:11)
at IncomingMessage.emit (events.js:412:35)
at endReadableNT (internal/streams/readable.js:1317:12)
at processTicksAndRejections (internal/process/task_queues.js:82:21) {
code: 'ERR_BAD_REQUEST',
config: {
transitional: {
silentJSONParsing: true,
forcedJSONParsing: true,
clarifyTimeoutError: false
},
adapter: [ 'xhr', 'http' ],
transformRequest: [ [Function: transformRequest] ],
transformResponse: [ [Function: transformResponse] ],
timeout: 0,
xsrfCookieName: 'XSRF-TOKEN',
xsrfHeaderName: 'X-XSRF-TOKEN',
maxContentLength: -1,
maxBodyLength: -1,
env: { FormData: [Function], Blob: null },
validateStatus: [Function: validateStatus],
headers: AxiosHeaders {
Accept: 'application/json, text/plain, */*',
'User-Agent': 'axios/1.3.3',
'Accept-Encoding': 'gzip, compress, deflate, br'
},
auth: {
username: 'ahmed',
password: undefined,
workstation: 'DESKTOP-1EF91E4',
domain: undefined
},
method: 'get',
url: "http://desktop-1ef91e4:7048/BC210/ODataV4/Company('CRONUS%20France%20S.A.')/ItemListec",
data: undefined
},
request: <ref *1> ClientRequest {
_events: [Object: null prototype] {
abort: [Function (anonymous)],
aborted: [Function (anonymous)],
connect: [Function (anonymous)],
error: [Function (anonymous)],
socket: [Function (anonymous)],
timeout: [Function (anonymous)],
prefinish: [Function: requestOnPrefinish]
},
_eventsCount: 7,
_maxListeners: undefined,
outputData: [],
outputSize: 0,
writable: true,
destroyed: false,
_last: true,
chunkedEncoding: false,
shouldKeepAlive: false,
_defaultKeepAlive: true,
useChunkedEncodingByDefault: false,
sendDate: false,
_removedConnection: false,
_removedContLen: false,
_removedTE: false,
_contentLength: 0,
_hasBody: true,
_trailer: '',
finished: true,
_headerSent: true,
socket: Socket {
connecting: false,
_hadError: false,
_parent: null,
_host: 'desktop-1ef91e4',
_readableState: [ReadableState],
_events: [Object: null prototype],
_eventsCount: 7,
_maxListeners: undefined,
_writableState: [WritableState],
allowHalfOpen: false,
_sockname: null,
_pendingData: null,
_pendingEncoding: '',
server: null,
_server: null,
parser: null,
_httpMessage: [Circular *1],
[Symbol(async_id_symbol)]: 465,
[Symbol(kHandle)]: [TCP],
[Symbol(kSetNoDelay)]: false,
[Symbol(lastWriteQueueSize)]: 0,
[Symbol(timeout)]: null,
[Symbol(kBuffer)]: null,
[Symbol(kBufferCb)]: null,
[Symbol(kBufferGen)]: null,
[Symbol(kCapture)]: false,
[Symbol(kBytesRead)]: 0,
[Symbol(kBytesWritten)]: 0,
[Symbol(RequestTimeout)]: undefined
},
_header: "GET /BC210/ODataV4/Company('CRONUS%20France%20S.A.')/ItemListec HTTP/1.1\r\n" +
'Accept: application/json, text/plain, */*\r\n' +
'User-Agent: axios/1.3.3\r\n' +
'Accept-Encoding: gzip, compress, deflate, br\r\n' +
'Host: desktop-1ef91e4:7048\r\n' +
'Authorization: Basic YWhtZWQ6\r\n' +
'Connection: close\r\n' +
'\r\n',
_keepAliveTimeout: 0,
_onPendingData: [Function: noopPendingOutput],
agent: Agent {
_events: [Object: null prototype],
_eventsCount: 2,
_maxListeners: undefined,
defaultPort: 80,
protocol: 'http:',
options: [Object],
requests: {},
sockets: [Object],
freeSockets: {},
keepAliveMsecs: 1000,
keepAlive: false,
maxSockets: Infinity,
maxFreeSockets: 256,
scheduling: 'lifo',
maxTotalSockets: Infinity,
totalSocketCount: 1,
[Symbol(kCapture)]: false
},
socketPath: undefined,
method: 'GET',
maxHeaderSize: undefined,
insecureHTTPParser: undefined,
path: "/BC210/ODataV4/Company('CRONUS%20France%20S.A.')/ItemListec",
_ended: true,
res: IncomingMessage {
_readableState: [ReadableState],
_events: [Object: null prototype],
_eventsCount: 4,
_maxListeners: undefined,
socket: [Socket],
httpVersionMajor: 1,
httpVersionMinor: 1,
httpVersion: '1.1',
complete: true,
headers: [Object],
rawHeaders: [Array],
trailers: {},
rawTrailers: [],
aborted: false,
upgrade: false,
url: '',
method: null,
statusCode: 401,
statusMessage: 'Unauthorized',
client: [Socket],
_consuming: false,
_dumped: false,
req: [Circular *1],
responseUrl: "http://ahmed:#desktop-1ef91e4:7048/BC210/ODataV4/Company('CRONUS%20France%20S.A.')/ItemListec",
redirects: [],
[Symbol(kCapture)]: false,
[Symbol(RequestTimeout)]: undefined
},
aborted: false,
timeoutCb: null,
upgradeOrConnect: false,
parser: null,
maxHeadersCount: null,
reusedSocket: false,
host: 'desktop-1ef91e4',
protocol: 'http:',
_redirectable: Writable {
_writableState: [WritableState],
_events: [Object: null prototype],
_eventsCount: 3,
_maxListeners: undefined,
_options: [Object],
_ended: true,
_ending: true,
_redirectCount: 0,
_redirects: [],
_requestBodyLength: 0,
_requestBodyBuffers: [],
_onNativeResponse: [Function (anonymous)],
_currentRequest: [Circular *1],
_currentUrl: "http://ahmed:#desktop-1ef91e4:7048/BC210/ODataV4/Company('CRONUS%20France%20S.A.')/ItemListec",
[Symbol(kCapture)]: false
},
[Symbol(kCapture)]: false,
[Symbol(kNeedDrain)]: false,
[Symbol(corked)]: 0,
[Symbol(kOutHeaders)]: [Object: null prototype] {
accept: [Array],
'user-agent': [Array],
'accept-encoding': [Array],
host: [Array],
authorization: [Array]
}
},
response: {
status: 401,
statusText: 'Unauthorized',
headers: AxiosHeaders {
'content-length': '0',
server: 'Microsoft-HTTPAPI/2.0',
'www-authenticate': 'Negotiate',
date: 'Thu, 16 Feb 2023 11:49:51 GMT',
connection: 'close'
},
config: {
transitional: [Object],
adapter: [Array],
transformRequest: [Array],
transformResponse: [Array],
timeout: 0,
xsrfCookieName: 'XSRF-TOKEN',
xsrfHeaderName: 'X-XSRF-TOKEN',
maxContentLength: -1,
maxBodyLength: -1,
env: [Object],
validateStatus: [Function: validateStatus],
headers: [AxiosHeaders],
auth: [Object],
method: 'get',
url: "http://desktop-1ef91e4:7048/BC210/ODataV4/Company('CRONUS%20France%20S.A.')/ItemListec",
data: undefined
},
request: <ref *1> ClientRequest {
_events: [Object: null prototype],
_eventsCount: 7,
_maxListeners: undefined,
outputData: [],
outputSize: 0,
writable: true,
destroyed: false,
_last: true,
chunkedEncoding: false,
shouldKeepAlive: false,
_defaultKeepAlive: true,
useChunkedEncodingByDefault: false,
sendDate: false,
_removedConnection: false,
_removedContLen: false,
_removedTE: false,
_contentLength: 0,
_hasBody: true,
_trailer: '',
finished: true,
_headerSent: true,
socket: [Socket],
_header: "GET /BC210/ODataV4/Company('CRONUS%20France%20S.A.')/ItemListec HTTP/1.1\r\n" +
'Accept: application/json, text/plain, */*\r\n' +
'User-Agent: axios/1.3.3\r\n' +
'Accept-Encoding: gzip, compress, deflate, br\r\n' +
'Host: desktop-1ef91e4:7048\r\n' +
'Authorization: Basic YWhtZWQ6\r\n' +
'Connection: close\r\n' +
'\r\n',
_keepAliveTimeout: 0,
_onPendingData: [Function: noopPendingOutput],
agent: [Agent],
socketPath: undefined,
method: 'GET',
maxHeaderSize: undefined,
insecureHTTPParser: undefined,
path: "/BC210/ODataV4/Company('CRONUS%20France%20S.A.')/ItemListec",
_ended: true,
res: [IncomingMessage],
aborted: false,
timeoutCb: null,
upgradeOrConnect: false,
parser: null,
maxHeadersCount: null,
reusedSocket: false,
host: 'desktop-1ef91e4',
protocol: 'http:',
_redirectable: [Writable],
[Symbol(kCapture)]: false,
[Symbol(kNeedDrain)]: false,
[Symbol(corked)]: 0,
[Symbol(kOutHeaders)]: [Object: null prototype]
},
data: ''
}
}
Error: Error retrieving articles data from Business Central
at getArticlesFromBC (D:\ESPRIT\5eme\PFE\B2B-ERP-MERN-App\routes\ArticleRoutes.js:44:11)
at processTicksAndRejections (internal/process/task_queues.js:95:5)
at async D:\ESPRIT\5eme\PFE\B2B-ERP-MERN-App\routes\ArticleRoutes.js:53:20
Even though it works perfectly in postman (NTLM authentication on Server Instance is enabled for that to happen)
express-ntlm seemed to authenticate the user but dosent follow up for some reason.
I switched to httpntlm and it worked perfectly, here is the new code in the node API file :
const express = require("express");
const router = express.Router();
const httpntlm = require("httpntlm");
// Get article data from Business Central
async function getArticlesFromBC() {
const username = process.env.USERNAME;
const password = process.env.PASSWORD;
const domain = process.env.DOMAIN;
const workstation = process.env.WORKSTATION;
const encodedCompanyId = encodeURIComponent("CRONUS France S.A.");
const url = `http://${process.env.SERVER}:7048/BC210/ODataV4/Company('${encodedCompanyId}')/ItemListec`;
const options = {
url: url,
username: username,
password: password,
workstation: workstation,
domain: domain
};
return new Promise((resolve, reject) => {
httpntlm.get(options, (err, res) => {
if (err) {
console.error(err);
reject(err);
} else {
resolve(res.body);
}
});
});
}
// Route to get article data
router.get("/", async (req, res) => {
try {
const articles = await getArticlesFromBC();
res.json(articles);
} catch (error) {
console.error("Error retrieving articles data from Business Central:", error.message);
res.status(500).send("Error retrieving articles data from Business Central");
}
});
module.exports = router;

How to pass body to express router for PUT request?

I'm trying to create a PUT request using express.js, but I keep getting this error stating that the body is not defined. But when I print the req to the console, I do see body with the data.
Express
router.put('/category-statement/:corporate_statement_link_id', function(req, res){
console.log("req: ",req);
var reqBody = req.body;
var id = req.params.corporate_statement_link_id;
console.log("Body: ", body);
console.log("id:", id);
let sql = `UPDATE corporate_statements
SET corporate_statement = ? WHERE corporate_statement_link_id = ?`;
db.run(sql,[reqBody.corporate_statement, id], (err, row) =>{
if(err){
res.status(500).send(err);
}
res.send(row)
});
})
Angular Service
updateCorporateStatementStatus(corporate_statement_link_id:number, corporate_statement:ICorporateStatementInfo){
console.log("corporate statement", corporate_statement);
const headers= new HttpHeaders()
.set('content-type', 'application/json')
.set('Access-Control-Allow-Origin', '*');
var body = corporate_statement; // copying to body thinking router.put is specifically looking for body
console.log(corporate_statement);
return this.http.put<ICorporateStatementInfo>('/api/v1/statements/category-statement/' + corporate_statement_link_id, body, {headers})
.subscribe(data => {
console.log(data);
})
}
req print
This is just a part of the req from router.put
params: { corporate_statement_link_id: '3' },
query: {},
res: ServerResponse {
_events: [Object: null prototype] {
finish: [Array],
end: [Function: onevent]
},
_eventsCount: 2,
_maxListeners: undefined,
outputData: [],
outputSize: 0,
writable: true,
_last: false,
chunkedEncoding: false,
shouldKeepAlive: true,
useChunkedEncodingByDefault: true,
sendDate: true,
_removedConnection: false,
_removedContLen: false,
_removedTE: false,
_contentLength: null,
_hasBody: true,
_trailer: '',
finished: false,
_headerSent: false,
socket: TLSSocket {
_tlsOptions: [Object],
_secureEstablished: true,
_securePending: false,
_newSessionPending: false,
_controlReleased: true,
secureConnecting: false,
_SNICallback: null,
servername: 'localhost',
alpnProtocol: 'http/1.1',
authorized: false,
authorizationError: null,
encrypted: true,
_events: [Object: null prototype],
_eventsCount: 11,
connecting: false,
_hadError: false,
_parent: [Socket],
_host: null,
_readableState: [ReadableState],
readable: true,
_maxListeners: undefined,
_writableState: [WritableState],
writable: true,
allowHalfOpen: false,
_sockname: null,
_pendingData: null,
_pendingEncoding: '',
server: [Server],
_server: null,
ssl: [TLSWrap],
_requestCert: false,
_rejectUnauthorized: true,
timeout: 120000,
parser: [HTTPParser],
on: [Function: socketListenerWrap],
addListener: [Function: socketListenerWrap],
prependListener: [Function: socketListenerWrap],
_paused: false,
_httpMessage: [Circular],
_peername: [Object],
[Symbol(res)]: [TLSWrap],
[Symbol(verified)]: false,
[Symbol(pendingSession)]: null,
[Symbol(asyncId)]: 19,
[Symbol(kHandle)]: [TLSWrap],
[Symbol(kSetNoDelay)]: false,
[Symbol(lastWriteQueueSize)]: 0,
[Symbol(timeout)]: Timeout {
_idleTimeout: 120000,
_idlePrev: [TimersList],
_idleNext: [TimersList],
_idleStart: 18664,
_onTimeout: [Function: bound ],
_timerArgs: undefined,
_repeat: null,
_destroyed: false,
[Symbol(refed)]: false,
[Symbol(asyncId)]: 977,
[Symbol(triggerId)]: 23
},
[Symbol(kBuffer)]: null,
[Symbol(kBufferCb)]: null,
[Symbol(kBufferGen)]: null,
[Symbol(kCapture)]: false,
[Symbol(kBytesRead)]: 0,
[Symbol(kBytesWritten)]: 0,
[Symbol(error-emitted)]: false
},
connection: TLSSocket {
_tlsOptions: [Object],
_secureEstablished: true,
_securePending: false,
_newSessionPending: false,
_controlReleased: true,
secureConnecting: false,
_SNICallback: null,
servername: 'localhost',
alpnProtocol: 'http/1.1',
authorized: false,
authorizationError: null,
encrypted: true,
_events: [Object: null prototype],
_eventsCount: 11,
connecting: false,
_hadError: false,
_parent: [Socket],
_host: null,
_readableState: [ReadableState],
readable: true,
_maxListeners: undefined,
_writableState: [WritableState],
writable: true,
allowHalfOpen: false,
_sockname: null,
_pendingData: null,
_pendingEncoding: '',
server: [Server],
_server: null,
ssl: [TLSWrap],
_requestCert: false,
_rejectUnauthorized: true,
timeout: 120000,
parser: [HTTPParser],
on: [Function: socketListenerWrap],
addListener: [Function: socketListenerWrap],
prependListener: [Function: socketListenerWrap],
_paused: false,
_httpMessage: [Circular],
_peername: [Object],
[Symbol(res)]: [TLSWrap],
[Symbol(verified)]: false,
[Symbol(pendingSession)]: null,
[Symbol(asyncId)]: 19,
[Symbol(kHandle)]: [TLSWrap],
[Symbol(kSetNoDelay)]: false,
[Symbol(lastWriteQueueSize)]: 0,
[Symbol(timeout)]: Timeout {
_idleTimeout: 120000,
_idlePrev: [TimersList],
_idleNext: [TimersList],
_idleStart: 18664,
_onTimeout: [Function: bound ],
_timerArgs: undefined,
_repeat: null,
_destroyed: false,
[Symbol(refed)]: false,
[Symbol(asyncId)]: 977,
[Symbol(triggerId)]: 23
},
[Symbol(kBuffer)]: null,
[Symbol(kBufferCb)]: null,
[Symbol(kBufferGen)]: null,
[Symbol(kCapture)]: false,
[Symbol(kBytesRead)]: 0,
[Symbol(kBytesWritten)]: 0,
[Symbol(error-emitted)]: false
},
_header: null,
_onPendingData: [Function: bound updateOutgoingData],
_sent100: false,
_expect_continue: false,
req: [Circular],
locals: [Object: null prototype] {},
_startAt: undefined,
_startTime: undefined,
writeHead: [Function: writeHead],
__onFinished: [Function: listener] { queue: [Array] },
[Symbol(kCapture)]: false,
[Symbol(kNeedDrain)]: false,
[Symbol(corked)]: 0,
[Symbol(kOutHeaders)]: [Object: null prototype] { 'x-powered-by': [Array] }
},
_startAt: [ 267748, 220273300 ],
_startTime: 2020-10-19T01:47:48.684Z,
_remoteAddress: '::1',
body: { corporate_statement: false },
_body: true,
length: undefined,
route: Route {
path: '/category-statement/:corporate_statement_link_id',
stack: [ [Layer] ],
methods: { put: true }
},
[Symbol(kCapture)]: false
}
The error printed by app.js
// error handler
app.use(function (err, req, res, next) {
// set locals, only providing error in development
console.log(err.message);
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
console.log("this is where it's happening");
// render the error page
res.status(err.status || 500);
res.json({ error: err })
});
body is not defined
Look carefully in your code. Especially, your PUT route.
router.put('/category-statement/:corporate_statement_link_id', function(req, res){
console.log("req: ",req);
// You define `reqBody`...
var reqBody = req.body;
var id = req.params.corporate_statement_link_id;
// ...So where does `body` come from?
console.log("Body: ", body);
console.log("id:", id);
let sql = `UPDATE corporate_statements
SET corporate_statement = ? WHERE corporate_statement_link_id = ?`;
db.run(sql,[reqBody.corporate_statement, id], (err, row) =>{
if(err){
res.status(500).send(err);
}
res.send(row)
});
})
As see in your code, you defined reqBody, assigning it the value of req.body. Then, you try to access the (non-existent) variable body. You probably meant to type reqBody.

Firebase schedule function subpub axios POST request

I'm using firebase functions to schedule a puppeteer task from a firebase pubsub namespace.
I also want to post the response back to an API endpoint outside google using axios.
I tried Axios directly from the worker but I get a 500 error.
My goal:
Use firebase schedule and pubsub namespace to generate puppeteer
jobs - complete
Post results back to external endpoint using axios - need your help :)
Code:
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const functions = require("firebase-functions");
const admin = require("firebase-admin");
const puppeteer = require('puppeteer');
const url = require('url');
// Request Data From A URL
var axios = require('axios');
var https = require('https');
// var cors = require("cors");
// Initalise App
admin.initializeApp();
const db = admin.firestore();
const workers = {
extract: async ({ uri, post_id, store_id, domain }) => {
let theTitle = null;
let thePrice = null;
let host = url.parse(uri).host;
let postId = post_id;
let storeId = store_id;
let theDomain = domain;
const SELECTORS = {
amazonPrice: '#priceblock_ourprice',
ebayPrice: '#prcIsum',
const browser = await puppeteer.launch({ args: ['--no-sandbox', '--disable-setuid-sandbox'] });
console.log('spawning chrome headless');
console.log(postId);
console.log(storeId);
console.log(domain);
const page = await browser.newPage();
// Goto page and then do stuff
console.log('going to ', uri);
await page.goto(uri, {
waitUntil: ["domcontentloaded", "networkidle0"]
});
console.log('waiting for page to load ');
console.log(host);
// theTitle = await page.title();
try {
theTitle = await page.title();
// find amazon price
if (host === 'www.amazon.co.uk' || 'amazon.co.uk') {
const priceInput = await page.$(SELECTORS.amazonPrice)
thePrice = await page.evaluate(element => element.textContent, priceInput)
}
// find ebay price
if (host === 'www.ebay.co.uk' || 'ebay.co.uk') {
const priceInput = await page.$(SELECTORS.ebayPrice)
thePrice = await page.evaluate(element => element.value, priceInput)
}
else {
console.log('failed scrape at', host);
}
}
catch (error) {
console.error('There was an error processing the page:', error);
}
finally {
// close browser
if (browser !== null) {
await browser.close();
}
}
console.log(theTitle);
console.log(thePrice);
const response = {
title: theTitle,
price: thePrice,
};
console.log('post' + postId + storeId + thePrice + theDomain);
axios.post('endpoint', {
price: thePrice,
store_id: storeId,
post_id: postId,
domain: theDomain,
},
{
headers: {
'Content-Type': 'multipart/form-data',
}
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
// axios post end
return response;
}
};
exports.taskRunner = functions.runWith({ memory: '2GB' }).pubsub
// export const taskRunner = functions.region('europe-west2').runWith( { memory: '2GB' }).pubsub
.schedule('*/15 * * * *').onRun(async (context) => {
// Consistent timestamp
const now = admin.firestore.Timestamp.now();
// Query all documents ready to perform
const query = db.collection('tasks').where('performAt', '<=', now).where('status', '==', 'scheduled');
const tasks = await query.get();
// Jobs to execute concurrently.
const jobs = [];
// Loop over documents and push job.
tasks.forEach(snapshot => {
const { worker, options } = snapshot.data();
const job = workers[worker](options)
// Update doc with status on success or error
// .then(() => snapshot.ref.update({ status: 'complete' }))
.catch((err) => snapshot.ref.update({ status: 'error' }));
jobs.push(job);
});
// Execute all jobs concurrently
return await Promise.all(jobs);
});
Error
Error: Request failed with status code 500
at createError (/srv/node_modules/axios/lib/core/createError.js:16:15)
at settle (/srv/node_modules/axios/lib/core/settle.js:17:12)
at IncomingMessage.handleStreamEnd (/srv/node_modules/axios/lib/adapters/http.js:236:11)
at emitNone (events.js:111:20)
at IncomingMessage.emit (events.js:208:7)
at endReadableNT (_stream_readable.js:1064:12)
at _combinedTickCallback (internal/process/next_tick.js:139:11)
at process._tickDomainCallback (internal/process/next_tick.js:219:9)
config:
{ url: 'endpoint',
method: 'post',
data: '{"£59.99":null,"store_id":32,"post_id":25,"domain":"amazon.co.uk"}',
headers:
{ Accept: 'application/json, text/plain, */*',
'Content-Type': 'multipart/form-data',
'User-Agent': 'axios/0.19.2',
'Content-Length': 65 },
transformRequest: [ [Function: transformRequest] ],
transformResponse: [ [Function: transformResponse] ],
timeout: 0,
adapter: [Function: httpAdapter],
xsrfCookieName: 'XSRF-TOKEN',
xsrfHeaderName: 'X-XSRF-TOKEN',
maxContentLength: -1,
validateStatus: [Function: validateStatus] },
request:
ClientRequest {
domain:
Domain {
domain: null,
_events: [Object],
_eventsCount: 1,
_maxListeners: undefined,
members: [Array] },
_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: true,
sendDate: false,
_removedConnection: false,
_removedContLen: false,
_removedTE: false,
_contentLength: null,
_hasBody: true,
_trailer: '',
finished: true,
_headerSent: true,
socket:
TLSSocket {
_tlsOptions: [Object],
_secureEstablished: true,
_securePending: false,
_newSessionPending: false,
_controlReleased: true,
_SNICallback: null,
servername: 'SERVERNAME',
npnProtocol: false,
alpnProtocol: false,
authorized: true,
authorizationError: null,
encrypted: true,
_events: [Object],
_eventsCount: 9,
connecting: false,
_hadError: false,
_handle: [Object],
_parent: null,
_host: 'HOST',
_readableState: [Object],
readable: true,
domain: [Object],
_maxListeners: undefined,
_writableState: [Object],
writable: false,
allowHalfOpen: false,
_bytesDispatched: 259,
_sockname: null,
_pendingData: null,
_pendingEncoding: '',
server: undefined,
_server: null,
ssl: [Object],
_requestCert: true,
_rejectUnauthorized: true,
parser: null,
_httpMessage: [Circular],
[Symbol(asyncId)]: 538,
[Symbol(bytesRead)]: 0 },
connection:
TLSSocket {
_tlsOptions: [Object],
_secureEstablished: true,
_securePending: false,
_newSessionPending: false,
_controlReleased: true,
_SNICallback: null,
servername: 'HOST',
npnProtocol: false,
alpnProtocol: false,
authorized: true,
authorizationError: null,
encrypted: true,
_events: [Object],
_eventsCount: 9,
connecting: false,
_hadError: false,
_handle: [Object],
_parent: null,
_host: 'HOST',
_readableState: [Object],
readable: true,
domain: [Object],
_maxListeners: undefined,
_writableState: [Object],
writable: false,
allowHalfOpen: false,
_bytesDispatched: 259,
_sockname: null,
_pendingData: null,
_pendingEncoding: '',
server: undefined,
_server: null,
ssl: [Object],
_requestCert: true,
_rejectUnauthorized: true,
parser: null,
_httpMessage: [Circular],
[Symbol(asyncId)]: 538,
[Symbol(bytesRead)]: 0 },
_header: 'POST ENDPOINT HTTP/1.1\r\nAccept: application/json, text/plain, */*\r\nContent-Type: multipart/form-data\r\nUser-Agent: axios/0.19.2\r\nContent-Length: 65\r\nHost: HOST\r\nConnection: close\r\n\r\n',
_onPendingData: [Function: noopPendingOutput],
agent:
Agent {
domain: null,
_events: [Object],
_eventsCount: 1,
_maxListeners: undefined,
defaultPort: 443,
protocol: 'https:',
options: [Object],
requests: {},
sockets:
more_vert
Logs are subject to Cloud Logging's
After some work and trial & error. I settled on using the Request package to solve for the issue - https://www.npmjs.com/package/request
Not had time to investigate why Axios was not working but will review and if enlightened I will post here.

nodejs client can`t signup to nodejs passport based authentication service

I am trying to implement nodejs express passport axios based server-client communication. My goal push files to the server using the terminal. But first I try to implement an authentication service. I have passport auth service which works well when I signing throw postman app.
Also, I have implemented nodejs based client, which try signup to the server but without success.
error:
{ Error: Request failed with status code 400
at createError (/home/gefalko/gepick-devenv/node_modules/axios/lib/core/createError.js:16:15)
at settle (/home/gefalko/gepick-devenv/node_modules/axios/lib/core/settle.js:18:12)
at IncomingMessage.handleStreamEnd (/home/gefalko/gepick-devenv/node_modules/axios/lib/adapters/http.js:201:11)
at emitNone (events.js:111:20)
at IncomingMessage.emit (events.js:208:7)
at endReadableNT (_stream_readable.js:1064:12)
at _combinedTickCallback (internal/process/next_tick.js:139:11)
at process._tickCallback (internal/process/next_tick.js:181:9)
config:
{ adapter: [Function: httpAdapter],
transformRequest: { '0': [Function: transformRequest] },
transformResponse: { '0': [Function: transformResponse] },
timeout: 0,
xsrfCookieName: 'XSRF-TOKEN',
xsrfHeaderName: 'X-XSRF-TOKEN',
maxContentLength: -1,
validateStatus: [Function: validateStatus],
headers:
{ Accept: 'application/json, text/plain, */*',
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
'User-Agent': 'axios/0.18.0',
'Content-Length': 45 },
method: 'post',
url: 'http://localhost:3005/login',
data: '{"username":"gefalko","password":"mypass"}' },
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: true,
sendDate: false,
_removedConnection: false,
_removedContLen: false,
_removedTE: false,
_contentLength: null,
_hasBody: true,
_trailer: '',
finished: true,
_headerSent: true,
socket:
Socket {
connecting: false,
_hadError: false,
_handle: [Object],
_parent: null,
_host: 'localhost',
_readableState: [Object],
readable: true,
domain: null,
_events: [Object],
_eventsCount: 8,
_maxListeners: undefined,
_writableState: [Object],
writable: false,
allowHalfOpen: false,
_bytesDispatched: 263,
_sockname: null,
_pendingData: null,
_pendingEncoding: '',
server: null,
_server: null,
parser: null,
_httpMessage: [Circular],
[Symbol(asyncId)]: 45,
[Symbol(bytesRead)]: 0 },
connection:
Socket {
connecting: false,
_hadError: false,
_handle: [Object],
_parent: null,
_host: 'localhost',
_readableState: [Object],
readable: true,
domain: null,
_events: [Object],
_eventsCount: 8,
_maxListeners: undefined,
_writableState: [Object],
writable: false,
allowHalfOpen: false,
_bytesDispatched: 263,
_sockname: null,
_pendingData: null,
_pendingEncoding: '',
server: null,
_server: null,
parser: null,
_httpMessage: [Circular],
[Symbol(asyncId)]: 45,
[Symbol(bytesRead)]: 0 },
_header: 'POST /login HTTP/1.1\r\nAccept: application/json, text/plain, */*\r\nContent-Type: application/x-www-form-urlencoded; charset=UTF-8\r\nUser-Agent: axios/0.18.0\r\nContent-Length: 45\r\nHost: localhost:3005\r\nConnection: close\r\n\r\n',
_onPendingData: [Function: noopPendingOutput],
agent:
Agent {
domain: null,
_events: [Object],
_eventsCount: 1,
_maxListeners: undefined,
defaultPort: 80,
protocol: 'http:',
options: [Object],
requests: {},
sockets: [Object],
freeSockets: {},
keepAliveMsecs: 1000,
keepAlive: false,
maxSockets: Infinity,
maxFreeSockets: 256 },
socketPath: undefined,
timeout: undefined,
method: 'POST',
path: '/login',
_ended: true,
res:
IncomingMessage {
_readableState: [Object],
readable: false,
domain: null,
_events: [Object],
_eventsCount: 3,
_maxListeners: undefined,
socket: [Object],
connection: [Object],
httpVersionMajor: 1,
httpVersionMinor: 1,
httpVersion: '1.1',
complete: true,
headers: [Object],
rawHeaders: [Array],
trailers: {},
rawTrailers: [],
aborted: false,
upgrade: false,
url: '',
method: null,
statusCode: 400,
statusMessage: 'Bad Request',
client: [Object],
_consuming: true,
_dumped: false,
req: [Circular],
responseUrl: 'http://localhost:3005/login',
redirects: [],
read: [Function] },
aborted: undefined,
timeoutCb: null,
upgradeOrConnect: false,
parser: null,
maxHeadersCount: null,
_redirectable:
Writable {
_writableState: [Object],
writable: true,
domain: null,
_events: [Object],
_eventsCount: 2,
_maxListeners: undefined,
_options: [Object],
_ended: true,
_ending: true,
_redirectCount: 0,
_redirects: [],
_requestBodyLength: 45,
_requestBodyBuffers: [],
_onNativeResponse: [Function],
_currentRequest: [Circular],
_currentUrl: 'http://localhost:3005/login' },
[Symbol(outHeadersKey)]:
{ accept: [Array],
'content-type': [Array],
'user-agent': [Array],
'content-length': [Array],
host: [Array] } },
response:
{ status: 400,
statusText: 'Bad Request',
headers:
{ 'x-powered-by': 'Express',
date: 'Wed, 20 Mar 2019 11:52:49 GMT',
connection: 'close',
'content-length': '11' },
config:
{ adapter: [Function: httpAdapter],
transformRequest: [Object],
transformResponse: [Object],
timeout: 0,
xsrfCookieName: 'XSRF-TOKEN',
xsrfHeaderName: 'X-XSRF-TOKEN',
maxContentLength: -1,
validateStatus: [Function: validateStatus],
headers: [Object],
method: 'post',
url: 'http://localhost:3005/login',
data: '{"username":"gefalko","password":"mypass"}' },
request:
ClientRequest {
domain: null,
_events: [Object],
_eventsCount: 6,
_maxListeners: undefined,
output: [],
outputEncodings: [],
outputCallbacks: [],
outputSize: 0,
writable: true,
_last: true,
upgrading: false,
chunkedEncoding: false,
shouldKeepAlive: false,
useChunkedEncodingByDefault: true,
sendDate: false,
_removedConnection: false,
_removedContLen: false,
_removedTE: false,
_contentLength: null,
_hasBody: true,
_trailer: '',
finished: true,
_headerSent: true,
socket: [Object],
connection: [Object],
_header: 'POST /login HTTP/1.1\r\nAccept: application/json, text/plain, */*\r\nContent-Type: application/x-www-form-urlencoded; charset=UTF-8\r\nUser-Agent: axios/0.18.0\r\nContent-Length: 45\r\nHost: localhost:3005\r\nConnection: close\r\n\r\n',
_onPendingData: [Function: noopPendingOutput],
agent: [Object],
socketPath: undefined,
timeout: undefined,
method: 'POST',
path: '/login',
_ended: true,
res: [Object],
aborted: undefined,
timeoutCb: null,
upgradeOrConnect: false,
parser: null,
maxHeadersCount: null,
_redirectable: [Object],
[Symbol(outHeadersKey)]: [Object] },
data: 'Bad Request' } }
my client:
const axios = require('axios')
const prompt = require('prompt')
var prompt_attributes = [
{
name: 'username',
validator: /^[a-zA-Z\s\-]+$/,
warning: 'Username is not valid, it can only contains letters, spaces, or dashes'
},
{
name: 'password',
hidden: true
}
]
prompt.start();
prompt.get(prompt_attributes, function (err, result) {
if (err) {
console.log(err);
return 1;
}else {
console.log('Command-line received data:');
const username = result.username
const password = result.password
const config = {
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
}
const reqBody = {
username: username,
password: password
}
axios.post('http://localhost:3005/login', reqBody, config).then(response => {
console.log(response.data);
}).catch(error => {
console.log(error);
})
}
});
also tried 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' but it not help.
server:
import * as express from 'express'
const app = express()
const passport = require('passport')
const LocalStrategy = require('passport-local').Strategy
const bcrypt = require('bcryptjs')
app.use(require('cookie-parser')())
app.use(require('body-parser').urlencoded({ extended: true }))
app.use(passport.initialize())
const port = 3005
/* DATABASE */
import { MongoClient, ObjectID } from 'mongodb'
const mongoUrl = "mongodb://localhost:27017/";
/* AUTHENTICATION */
MongoClient.connect(mongoUrl, async (err, db) => {
const myDB = db.db('mydb')
const Users = myDb.collection('users')
passport.serializeUser(function(user, done) {
done(null, user);
});
passport.deserializeUser(function(user, done) {
done(null, user);
});
passport.use(new LocalStrategy(
function(username, password, done) {
Users.findOne({ username: username }, async function(err, user) {
console.log('USER FROM DB:', user)
console.log('PASS from client', password)
if (err) { return done(err); }
if (!user){
return done(null, false, { message: 'Incorrect username.' });
}
const res = await bcrypt.compare(password, user.password)
return res ? done(null, user) : done(null, false, { message: 'Incorrect username.' })
})
}))
app.post('/login',passport.authenticate('local'), (req, res) =>
{
res.send('logined as ' + req.user.username)
}
)
app.listen(port, () => console.log('http server listening on port '+port+'!'))
})
Also, I found that my request body is parsed strange on the server when it`s come from node client and it is parsed correctly when it's coming from postman.
request body from nodejs axios client:
{ '{"username":"gefalko","password":"mypass"}': '' }
request body from postman client:
{"username":"gefalko","password":"mypass"}
Try this format :
var qs = require('qs');
axios.post('/foo', qs.stringify({ 'bar': 123 } , config);

Rethinkdb query always returns null Eventhough data is existed?

I am new to rethinkDB,I am trying to find data by username using filter function.
But rethinkDB returns null eventhough data existed.
//Define Your Api//Define Your Api
import express from 'express';
import r from 'rethinkdb';
const router = express.Router();
router.post('/users',(req,res)=>{
let username = req.body.data.username;
let password = req.body.data.password;
console.log(username,password);
r.connect({db:"image"}).then((conn) => {
r.table("users").filter({username:"arfo"}).run(conn,function (err, data) {
console.log(data) //null
})
})
});
export default router
Updated
it returns me a bunch of data like this do i have to manipulate this data
Cursor {
_type: 3,
_eachCb: [Function],
_conn:
TcpConnection {
host: 'localhost',
port: 28015,
db: 'image',
authKey: '',
timeout: 20,
ssl: false,
outstandingCallbacks: {},
nextToken: 2,
open: true,
closing: false,
buffer: <Buffer >,
_events: {},
_eventsCount: NaN,
_closePromise: null,
rawSocket:
Socket {
connecting: false,
_hadError: false,
_handle: [Object],
_parent: null,
_host: 'localhost',
_readableState: [Object],
readable: true,
domain: null,
_events: [Object],
_eventsCount: 7,
_maxListeners: undefined,
_writableState: [Object],
writable: true,
allowHalfOpen: false,
destroyed: false,
_bytesDispatched: 325,
_sockname: null,
_pendingData: null,
_pendingEncoding: '',
server: null,
_server: null,
user: 'admin',
password: '',
read: [Function],
_consuming: true } },
_token: 1,
_opts: {},
_root: { [Function] args: [ [Object], [Object] ], optargs: {} },
_responses: [ { t: 2, r: [Object], n: [] } ],
_responseIndex: 0,
_outstandingRequests: 0,
_iterations: 0,
_endFlag: true,
_contFlag: false,
_closeAsap: false,
_cont: null,
_cbQueue: [],
_closeCb: null,
_closeCbPromise: null,
next: [Function] }
From the RethinkDB docs, it looks like run returns (err, data). For example (from the docs):
r.table('marvel').run(conn, function(err, cursor) {
cursor.each(console.log);
})
So if you update your code to:
r.table("users").filter({username:"arfo"}).run(conn,function (err, data) {
console.log(data)
})
Then it should remove the null log that you were seeing.
I'm no RethinkDB expert, but from the docs it looks like if you want to get the data from the response then you can call toArray on the cursor:
r.table("test").run( conn, function(error, cursor) {
cursor.toArray( function(error, results) {
console.log(results) // results is an array of documents
})
})

Resources