Parse xml request body using loopback4 - node.js

I'm looking for an extension to existing body parsers.. I have a requirement to parse xml data using loopback4 node.. I have tried setting content-type to application/xml but it is giving me an unsupported content type error. xml is not supported. I did not find any examples in loopback4 documentation.
I have tried below code:
#post('/dashboard/parseXmlRequest/', {
responses: {
'200': {
description: 'parses the xml and sends the response',
content: {
'application/xml': {
schema: {
type: 'any'
}
}
},
},
},
})
async parseXmlRequest(
#requestBody({
content: {
'application/xml': {
schema: {type: 'object'},
},
},
})
data: object) {
try {
console.log("request : ", data);
return await this.myService.deviceResponse(body);
}
catch (err) {
console.log(err);
return err;
}
}
Can you please help.. thank you.

have you made any progress?
As workaround, I'm using text/plain instead xml;
#post('/data/import', {
responses: {
'200': {
description: 'Import XML',
content: {'application/json': {type: 'any' }},
},
},
})
async import(
#requestBody({
content: {
'text/plain': {
},
},
})
xml : string,
): Promise<string> {
return this.dataRepository.import(xml);
}
async import( xml: string) : Promise<string> {
try {
console.log("XML =>",xml);
const result = await xml2js.parseStringPromise(xml, {mergeAttrs: true});
const json = JSON.stringify(result, null, 4);
return json;
} catch (err) {
console.log(err);
return Promise.resolve(err);
}
}

Related

Node-orcaledb: execute() and executeMany() crash without error

I am building an api rest with node-oracledb, I can retrieve all kind of data but the program breaks every time I try to do an insert.
This is the generic method I use to get a connection from the pool and perform the query.
import oracledb from "oracledb";
export const executeQuery = async ({ query, binds, options, type, res }) => {
let connection = null;
try {
connection = await oracledb.getConnection();
} catch (error) {
console.log("Error al conectar OracleDB");
}
let result = null;
try {
result =
type === "insertOne"
? await connection.execute(query, binds, options)
: type === "insertMany"
? await connection.executeMany(query, binds, options)
: null;
console.log(result);
} catch (err) {
console.error("error", err.message);
res.status(500).json("Error recuperando datos");
} finally {
if (connection) {
try {
res.status(200).json(result.rows);
// Always release the connection back to the pool
await connection.close();
} catch (err) {
return console.error(err.message);
}
}
}
};
This is the controller method with which I am trying to insert a single record, in production the bind data would come from a post request.
insertOneExample: async (req, res) => {
const { items } = req.body;
const query = `MERGE INTO SCHEMA.TABLE USING dual ON (CODIGO_HOSPI = :CODIGO_HOSPI AND CENTRO_ID = :CENTRO_ID)
WHEN MATCHED THEN UPDATE SET PREV1 = :PREV1, PREV2 = :PREV2, PREV3 = :PREV3, PREV4 = :PREV4, PREV5 = :PREV5, PREV6 = :PREV6, PREV7 = :PREV7, PREV8 = :PREV8, PREV9 = :PREV9, PREV10 = :PREV10, PREV11 = :PREV11, PREV12 = :PREV12,
WHEN NOT MATCHED THEN INSERT (CODIGO_HOSPI, PREV1, PREV2, PREV3, PREV4, PREV5, PREV6, PREV7, PREV8, PREV9, PREV10, PREV11, PREV12, CENTRO_ID)
VALUES (:CODIGO_HOSPI, :PREV1, :PREV2, :PREV3, :PREV4, :PREV5, :PREV6, :PREV7, :PREV8, :PREV9, :PREV10, :PREV11, :PREV12, :CENTRO_ID)`
const options = {
autoCommit: true,
bindDefs: {
CODIGO_HOSPI: { type: oracledb.STRING, maxSize: 20 },
PREV1: { type: oracledb.NUMBER },
PREV2: { type: oracledb.NUMBER },
PREV3: { type: oracledb.NUMBER },
PREV4: { type: oracledb.NUMBER },
PREV5: { type: oracledb.NUMBER },
PREV6: { type: oracledb.NUMBER },
PREV7: { type: oracledb.NUMBER },
PREV8: { type: oracledb.NUMBER },
PREV9: { type: oracledb.NUMBER },
PREV10: { type: oracledb.NUMBER },
PREV11: { type: oracledb.NUMBER },
PREV12: { type: oracledb.NUMBER },
CENTRO_ID: { type: oracledb.STRING, maxSize: 10 },
},
};;
executeQuery({
query,
binds: {
CODIGO_HOSPI: "101",
PREV1: 52600,
PREV2: 870,
PREV3: 123,
PREV4: 564,
PREV5: 846,
PREV6: 625,
PREV7: 897,
PREV8: 124,
PREV9: 656,
PREV10: 456,
PREV11: 324,
PREV12: 212,
CENTRO_ID: "10346",
},
options,
type: "insertOne",
res,
});
}
When executing the method, the server crashes without any error message.
no error crash
*** sql statement is not the problem, it also crashes with a simple insert.
Try sending parameter values as strings instead of numbers, that fixed my issue.
Reference: https://github.com/oracle/node-oracledb/issues/1377#issuecomment-1346171847

