Elastic Search Node.js client - Routing Error - node.js

We have elastic hosted on GCP. I'm getting an error when I try to simply post a document. I'm using their node.js package, and I'm stuck with the following error:
PS C:\Projects\foo> node --experimental-modules --unhandled-rejections=strict app.js
(node:19356) ExperimentalWarning: The ESM module loader is experimental.
(node:19356) ExperimentalWarning: Conditional exports is an experimental feature. This feature could change at any time
Posting to Elastic => 5f91dfb0c64004000aab6c9b
C:\Projects\foo\node_modules\#elastic\elasticsearch\lib\Transport.js:257
const error = new ResponseError(result)
^
ResponseError: Response Error
at IncomingMessage.<anonymous> (C:\Projects\foo\node_modules\#elastic\elasticsearch\lib\Transport.js:257:25)
at IncomingMessage.emit (events.js:323:22)
at endReadableNT (_stream_readable.js:1204:12)
at processTicksAndRejections (internal/process/task_queues.js:84:21) {
name: 'ResponseError',
meta: {
body: { error: 'Routing Error. The path you have requested is invalid.' },
statusCode: 404,
headers: {
'content-type': 'application/json;charset=utf-8',
server: 'Jetty(9.4.30.v20200611)',
'x-cloud-request-id': 'srCq9DMFQVWuGsdXxgWhjA',
'x-content-type-options': 'nosniff',
'x-found-handling-cluster': '[Removed]',
'x-found-handling-instance': 'instance-0000000001',
'x-frame-options': 'SAMEORIGIN',
'x-request-id': 'a2696b33-e4dc-4dfc-a8b1-f7ec17906ff7',
'x-runtime': '0.010689',
'x-xss-protection': '1; mode=block',
date: 'Mon, 09 Nov 2020 21:28:28 GMT',
'content-length': '66'
},
meta: {
context: null,
request: [Object],
name: 'elasticsearch-js',
connection: [Object],
attempts: 0,
aborted: false
}
}
}
I have the client set up as follows
const client = new Client({
node: 'https://[REMOVED].ent-search.us-central1.gcp.cloud.es.io',
auth: {
apiKey: 'Bearer private-[REMOVED]'
}
});
Then I attempt to send a json file as an array to Elastic.
client.helpers.bulk({
datasource: posts,
onDocument(doc) {
return {
create: {_index: 'my-index', _id: elasticPost.id}
};
}
});
Update:
The JSON names MUST be lowercase. For example:
Doesn't Work:
{
"Id": 123456
}
Works:
{
"id": 123456
}
Another thing may have to do with needing the cloud ID from Elastic, I'm not sure if this is required as well, but the lowercase allowed me to upload our document directly into Elastic.

I think you have one too many create in the command you return from onDocument. The command you can return is described here:
So, by removing one create layer, it should work:
client.helpers.bulk({
datasource: posts,
onDocument(doc) {
return {
create: {_index: 'my-index', _id: elasticPost.id}
};
}
});
UPDATE:
Looking at the host name *.ent-search.*, it looks like you're using the elasticsearch client to try to connect to the Enterprise search backend, that cannot work as the latter doesn't support the _bulk API.
If you connect to an AppSearch backend, you can't use the the _bulk endpoint (i.e. client.helpers.bulk()). Instead, you need to add documents through the AppSearch Documents API. Feel free to share more info on what you're trying to achieve.

The JSON names MUST be lowercase. For example:
Doesn't Work:
{
"Id": 123456,
"userName": "Dave2118"
}
Works:
{
"id": 123456,
"username": "Dave2118"
}

Related

How to properly send a GraphQL update request using Axios?

I created an application using AWS Amplify, and I want to create an endpoint in an API function that will mutate a field in GraphQL. Since its a nodejs API function, I cannot use the recommended libraries from the AWS documentation which use ES6, since the functions can only use ES5. Therefore I need to use Axios.
I created a graphql query:
const query = /* GraphQL */ `mutation updatePublication($id: ID!, $keywords: String) {
updatePublication(id: $id, keywords: $keywords){
id
keywords
}
}`
Next, I created the Axios request based on this StackOverflow question.
const data = await axios.post(
process.env.API_APPNAME_GRAPHQLAPIENDPOINTOUTPUT,
{
query: query,
variables: {
id: variableWithID,
keywords: "updated keywords!"
}
},
{
headers: {
'Content-Type': 'application/json',
'x-api-key': process.env.API_APPNAME_GRAPHQLAPIKEYOUTPUT
}
}
)
When I run the query, I get a status 200 from the server with the following errors:
data: null,
errors: [
{
path: null,
locations: [Array],
message: "Validation error of type MissingFieldArgument: Missing field argument input # 'updatePublication'"
},
{
path: null,
locations: [Array],
message: "Validation error of type UnknownArgument: Unknown field argument id # 'updatePublication'"
},
{
path: null,
locations: [Array],
message: "Validation error of type UnknownArgument: Unknown field argument keywords # 'updatePublication'"
}
]
}
Can anyone advise on what this means?

