ElasticSearch-js { body } is undefined - node.js

I am getting this error when running a AWS lambda function to push data into an Elasticsearch instance
I can get it to run if I manually remove the { body } from the node modules, but I can't find why it keeps erroring on that.
my code
client.helpers.bulk({
datasource: docs,
onDocument(doc) {
return {
index: { _index: index , _id: doc.id },
body: doc.body
}
},
onDrop(doc) {
console.log("failed to index ", doc.key);
},
retries: 5,
flushBytes: 1000000,
wait: 10000
})
error
{
"errorType": "Runtime.UnhandledPromiseRejection",
"errorMessage": "TypeError: Cannot destructure property 'body' of 'undefined' as it is undefined.",
"reason": {
"errorType": "TypeError",
"errorMessage": "Cannot destructure property 'body' of 'undefined' as it is undefined.",
"stack": [
"TypeError: Cannot destructure property 'body' of 'undefined' as it is undefined.",
" at /var/task/node_modules/#elastic/elasticsearch/lib/Helpers.js:679:81"
]
},
"promise": {},
"stack": [
"Runtime.UnhandledPromiseRejection: TypeError: Cannot destructure property 'body' of 'undefined' as it is undefined.",
" at process.<anonymous> (/var/runtime/index.js:35:15)",
" at process.emit (events.js:314:20)",
" at process.EventEmitter.emit (domain.js:483:12)",
" at processPromiseRejections (internal/process/promises.js:209:33)",
" at processTicksAndRejections (internal/process/task_queues.js:98:32)"
]
}