Node.Js Elasticsearch Responding Blank _source

I have created one sample index using elasticsearch and node.js with below code setup.
const { Client } = require('#elastic/elasticsearch');
const { ELASTIC_SEARCH } = require('../config');
// Elastic Search Cloud Client Setup
const elasticClient = new Client({
cloud: { id: ELASTIC_SEARCH.CLOUDID },
auth: {
apiKey: ELASTIC_SEARCH.API_KEY
}
});
async function prepareIndex() {
const merchantIndexExists = await elasticClient.indices.exists({ index: 'index2' });
if (merchantIndexExists) return;
await elasticClient.indices.create({
index: 'index2',
body: {
mappings: {
dynamic: 'strict',
properties: {
company_name: { type: 'text' },
company_email: { type: 'keyword' },
name: { type: 'text' },
price: { type: 'scaled_float', scaling_factor: 10 },
created_date: { type: 'date' },
is_delete: { type: 'boolean', doc_values: false },
merchant: { type: 'keyword', index: 'true' }
}
}
}
});
}
After index creation i have added document with below code:
const { company_name, company_email, price } = req.body;
const response = await elasticClient.index({
index: 'index2',
document: {
company_email,
company_name,
price
}
});
Now when I'm calling search API from my kibana cloud console it's returning the exact search results with all the fileds. like
But when I'm hitting same search query via code in postman it's returning blank _source. Here is the search query with postman response
const response = await elasticClient.search({
index: 'index2',
query: {
match_all: {}
}
});
Can anyone please help me out of this?
When using the Node.js ElasticSearch client, you have to wrap the query into a body property and pass it to the search.
const response = await elasticClient.search({
index: 'index2',
body: {
query: {
match_all: {}
}
}
});

Recaptcha v3 Invalid Input Response

I'm having a problem when trying to apply recaptcha into my web app.
Basically, it's returning the error message: "invalid-input-response"
What could I be doing wrong?
Stack:
#nuxtjs/recaptcha 1.1.1
express-recaptcha 5.1.0
nuxt 2.15.8
node 16.15.9
Here is my configuration on front, I don't have certain about the recaptcha mode, if I should use base or enterprise.
nuxt.config.js
modules: [
'#nuxtjs/recaptcha',
],
recaptcha: {
hideBadge: true,
mode: 'base',
siteKey: 'MY_SITE_KEY',
version: 3,
size: 'normal',
},
On index I don't know if has any problem here
Based on docs, it's only do that
On my action I'm sending the token alongside my data on that format
{
token: 'asdadsadadasdas',
review: {...}
}
index.vue
async mounted() {
try {
await this.$recaptcha.init()
} catch (e) {
console.log(e);
}
},
methods: {
...mapActions({
getProduct: "getProduct",
postReview: "postReview",
}),
async submit() {
const postReviewToken = await this.$recaptcha.execute('postReview')
try {
await this.postReview({
token: postReviewToken,
productId: this.$route.params.productId,
review: {
title: this.review.title,
content: this.review.content,
},
});
this.getProduct({ productId: this.$route.params.productId });
this.review = {
title: "",
content: "",
};
} catch (error) {}
},
},
Node
And on my api I just added the middleware as docs require
import { RecaptchaV3 } from 'express-recaptcha/dist'
const recaptcha = new RecaptchaV3(
'MY_SITE_KEY',
'MY_SECRET_KEY'
)
routes.post('/product/:id/review', recaptcha.middleware.verify, async (request: Request, response: Response) => {
if (request.recaptcha?.error) {
return response.status(400).json({ message: request.recaptcha.error })
}
const review = await prisma.review.create({
data: {
productId: request.params.id,
title: request.body.review.title,
content: request.body.review.content,
},
select: {
id: true,
title: true,
content: true,
}
})
response.json({review});
});

Serverless Event object failed validation at createError