NotFound error when calling flights date API

I have been using NodeJS library for querying the price of the chepeast flight for a route, for next 60 days. Even after switching to production environment, the API throws 404 error (details mentioned below) for some common routes like SFO to YYC.
Do let me know how I can resolve this.
NotFoundError {
response: Response {
headers: {
date: 'Tue, 19 Oct 2021 17:09:32 GMT',
'content-type': 'application/vnd.amadeus+json',
'content-length': '263',
connection: 'close',
'ama-internal-message-version': '14.1',
'ama-request-id': '00010UI9218IBV',
'ama-gateway-request-id': 'rrt-0b7b1036c139b8050-a-eu-4707-50043169-1',
'access-control-allow-headers': 'origin, x-requested-with, accept, Content-Type, Authorization',
'access-control-max-age': '3628800',
'access-control-allow-methods': '*',
server: 'Amadeus',
'access-control-allow-origin': '*'
},
statusCode: 404,
request: Request {
host: 'api.amadeus.com',
port: 443,
ssl: true,
scheme: 'https',
verb: 'GET',
path: '/v1/shopping/flight-dates',
params: [Object],
queryPath: '/v1/shopping/flight-dates?origin=SFO&destination=YYC&departureDate=2021-10-19%2C2021-12-
18&oneWay=true&viewBy=DATE',
bearerToken: '[REDACTED]',
clientVersion: '5.7.0',
languageVersion: '14.16.1',
appId: null,
appVersion: null,
headers: [Object]
},
body: '{"errors":[{"status":404,"code":6003,"title":"ITEM/DATA NOT FOUND OR DATA NOT EXISTING","detail":"No price result found"},{"status":404,"code":6003,"title" :"ITEM/DATA NOT FOUND OR DATA NOT EXISTING","detail":"No price results found for input combined criteria"}]}',
result: { errors: [Array] },
data: undefined,
parsed: true
},
description: [
{
status: 404,
code: 6003,
title: 'ITEM/DATA NOT FOUND OR DATA NOT EXISTING',
detail: 'No price result found'
},
{
status: 404,
code: 6003,
title: 'ITEM/DATA NOT FOUND OR DATA NOT EXISTING',
detail: 'No price results found for input combined criteria'
}
],
code: 'NotFoundError'
}
My code to query the data looks something like this:
const Amadeus = require("amadeus");
var client = new Amadeus({
hostname: "production",
clientId: FLIGHT_SEARCH_API_KEY,
clientSecret: FLIGHT_SEARCH_API_SECRET,
});
const response = await client.shopping.flightDates.get({
origin,
destination,
departureDate: `${currentDate},${lastDate}`,
oneWay: true,
viewBy: "DATE",
});
The Flight Inspiration Search & Flight Cheapest Date Search APIs are built on top of a pre-computed cache. The APIs compute every day the most trending options based on past searches and bookings and fill the cache, which means that the cache is dynamic. If you need to get access to a full inventory of Amadeus you need to use the live Flight Offers Search API.

Securing Cloud Functions using IAM + NodeJS application running on AppEngine