I was also getting this error when referencing #opensearch-project/opensearch (which is an elasticsearch-js client fork) and using the client.helpers.bulk helper. That was in conjunction with aws-elasticsearch-connector for implementing AWS SigV4 signed API requests.
The error message was as follows:
TypeError: Cannot destructure property 'body' of 'undefined' as it is undefined.
at node_modules/#opensearch-project/opensearch/lib/Helpers.js:704:93
It was quite annoying and I was not in the mood for implementing my own OpenSearch client and interacting with the APIs directly, so I dig deeper and found the issue.
How can one reproduce the bug?
I created an isolated test to illustrate the problem. Hopefully it's easily reproducible this way.
import { Client } from '#opensearch-project/opensearch';
import * as AWS from 'aws-sdk';
// My fork of https://www.npmjs.com/package/aws-elasticsearch-connector capable of signing requests to AWS OpenSearch
// #opensearch-project/opensearch is not yet capable of signing AWS requests
const createAwsElasticsearchConnector = require('../modules/aws-oss-connector');
const domain =
'PUT_YOUR_DOMAIN_URL_HERE.es.amazonaws.com';
const index = 'YOUR_TEST_INDEX_NAME';
const bootstrapOSSClient = (): Client => {
const ossConnectorConfig = createAwsElasticsearchConnector(AWS.config);
const client = new Client({
...ossConnectorConfig,
node: `https://${domain}`,
});
return client;
};
const main = async (): Promise<void> => {
try {
console.info('Starting processing');
// TEST DEFINITION
const input = [
{ id: '1', name: 'test' },
{ id: '2', name: 'test 2' },
];
const client = bootstrapOSSClient();
const response = await client.helpers.bulk({
datasource: input,
onDocument(doc: any) {
console.info(`Processing document #${doc.id}`);
return {
index: { _index: index, _id: doc.id },
};
},
});
console.info(`Indexed ${response.successful} documents`);
// END TEST DEFINITION
console.info('Finished processing');
} catch (error) {
console.warn(`Error in main(): ${error}`);
}
};
try {
main().then(() => {
console.info('Exited main()');
});
} catch (error) {
console.warn(`Top-level error: ${error}`);
}
and the result was
$ npx ts-node ./.vscode/test.ts
Starting processing
Processing document #1
Processing document #2
(node:39232) UnhandledPromiseRejectionWarning: TypeError: Cannot destructure property 'body' of 'undefined' as it is undefined.
at D:\Development\eSUB\Coronado\git\platform\node_modules\#opensearch-project\opensearch\lib\Helpers.js:704:93
(Use `node --trace-warnings ...` to show where the warning was created)
(node:39232) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 1)
(node:39232) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
Indexed 2 documents
Finished processing
Exited main()
Stepping through the code I am able to intercept a single call to node_modules/#opensearch-project/opensearch/lib/Helpers.js:704:93 where
client.bulk() is called
which calls bulkApi() in \opensearch\api\api\bulk.js and returns successfully
await finish() is called in \opensearch\lib\Helpers.js:559
inside \opensearch\lib\Transport.js a call to prepareRequest() is made, ending with return transportReturn
this ends up in request():177 calling
return p.then(onFulfilled, onRejected)
with p being null at that time. That resulted my callback in the AWS Transport class responsible for signing requests to callback to the Helper.js tryBulk() with second parameter undefined, resulting in the Cannot destructure property 'body' error.
What is the expected behavior?
Transport.js implementation of the request should obviously not result in a null p promise issue when callback is passed in the request() call. I logged a bug in the opensearch-js repository.
Workaround
At least for me, this looks to be a problem only when using custom AWS signed requests connector implementation. If your case is similar, a quick workaround involves modifying that implementation Transport class. Here is a quick and dirty hotfix that's specific to aws-elasticsearch-connector.
You need to modify AmazonTransport.js from
class AmazonTransport extends Transport {
request (params, options = {}, callback = undefined) {
...
// Callback support
awaitAwsCredentials(awsConfig)
.then(() => super.request(params, options, callback))
.catch(callback)
}
to
// Callback support
// Removed .then() chain due to a bug https://github.com/opensearch-project/opensearch-js/issues/185
// .then() was calling then (onFulfilled, onRejected) on transportReturn, resulting in a null value exception
awaitAwsCredentials(awsConfig).then();
try {
super.request(params, options, callback);
} catch (err) {
callback(err, { body: null });
}

Related

NestJS - Microservices - Kafka Exception Handling

I'm using NestJS to implement a microservice architecture, I'm using CLIENT app using NestJS,
The client app receives a rest request and sends to Kafka to get the result
try {
const pattern = 'findDoctors';
const payload = body;
const doctors = await lastValueFrom(
this.client.send(pattern, payload).pipe(timeout(50000)),
);
return doctors;
} catch (e) {
console.log(e);
throw new Error(e);
}
And in the microservice side (Hybrid Application for now, will remove the rest apis later)
#MessagePattern('findDoctors')
findDoctors(#Payload() message): any {
return this.doctorService.searchForDoctors(message.value);
}
async searchForDoctors(data): Promise<any[]> {
this.logger.info('Started search for doctors job');
throw 'Not Found';
}
After i throw the exception i get in the logs
node:17720) UnhandledPromiseRejectionWarning: TypeError [ERR_INVALID_ARG_TYPE]: The first argument must be of type string or an instance of Buffer, ArrayBuffer, or Array or an Array-like Object. Received an instance of Object
at Function.from (buffer.js:330:9)
at ServerKafka.assignErrorHeader (C:\Users\Desktop\Projects\node_modules\#nestjs\microservices\server\server-kafka.js:137:73)
at ServerKafka.sendMessage (C:\Users\Desktop\Projects\node_modules\#nestjs\microservices\server\server-kafka.js:119:14)
at C:\Users\Desktop\Projects\node_modules\#nestjs\microservices\server\server-kafka.js:81:31
at C:\Users\Desktop\node_modules\#nestjs\microservices\server\server.js:46:31
at processTicksAndRejections (internal/process/task_queues.js:79:11)
(node:17720) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 3)
(node:17720) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
and the client side just waits to timeout and never receive an exception response from the micro service
Tried using RpcException but it's the same
Found the answer
used
return new RpcException('not found');
instead of
throw new RpcException('not found')
throwing the exception needs an exception filter to catch it
#Catch(RpcException)
export class ExceptionFilter implements RpcExceptionFilter<RpcException> {
catch(exception: RpcException, host: ArgumentsHost): Observable<any> {
return throwError(exception.getError());
}
}
and in the client side you can catch the error when using filters and return a normal http exception, or use filters on that too
#Post('/search')
async findAll(#Body() body) {
console.log('Sending kafka msg');
try {
const doctors = await this.doctorService.findDoctors(body);
return doctors;
} catch (e) {
console.log(e)
throw new HttpException({
status: '500',
error: e.message,
}, 500)
}
}

Why am I having trouble displaying and deleting in Mongo using Prisma (React app)?

I use Node, Express, React, Mongo and Prisma to import a csv file in the database, display it on the frontend and delete all records in the db. It worked with one record and so I assumed it would work with the rest of the csv file (1000 records). But I get an error:
Invalid `prisma.movie.findMany()` invocation:
Error occurred during query execution:
ConnectorError(ConnectorError { user_facing_error: None, kind: RawError { code: "unknown", message: "Command failed (CursorNotFound): cursor id 124425195753416376 not found)" } })
(node:2171) UnhandledPromiseRejectionWarning: Error:
Invalid `prisma.movie.deleteMany()` invocation:
Error occurred during query execution:
ConnectorError(ConnectorError { user_facing_error: None, kind: RawError { code: "unknown", message: "Command failed (CursorNotFound): cursor id 4391617472265441923 not found)" } })
at cb (/Users/nwsursock/Sites/test-algot/backend/node_modules/#prisma/client/runtime/index.js:36378:17)
at runMicrotasks ()
at processTicksAndRejections (internal/process/task_queues.js:93:5)
at async exports.deleteRequest (/Users/nwsursock/Sites/test-algot/backend/src/controllers/movie.controller.js:49:3)
(node:2171) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 2)
My code is rather simple. I'm using the Prisma API in REST endpoints.
const { PrismaClient } = require("#prisma/client");
const prisma = new PrismaClient();
exports.createRequest = async (req, res) => {
const movie = req.body.movie;
console.log("============> importing", movie);
const data = {
name: movie.Name,
genre: movie.Genre,
descr: movie.Description,
director: movie.Director,
actors: movie.Actors,
year: movie.Year,
runtime: Number(movie["Runtime (Minutes)"]),
rating: Number(movie.Rating),
votes: Number(movie.Votes),
revenue: Number(movie["Revenue (Millions)"]),
score: Number(movie.Metascore),
};
const result = await prisma.movie.create({ data });
console.log("============> imported", result);
res.status(201).json({ message: "Movie correctly added!" });
};
exports.readRequest = async (req, res) => {
try {
const movies = await prisma.movie.findMany();
res.status(200).json(movies);
} catch (e) {
console.log("======> Error:", e.message);
}
};
exports.deleteRequest = async (req, res) => {
await prisma.movie.deleteMany({});
res.status(202).json({ message: "Table deleted!" });
};
It's a version problem. You have to downgrade to Prisma 2.26. Above, the bug appears. https://github.com/prisma/prisma/issues/8389

Mock fetch in Jest tests throwing “invalid json response” and “Unhandled promise rejection” errors

I’m trying to do unit tests for some of my redux-saga generators and am getting a couple of errors I’m not sure how to resolve. I’m using create-react-app, so my testing suite is Jest and Enzyme.
A basic example:
Setup: src/setupTests.js
import 'jest-enzyme'
import { configure } from 'enzyme'
import Adapter from 'enzyme-adapter-react-16'
global.fetch = require('jest-fetch-mock')
configure({
adapter: new Adapter(),
automock: false,
collectCoverageFrom: [
'<rootDir>/src/**/*.js',
'!<rootDir>/src/**/*.stories.js',
'!<rootDir>/node_modules/',
'!<rootDir>/src/index.js',
],
coverageThreshold: {
global: {
branches: 90,
functions: 90,
lines: 90,
statements: 90,
},
},
verbose: true,
})
Saga: src/store/sagas/api-saga.js
import { takeEvery, put } from 'redux-saga/effects'
import {
API_ERRORED,
DATA_LOADED,
DATA_REQUESTED,
} from '../constants/action-types'
export function* workerSaga() {
try {
const payload =
yield fetch('https://jsonplaceholder.typicode.com/posts')
.then(response => response.json())
yield put({
type: DATA_LOADED,
payload,
})
} catch (e) {
yield put({
type: API_ERRORED,
payload: false,
})
}
}
export default function* watcherSaga() {
yield takeEvery(
DATA_REQUESTED,
workerSaga,
)
}
Saga Test: src/store/sagas/api-saga.test.js
import { put, takeEvery } from 'redux-saga/effects'
import watcherSaga, { workerSaga } from './api-saga'
import {
API_ERRORED,
DATA_LOADED,
DATA_REQUESTED,
} from '../constants/action-types'
describe('saga workers', () => {
test('should dispatch action "DATA_LOADED" with result from fetch API',
() => {
const articles = 'Some content'
const mockResponse = {
articles,
}
const generator = workerSaga()
generator.next()
expect(generator.next(mockResponse).value)
.toEqual(
put({
type: DATA_LOADED,
payload: {
articles,
},
})
)
expect(generator.next().done).toBeTruthy()
})
})
The errors I’m receiving:
(node:2009) UnhandledPromiseRejectionWarning: FetchError: invalid json response body at undefined reason: Unexpected end of JSON input
(node:2009) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 2)
(node:2009) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
(node:2009) UnhandledPromiseRejectionWarning: FetchError: invalid json response body at undefined reason: Unexpected end of JSON input
(node:2009) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 4)
I thought introducing jest-fetch-mock would help resolve some of these issues, but it doesn’t seem so. The tests pass, but these errors persist.
What am I missing?
Versions
redux#4.0.4
redux-saga#1.0.5
enzyme#3.10.0
jest#24.7.1
You'll need to set up jest-fetch-mock to return a value:
Something like:
describe('saga workers', () => {
test('should dispatch action "DATA_LOADED" with result from fetch API',
() => {
const articles = 'Some content'
const mockResponse = {
articles,
}
// configure the mockResponse here:
fetch.mockResponse(mockResponse);
const generator = workerSaga()
generator.next()
expect(generator.next().value)
.toEqual(
put({
type: DATA_LOADED,
payload: {
articles,
},
})
)
expect(generator.next().done).toBeTruthy()
})
})
See https://github.com/jefflau/jest-fetch-mock#api