I am working on a serverless/nodejs12 project. The project deploys fine, but when I try to invoke the endpoint with postman I get the following error. I have browsed through many postings of similar errors but still failed to understand what's going on. Will appreciate any pointers.
Thank you
at createError (/var/task/src/handlers/webpack:/home/serverless-workspace/notification/node_modules/#middy/util/index.js:259:1)
at validatorMiddlewareBefore (/var/task/src/handlers/webpack:/home/serverless-workspace/notification/node_modules/#middy/validator/index.js:55:1)
at runMiddlewares (/var/task/src/handlers/webpack:/home/serverless-workspace/notification/node_modules/#middy/core/index.js:120:1)
at runRequest (/var/task/src/handlers/webpack:/home/serverless-workspace/notification/node_modules/#middy/core/index.js:80:1) {
details: [
{
instancePath: '/body',
schemaPath: '#/properties/body/type',
keyword: 'type',
params: [Object],
message: 'must be object'
}
]
createNotification.js
--------------------------
async function createNotification(event, context) {
const { title } = event.body;
const { destination } = event.body;
const { destinationType } = event.body
const notification = {
id: uuid(),
title,
destination,
destinationType,
status: 'OPEN',
createdAt: new Date().toISOString(),
}
try {
await dynamodb.put({
TableName: process.env.NOTIFY_TABLE_NAME,
Item: notification
}).promise();
} catch (error) {
console.error(error);
throw new createError.InternalServerError(error);
}
return {
statusCode: 200,
body: JSON.stringify(notification),
};
}
export const handler = commonMiddleware(createNotification)
.use(validator({ inputSchema: createNotificationSchema }));
and the schema
----------------------
const schema = {
type: 'object',
properties: {
body: {
type: 'object',
required: ['status'],
default: { status: 'OPEN' },
properties: {
status: {
default: 'OPEN',
enum: ['OPEN', 'CLOSED'],
},
},
},
},
required: ['body'],
};
export default schema;
You're getting the error must be object. I'm guessing your input looks like { event: { body: 'JSON string' } }. You'll need to use another middy middleware to parse the body prior to validating the input. Which middleware will depend on what AWS event it's expecting. Middy >3.0.0 supports all AWS events.

Abstract type Node must resolve to an Object type at runtime for field Root.node with value \"\",received \"null\"."

I am implementing a search feature with react and relay.
Below is my schema.js
var { nodeInterface, nodeField } = nodeDefinitions(
(globalId) => {
var { type, id } = fromGlobalId(globalId);
if (type === 'User') {
return getUser(id);
}else if (type === 'Post') {
return getPost(id);
}else if (type === 'Setting') {
return getSetting(id);
}
return null;
},
(obj) => {
if (obj instanceof User) {
return userType;
}else if (obj instanceof Post) {
return postType;
}else if (obj instanceof Setting) {
return settingType;
}
return null;
}
);
var postType = new GraphQLObjectType({
name: 'Post',
fields: {
_id: {
type: new GraphQLNonNull(GraphQLID)
},
createdAt: {
type: GraphQLString
},
id: globalIdField('Post'),
title: {
type: GraphQLString
},
color: {
type: GraphQLString
},
userId: globalIdField('User'),
username: {
type: GraphQLString,
resolve: (post) => getUserById(post.userId),
},
content: {
type: GraphQLString
},
images: {
type: postImageType,
description: "Post's main image links"
}
},
interfaces: [nodeInterface]
});
const {
connectionType: postConnection,
} = connectionDefinitions({name: 'Post', nodeType: postType});
var settingType = new GraphQLObjectType({
name: 'Setting',
fields: {
_id: {
type: new GraphQLNonNull(GraphQLID)
},
id: globalIdField('Setting'),
amount: {
type: GraphQLString
},
all_posts: {
type: postConnection,
args: {
...connectionArgs,
query: {type: GraphQLString}
},
resolve: (rootValue, args) => connectionFromPromisedArray(
getAllPosts(rootValue, args),
args
),
},
},
interfaces: [nodeInterface]
});
var Root = new GraphQLObjectType({
name: 'Root',
fields: () => ({
node: nodeField,
setting: {
type: settingType,
args: {
...connectionArgs,
currency: {type: GraphQLString}
},
resolve: (rootValue, args) => {
return getSetting(args.currency).then(function(data){
return data[0];
}).then(null,function(err){
return err;
});
}
},
})
});
Below is my database.js
export function getAllPosts(params,args) {
let findTitle = {};
let findContent = {};
if (args.query) {
findTitle.title = new RegExp(args.query, 'i');
findContent.content = new RegExp(args.query, 'i');
}
console.log("getAllPosts",args)
return new Promise((resolve, reject) => {
Post.find({$or: [findTitle,findContent]}).sort({createdAt: 'descending'}).exec({}, function(err, posts) {
if (err) {
resolve({})
} else {
resolve(posts)
}
});
})
}
Now I want to fetch all posts by $query variable
So in view I wrote like this
import React, { Component } from 'react';
import Relay from 'react-relay';
class BlogList extends Component {
constructor(props) {
super(props);
this.state = {
query: '',
};
this.handleSubmit = this.handleSubmit.bind(this);
}
handleSubmit(){
this.props.relay.setVariables({query: this.state.query});
}
render() {
return (
<div className="input-group col-md-12">
<input type="text" onChange={this.handleChange.bind(this,"query")} value={this.state.query} name="query" placeholder="Enter Title or content"/><br/>
<span className="input-group-btn">
<button type="button" onClick={this.handleSubmit} className="btn btn-info btn-lg">
<i className="glyphicon glyphicon-search"></i>
</button>
</span>
</div>
)
}
};
export default Relay.createContainer(BlogList, {
initialVariables: {
query: ''
},
fragments: {
viewer: () => Relay.QL`
fragment on Setting {
id,
all_posts(first: 10000000,query: $query) {
edges {
node {
id,
_id,
title,
content,
createdAt,
username,
color,
images{
full
}
}
}
}
}
`,
},
});
And in routes I have
const SettingQueries = {
viewer: () => Relay.QL`query{
setting(currency: "USD")
}`,
}
export default [{
path: '/',
component: App,
queries: UserQueries,PostQueries,SettingQueries,
indexRoute: {
component: IndexBody,
},
childRoutes: [
,{
path: 'settings',
component: Setting,
queries: SettingQueries,
}]
}]
Things are working on /graphql as
but when I search from website it generates error in response
{
"data": {
"node": null
},
"errors": [
{
"message": "Abstract type Node must resolve to an Object type at runtime for field Root.node with value \"\",received \"null\".",
"locations": [
{
"line": 2,
"column": 3
}
]
}
]
}
as my web-browser is sending requests as below
Please suggest me what am I missing?
Also If I need to add some additional information please let me know.
The problem might be in your nodeDefinitions() function. First callback, also named idFetcher must return a single object. However, i see in your definition that you return a collection
var { nodeInterface, nodeField } = nodeDefinitions(
(globalId) => {
var { type, id } = fromGlobalId(globalId);
...
}else if (type === 'Post') {
return getPosts(); // this should be getPost(id)
}
);
And thats why your next callback, known as typeResolver fails and returns you a null.
var { nodeInterface, nodeField } = nodeDefinitions(
...
(obj) => {
...
// here you get Promise/Collection instead of single Post instance, therefore condition failed
}else if (obj instanceof Post) {
return postType;
}
return null;
}
);
LordDave's answer revealed one problem in your code. As you commented in his answer, all_posts field of settingType was not working.
If you used mongoose library in your DB code, I see a problem with your query:
Post.find({$or: [findTitle,findContent]}).sort({createdAt: 'descending'}).exec({}, function(err, posts) {
if (err) {
resolve({})
} else {
resolve(posts)
}
});
Based on documentation of exec, change your query to
return Post.find({$or: [findTitle,findContent]}).sort({createdAt: 'descending'}).exec(function(err, posts) {
if (err) {
resolve({})
} else {
resolve(posts)
}
});
As exec returns a promise, you can even do
return Post.find({$or: [findTitle,findContent]}).sort({createdAt: 'descending'}).exec();
Finally I got it working by creating a new type 'postList' and defined it as below
var { nodeInterface, nodeField } = nodeDefinitions(
(globalId) => {
var { type, id } = fromGlobalId(globalId);
if (type === 'User') {
return getUser(id);
}else if (type==='postList') {
return getpostList(id);
} else{
return null;
}
},
(obj) => {
if (obj instanceof User) {
return userType;
}else if (obj instanceof postList) {
return postListType;
}else{
return null;
}
}
);
In database.js
class postList {}
postList.id = "Post_id";
export {postList}
export function getpostList(id) {
return new postList
}
and under root fields as below
var postListType = new GraphQLObjectType({
name: 'postList',
description: 'List of posts',
  fields: () => ({
  id: globalIdField('postList'),
  posts: {
  type: postConnection,
  description: 'List of posts',
  args: {
...connectionArgs,
query: {type: GraphQLString}
},
  resolve: (_, args) => connectionFromPromisedArray(getAllPosts(_,args), args),
  },
}),
interfaces: [nodeInterface],
});
var Root = new GraphQLObjectType({
name: 'Root',
fields: () => ({
node: nodeField,
postList: {
type: postListType,
resolve:(rootValue)=> {
return getpostList()
}
},
})
});
I ran into this issue when I was using an InterfaceType and checked for the InterfaceType before the specialized ObjectType in the if-elseif-else of my TypeResolver

Resources