I need some help with example if possible of code changes to be done on my NodeJS server code running on AppEngine in order to allow it to securely access my cloud fucntions.
I created a cloud function and I have a public URL for it. I then went ahead and removed allUser access in the Permissions' tab of the function. Under Service account I have App Engine Default Service account` selected.
My server on AppEngine was calling the public URL of the CF and when `allUser' permission was there, everything was hunky dory. But when it was removed, I started getting 403 error.
I need help with code changes on NodeJS side to be able to invoke the cloud fucntion again please.
My CF and App engine are in the same project and in the same region.
My server code is as follows using an https library to make the post request.
const checkingData = JSON.stringify({
'check' : 123
})
const checkingOptions = {
hostname: MY_CLOUD_PUBLIC_URL,
port: 443,
timeout: 5000,
path: MY_CLOUD_URL_PATH,
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': checkingData.length,
}
}
const checkRequest = https.request(checkingOptions, checkD => {
if (checkD.statusCode==200) { // OK?
checkD.on('data', d => {
// Do something useful with the data
})
})
checkRequest.write(checkingData);
checkRequest.end();
I have been trying to find an answer for this for days now and started having migranes because of this. Any help with example code would be much appreciated. Many thanks!
EDIT
I can see the token now! (Yayyy!)
I changed my checkingOptions to work with request-promise in the following way:
const checkingOptions = {
uri: 'https://'+process.env.CLOUD_URL+process.env.CHECK,
port: 443,
timeout: 5000,
body:checkingData,
json: true,
// path: process.env.CHECK,
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': checkingData.length,
}
}
I am getting the following errors:
Unhandled rejection StatusCodeError: 401 - "\n<html><head>\n<meta http-equiv=\"content-type\" content=\"text/html;charset=utf-8\">\n<title>401 Unauthorized</title>\n</head>\n<body text=#000000 bgcolor=#ffffff>\n<h1>Error: Unauthorized</h1>\n<h2>Your client does not have permission to the requested URL <code>/check</code>.</h2>\n<h2></h2>\n</body></html>\n"
2021-02-27 19:38:01 default[20210227t192944] at new StatusCodeError (/workspace/node_modules/request-promise-core/lib/errors.js:32:15)
2021-02-27 19:38:01 default[20210227t192944] at Request.plumbing.callback (/workspace/node_modules/request-promise-core/lib/plumbing.js:104:33)
2021-02-27 19:38:01 default[20210227t192944] at Request.RP$callback [as _callback] (/workspace/node_modules/request-promise-core/lib/plumbing.js:46:31)
2021-02-27 19:38:01 default[20210227t192944] at Request.self.callback (/workspace/node_modules/request/request.js:185:22)
2021-02-27 19:38:01 default[20210227t192944] at Request.emit (events.js:314:20)
2021-02-27 19:38:01 default[20210227t192944] at Request.<anonymous> (/workspace/node_modules/request/request.js:1154:10)
2021-02-27 19:38:01 default[20210227t192944] at Request.emit (events.js:314:20)
2021-02-27 19:38:01 default[20210227t192944] at IncomingMessage.<anonymous> (/workspace/node_modules/request/request.js:1076:12)
2021-02-27 19:38:01 default[20210227t192944] at IncomingMessage.emit (events.js:326:22)
2021-02-27 19:38:01 default[20210227t192944] at endReadableNT (_stream_readable.js:1241:12)
Do I need a middleware in my cloud function as well? My cloud function looks like the follow:
exports.check = functions.https.onRequest((req, res) => {
console.log('----CHECKING----');
res.status(200).send('Hello from checking');
})
IAM ROLES:
CLOUD FUNCTION > PERMISSIONS TAB
You have a great example in the documentation. If you want I adapt it to your code, it could look like to this
// Make sure to `npm install --save request-promise` or add the dependency to your package.json
const request = require('request-promise');
// Set up metadata server request
// See https://cloud.google.com/compute/docs/instances/verifying-instance-identity#request_signature
const metadataServerTokenURL = 'http://metadata/computeMetadata/v1/instance/service-accounts/default/identity?audience=';
const tokenRequestOptions = {
uri: metadataServerTokenURL + MY_CLOUD_PUBLIC_URL,
headers: {
'Metadata-Flavor': 'Google'
}
};
const checkingData = JSON.stringify({
'check' : 123
})
const checkingOptions = {
uri: MY_CLOUD_PUBLIC_URL, //!!!changed here!!!
port: 443,
timeout: 5000,
path: MY_CLOUD_URL_PATH,
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': checkingData.length,
}
}
request(tokenRequestOptions).then((token) => {
request(checkingOptions).auth(null, null, true, token).then((response) => { //!!!changed here!!!
checkD.on('data', d => {
// Do something useful with the data
})
})
.catch((error) => {
res.status(400).send(error);
}); => {
})
checkRequest.write(checkingData);
checkRequest.end();
Don't forget to add the role role/cloudfunctions.invoker to the App Engine default service account, either at the project level or at the Cloud Functions level.
EDIT 1
Correct. request-promise has been deprecated for year. What alternative? I absolutely don't know because NodeJS hurts me (as I said in the comment).
As a lazy man, I found an alternative. I found the request-promise in the Cloud Run documentation. But you have to know that Cloud Run and Cloud Functions are very closed (they share the same underlying platform). I take my chance with Cloud Functions authentication documentation and bingo! There is an example with node-fetch
const fetch = require('node-fetch');
const MY_CLOUD_PUBLIC_URL = '....'
const metadataServerTokenURL = 'http://metadata/computeMetadata/v1/instance/service-accounts/default/identity?audience=';
// Fetch the token
const tokenResponse = await fetch(metadataServerTokenURL + MY_CLOUD_PUBLIC_URL, {
headers: {
'Metadata-Flavor': 'Google',
},
});
const token = await tokenResponse.text();
console.log(token)
const checkingData = JSON.stringify({
'check' : 123
})
// Provide the token in the request to the receiving function
try {
const functionResponse = await fetch(MY_CLOUD_PUBLIC_URL, {
method: 'post',
body: checkingData,
headers: {
'Content-Type': 'application/json',
Authorization: `bearer ${token}`},
});
console.log(await functionResponse.text());
} catch (err) {
console.error(err);
}
Add your check functions and it should work now!

Elastic search gives Bad request for ping

Code in elasticsearch.js file
function es() {
throw new Error('Looks like you are expecting the previous "elasticsearch" module. ' +
'It is now the "es" module. To create a client with this module use ' +
'`new es.Client(params)`.');
}
es.Client = require('./lib/client');
es.ConnectionPool = require('./lib/connection_pool');
es.Transport = require('./lib/transport');
es.errors = require('./lib/errors');
module.exports = es;
var elasticsearch = require('elasticsearch')
var client = new es.Client({
host: 'localhost:9200',
log: 'trace',
})
// Ping the cluster
client.ping({
requestTimeOut: 30000,
},
function(error){
if(error) {
console.log(error)
console.error("elasticsearch cluster is down!")
}
else {
console.log("All is well")
}
})
and I am running elastic search locally with command $bin/elasticsearch
but when I do $node elasticsearch.js it gives the error saying
Elasticsearch INFO: 2018-01-22T11:17:50Z
Adding connection to http://localhost:9200/
Elasticsearch DEBUG: 2018-01-22T11:17:50Z
starting request {
"method": "HEAD",
"requestTimeout": 3000,
"castExists": true,
"path": "/",
"query": {
"requestTimeOut": 30000
}
}
Elasticsearch TRACE: 2018-01-22T11:17:50Z
-> HEAD http://localhost:9200/?requestTimeOut=30000
<- 400
Elasticsearch DEBUG: 2018-01-22T11:17:50Z
Request complete
{ Error: Bad Request
at respond (/Users/ElasticSearchServer/node_modules/elasticsearch/src/lib/transport.js:307:15)
at checkRespForFailure (/Users/ElasticSearchServer/node_modules/elasticsearch/src/lib/transport.js:266:7)
at HttpConnector.<anonymous> (/Users/ElasticSearchServer/node_modules/elasticsearch/src/lib/connectors/http.js:159:7)
at IncomingMessage.bound (/Users/ElasticSearchServer/node_modules/elasticsearch/node_modules/lodash/dist/lodash.js:729:21)
at emitNone (events.js:91:20)
at IncomingMessage.emit (events.js:185:7)
at endReadableNT (_stream_readable.js:974:12)
at _combinedTickCallback (internal/process/next_tick.js:80:11)
at process._tickCallback (internal/process/next_tick.js:104:9)
status: 400,
displayName: 'BadRequest',
message: 'Bad Request',
path: '/',
query: { requestTimeOut: 30000 },
body: undefined,
statusCode: 400,
response: '',
toString: [Function],
toJSON: [Function] }
elasticsearch cluster is down!
If I try adding new index, delete index, check the health or search, it works fine and gives the appropriate result.
Can anyone help me to fix the issue? thanks in advance!
In the new JavaScript client every option that is not intended for Elasticsearch lives in a second object, your code should be updated as follows:
'use strict'
const { Client } = require('#elastic/elasticsearch')
const client = new Client({ node: 'http://localhost:9200' })
client.ping({}, { requestTimeout: 20000 }, (err, response) => {
...
})
In the response object other than body, statusCode, and headers, you will also find a warnings array and a meta object, which should help you debug issues.
In this case, warnings contained the following message: 'Client - Unknown parameter: "requestTimeout", sending it as query parameter'.

Azure Insert failed in database but query works

I am trying to do an Insert/replace :
insertOrReplaceEntity('myusertables', task, function(error)
it always goes to error code indicating that insertion did not happen.
How to debug this in Azure?
I am using the Azure emulator and have in the code:
var account = azure.ServiceClient.DEVSTORE_STORAGE_ACCOUNT;
var accountKey = azure.ServiceClient.DEVSTORE_STORAGE_ACCESS_KEY;
I get PUT failed with 403.
{ error:
{ [Error: Server failed to authenticate the request. Make sure the value of Authorization header is formed correctl
including the signature.]
code: 'AuthenticationFailed',
message: 'Server failed to authenticate the request. Make sure the value of Authorization header is formed correc
y including the signature.' },
response:
{ isSuccessful: false,
statusCode: 403,
body:
{ '#': [Object],
code: 'AuthenticationFailed',
message: [Object] },
headers:
{ 'content-length': '356',
'content-type': 'application/xml',
server: 'Microsoft-HTTPAPI/2.0',
date: 'Mon, 12 Nov 2012 20:57:10 GMT' },
md5: undefined } }
As Described here the storage emulator does not support Insert-Or-Replace Entity or Insert-Or-Merge Entity, known as upsert features. That's why when you use insertOrReplaceEntity in your code it return an error. If you have to verify the code, you may need to check it with the real Azure Table Storage.

Resources