Nothing happen inside of an async function (send request with easysoap)

I am new in node.js, and I am experimenting things since a few days already.
Today, I have tried to send a XML request to an API, with the use of easysoap-request.
It worked perfectly, but I would have had to create an XML file for each different query, so I tried with easysoap. Here my code:
const EasySoap = require('easysoap');
console.log("test");
(async () => {
const params = {
host : 'https://comeapi.com',
path : '/dir/soap',
wsdl : '/dir/wsdl',
headers: [{
'user-agent': 'Request-Promise',
'Content-Type': 'text/xml',
}]
}
var soapClient = EasySoap(params);
soapClient.call({
method :'one_methode',
attributes: {
xmlns: 'https://someapi.com'
},
params: {
'api' : {
'authentication' : {
'login' : 'mylogin',
'password' : 'mypassword'
},
'params' : {
'another_params' : {
'name' : 'Brian',
}
}
}
}
}).then((callResponse) => {
console.log(callResponse.data); // response data as json
console.log(callResponse.body); // response body
console.log(callResponse.header); //response header
}).catch((err) => {
throw new Error(err);
});
console.log("test2");
});
console.log("test3");
When I'm starting my file with the node command, it's only shows me "test" and "test 3" in the terminal, instead of the response of the API.
I do not understand the problem in my program because I have already used the "(async () => {" function in previous programs, and that rather well worked.
Thanks for you're help. ^^
Edit: I added the missing part in my code and now there is something new. It's an error, and I don't understand it...
(node:10264) UnhandledPromiseRejectionWarning: Error: Error: no wsdl/xml response
at soapClient.call.then.catch (C:\Users\user\Documents\src\script.js:40:15)
at process._tickCallback (internal/process/next_tick.js:68:7)
(node:10264) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
(node:10264) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
Is this a problem with the .catch() ? Can someone explain me ?
Thanks
Your function is only defined but never called. Call your function at the end of the definition
(async () => {
....
console.log("test2");
})(); // call this function by adding this parenthesis
This is called a IFFY(Immediately-Invoked Function Expression) function in javascript
If you don't want to use a IFFY name your function and call it, like this
const f = async () => {
....
console.log("test2");
}
f()
Your async function needs to be called. Currently you are only declaring a function. To execute it, you need to replace the line before console.log("test3"); by })();

UnhandledPromiseRejectionWarning: TypeError: cb is not a function in loopback.js

I have the following code:
Orders.js
'use strict';
var OrderService = require('../services/OrderService');
module.exports = function(Orders) {
var orderService = new OrderService(Orders);
Orders.history = function(data, cb) {
console.log("getting history");
orderService.getHistory(data, cb)
.catch(err => cb(err));
};
Orders.remoteMethod('history', {
http: { verb: 'get', path: '/:token/history' },
accepts: [
{ arg: "token", type: "string", required: true },
{ arg: "base_token", type: "string", required: true }
],
returns: { type: 'object', root: true }
});
};
Orderservice.js
function OrderService(Orders){
}
OrderService.prototype.getHistory = async function(token, baseToken, callback){
<some operation>
callback(null, this.validatorService.finalize(buyResult));
}
When I hit this API, I get the following error
node:1996) UnhandledPromiseRejectionWarning: TypeError: cb is not a function
at orderService.getHistory.catch.err (/usr/app/server/models/orders.js:12:18)
at processTicksAndRejections (internal/process/next_tick.js:81:5)
(node:1996) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
| (node:1996) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
I have similar code for other models and services, what am I missing?
When you define a remoteMethod the amount of arguments must always be equal to a number of arguments defined in the accepts property of your remoteMethod plus one which is cb. In your case there are two arguments defined in the accepts property, so the function should look like:
Orders.history = function(token, base_token, cb) {
console.log("getting history");
orderService.getHistory(token, cb)
.catch(err => cb(err));
};
I would also recommend you to change your Orders.history to an async function and move away from callbacks completely. Loopback supports async functions/promises starting from version 2. The function can be defined as following:
Orders.history = async function(token, base_token) {
console.log("getting history");
return orderService.getHistory(token); // must return a promise
};
It may require a bit of code refactoring on your side but it allows you to write a cleaner code and you do not have to worry about the exceptions handling all the time (Loopback supports it out of the box for async functions).

Resources