React & Axios - Dynamically add key and value to object - javascript

Working on a little project of mine and ran into an issue.
I am using the "ASOS" API and I need to dynamically add key and value to the parameters that it needs to find the correct product. It is to pick for example color, size, price range etc. Issue is, all things I've tried haven't ended up in a success.
How do I dynamically add key and value to an object?
Something like this:
currency: "USD",
sizeSchema: "US",
lang: "en-US",
newKey: newValue
Here is my code:
const FetchAPI = (props) => {
const [product, setProducts] = useState([]);
// Key and Value
let facetKey = props.facetKey;
let facetValue = props.facetValue;
// Sets the paramaters
let params = {
store: "US",
offset: props.offset,
categoryId: props.categoryId,
limit: props.limit,
country: "US",
sort: "freshness",
currency: "USD",
sizeSchema: "US",
lang: "en-US",
};
// Need to add my "facetKey" and "facetValue" to "params".
useEffect(() => {
const options = {
method: "GET",
url: "https://asos2.p.rapidapi.com/products/v2/list",
params: params,
headers: {
"x-rapidapi-key": "",
"x-rapidapi-host": "",
},
};
axios
.request(options)
.then(function (response) {
setProducts(response.data.products);
props.items(response.data.itemCount);
props.facets(response.data.facets);
console.log(response.data.facets);
})
.catch(function (error) {
console.error(error);
});
}, [props.offset, props.limit]);
return (
<div>
<div className={classes.container}>
{product.map((product) => (
<ProductCard
key={product.id}
img={product.imageUrl}
name={product.name}
price={product.price.current.text}
/>
))}
</div>
</div>
);
};
Thanks!
Keep in mind
The facetKey and facetValue return string values, and if the user havent picked a "facet", or an option to filter the products. Then it returns undefined, can of course change this to null.

You can use the [] operator with objects.
In general:
let obj = {};
let key = 'x';
let value = 3;
obj[key] = value;
console.log(obj);
console.log(obj[key]);
In your example:
let facetKey = props.facetKey;
let facetValue = props.facetValue;
// Sets the paramaters
let params = {
// ...
};
// Need to add my "facetKey" and "facetValue" to "params".
if (facetKey)
params[facetKey] = facetValue;

You can write the code as follows.
let params = {
store: "US",
offset: props.offset,
categoryId: props.categoryId,
limit: props.limit,
country: "US",
sort: "freshness",
currency: "USD",
sizeSchema: "US",
lang: "en-US",
[facetKey]: facetValue
};
And if facetKey can be undefined, you can do like this.
let params = {
store: "US",
offset: props.offset,
categoryId: props.categoryId,
limit: props.limit,
country: "US",
sort: "freshness",
currency: "USD",
sizeSchema: "US",
lang: "en-US",
};
facetKey && params = { ...params, [facetKey]: facetValue }
// or
if (facetKey) {
params = { ...params, [facetKey]: facetValue }
}

Related

Typescript/NestJS - extract object from db query response

I'm using external API to make an SQL query for a user. As a result i get matching Entity but as a set of fields, lookin like this:
[
{ IsNull: false, Name: 'Key', Value: '897', Values: null },
{ IsNull: false, Name: 'FirstName', Value: 'User', Values: null },
{ IsNull: false, Name: 'LastName', Value: 'Portal', Values: null },
{
IsNull: false,
Name: 'Email',
Value: 'some#email.com',
Values: null
},
{ IsNull: true, Name: 'Salutation', Value: null, Values: null },
{ IsNull: false, Name: 'Type', Value: '2', Values: null },
{
IsNull: false,
Name: 'LastLoggedDate',
Value: '2022-12-01 15:24:03',
Values: null
}
]
How to transform this response to end with simple object { email: 'some#email', firstName: 'User' lastName: 'Portal' } ??
I ended up with solution like this (below) but i believe there's some easiest way to do that, especially with more fields
let userRawEntity = queryResult.data.Entities[0].Fields;
const userEmail = userRawEntity.filter((obj) => { return obj.Name === 'Email' });
const userFirstName = userRawEntity.filter((obj) => { return obj.Name === 'FirstName' });
const userLastName = userRawEntity.filter((obj) => { return obj.Name === 'LastName' });
return { email: userEmail[0].Value, firstName: userFirstName[0].Value, lastName: userLastName[0].Value };
Edit:
final solution that works and looks nicer. thanks for help :)
if (queryResult.data.TotalEntityCount > 0) {
let user: {[key: string]: string | null } = {}
let userRawEntity = queryResult.data.Entities[0].Fields;
userRawEntity.forEach(data => user[data.Name] = data.Value);
return { email: user.Email, currency: user.Currency } as JwtPayload;
}
As a starting point, I would transform that entire array into an object as follows:
let dataTransformed: {[key: string]: string | null} = {}
data.forEach(d => {
dataTransformed[d.Name] = d.Value
})
Which will give you a nicer looking object as follows:
{
"Key": "897",
"FirstName": "User",
"LastName": "Portal",
"Email": "some#email.com",
"Salutation": null,
"Type": "2",
"LastLoggedDate": "2022-12-01 15:24:03"
}
You now have a familiar object with which to work with. From here, you can strip out the entries you don't want. Note, you may want to do further work in that array transformation such as checking for null values, changing keys to camel case, etc...
Another approach using lodash
_.mapValues(_.keyBy(data, "Name"), o => o.Value || o.Values);

Is there a way to transform a JavaScript object into another object with cleaner formatting?

When accessing a public register API, I receive more information than I need, and sometimes the data is returned with minor variations. I would like to delete some unnecessary fields, move nested fields to the top level, and rename them. The goal is to standardise format across several different APIs, and keep the memory requirement to a minimum. Example below:
Raw object:
[
{
startDate: "2022/08/27",
expiryDate: "2025/08/27",
party: {
type: "Business",
name: "Irregular Expressions Inc."
},
location: {
type: "Office",
address: {
locality: "Boston",
postcode: "PE21 8QR"
}
}
},
{
startDate: "2023/12/22",
expiryDate: "2024/06/22",
party: {
type: "Charity",
name: "Save the Badgers"
},
site: {
type: "Office",
address: {
locality: "Badgerton",
postcode: "BA6 6ER"
}
}
},
]
I want to transform this into a smaller, cleaner array:
[
{
startDate: "2022/08/27",
expiryDate: "2025/08/27",
partyName: "Irregular Expressions Inc.",
location: "Boston"
},
{
startDate: "2023/12/22",
expiryDate: "2024/06/22",
partyName: "Save the Badgers",
location: "Badgerton"
},
]
I have tried the below, but I'm getting an error.
module.exports = {
testTransform: (inputArray) => {
const outputArray = []
inputArray.forEach(element => {
outputArray.push({
startDate: element.startDate,
expiryDate: element.expiryDate,
partyName: element.party.name,
location: element.location.address.locality
})
})
return JSON.stringify(outputArray, null, ' ')
}
}
TypeError: Cannot read properties of undefined (reading 'address')
Am I going in the right direction, or is there a simpler way of doing this? I've searched for this type of transformation but with no luck - what am I missing?
You could take either location or site with logical OR || and later the proerties with optional chaining operator ?..
const
data = [{ startDate: "2022/08/27", expiryDate: "2025/08/27", party: { type: "Business", name: "Irregular Expressions Inc." }, location: { type: "Office", address: { locality: "Boston", postcode: "PE21 8QR" } } }, { startDate: "2023/12/22", expiryDate: "2024/06/22", party: { type: "Charity", name: "Save the Badgers" }, site: { type: "Office", address: { locality: "Badgerton", postcode: "BA6 6ER" } } }],
result = data.map(o => ({
startDate: o.startDate,
expiryDate: o.expiryDate,
partyName: o.party.name,
location: (o.location || o.site)?.address?.locality
}));
console.log(result);
Since it looks like you don't know what the outer key will be for the object with the address property, if the object will always have 4 properties, when destructuring, you can use rest syntax to collect the final property into a single object, and then take that object's values to get to the address.
const input=[{startDate:"2022/08/27",expiryDate:"2025/08/27",party:{type:"Business",name:"Irregular Expressions Inc."},location:{type:"Office",address:{locality:"Boston",postcode:"PE21 8QR"}}},{startDate:"2023/12/22",expiryDate:"2024/06/22",party:{type:"Charity",name:"Save the Badgers"},site:{type:"Office",address:{locality:"Badgerton",postcode:"BA6 6ER"}}}];
const output = input.map(({
startDate,
expiryDate,
party,
...rest
}) => ({
startDate,
expiryDate,
partyName: party.name,
location: Object.values(rest)[0].address.locality,
}));
console.log(output);
You are trying to read locality property of undefined. You could use optional chaining operator to prevent the exception throwing. So, you need to use somthing like element?.location?.address?.locality instead of element.location.address.locality.
That would require writing a function that recurcively goes throught the contents of an object an returns a non-nested object. The function below is such a function.
const flattenObject = (obj) => {
let result = {};
for (const i in obj) {
if ((typeof obj[i]) === 'object') {
const temp = flattenObject(obj[i]);
for (const j in temp) {
result[j] = temp[j];
}
}
else {
result[i] = obj[i];
}
}
return result;
};
The function can then be called on each nested object in the array. The map method of arrays would be do nicely for that step.
const result = nested.map(n => flattenObject(n))
console.table(result[0]) would produce the output below

Changing value after parsing from API

I'm parsing the following from:
json.listMap.forEach((listItem: { State: string; Country: string})```
Response.data looks like this:
```{
success: true,
listMap: [
{
State : 'Northrine Westfalia',
Country: 'Germany'
},
{
{
State : 'Bavaria',
Country: 'Germany'
}
}
]
}
How can I convert the value in country currently being 'Germany' to 'Deutschland' after parsing it from the API using Java Script?
-> Let me be more open here. I don't really know that method I could use to do this. Maybe someone could point me at a documentation, of course I don't expect anyone to just hand me the code.
Here's a general approach passing in the data, and from, and to arguments. It then uses map to return a new array of objects, changing the country where necessary.
Note: check your data for errors as you had some spare brackets in your example.
const data = {
success: true,
listMap: [{
State: 'Northrine Westfalia',
Country: 'Germany'
},
{
State: 'Bavaria',
Country: 'Germany'
}
]
}
function swap(data, prop, from, to) {
return data.listMap.map(obj => {
// Copy the object otherwise we'll return
// an array of objects that point
// to the old references
const newObj = {...obj};
if (newObj[prop] === from) newObj[prop] = to;
return newObj;
});
}
console.log(swap(data, 'Country', 'Germany', 'Deutchland'));
console.log(swap(data, 'State', 'Bavaria', 'New Bavaria'));
Use Array.map after parsing JSON into an JavaScript array:
const list = response.listMap.map(entry => {
return {
State : entry.State,
Country: entry.Country.replaceAll('Germany', 'Deutschland')
}
})
Of course, if you need JSON structure, just convert final array into JSON string with the following:
const newJSONList = JSON.stringify(list);
try this :
listMap = listMap.map(listMapItem => {
if ('Germany'===listMapItem.Country) {
listMapItem.Country = 'Deutschland';
return listMapItem;
} else {
return listMapItem;
}
});
assuming below is your response object.
var responsObj={ success: true,
listMap: [
{
State : 'Northrine Westfalia',
Country: 'Germany'
},
{
State : 'Bavaria',
Country: 'Germany'
}
]
};
responsObj.listMap=responsObj.listMap.map(x=>{
if(x.Country=="Germany"){
x.Country="Deutschland";
}
return x;
});
console.log(responsObj.listMap);
Something like this might help your requirement.
const rawJson = {
success: true,
listMap: [
{
State: 'Northrine Westfalia',
Country: 'Germany'
},
{
State: 'Bavaria',
Country: 'Germany'
}
]
};
for (itemObj of rawJson.listMap) {
// If needed, you can add check for current value to be 'Germany'
// if (itemObj.Country === 'Germany')
itemObj.Country = 'Deutschland';
}
console.log(rawJson);
Output:
{
success: true,
listMap: [
{ State: 'Northrine Westfalia', Country: 'Deutschland' },
{ State: 'Bavaria', Country: 'Deutschland' }
]
}

Building a gateway with nodeJs

I have to build a layer for an API using nodeJs and create some endpoints for the frontend.
I'm new to nodeJS and I've builded some small servers creating models and making some CRUD with Mongo.
This is the first time I have to make an intermediate layer to an existing API to filter the results.
I did it, and in the expected format, but I'm getting an error from node and I can't figure out how to resolve it.
The original API is kind like this:
{
id:'some id',
pagination: {...},
results: [...],
other_results: [...],
additional_info: [
{
id:'someid',
info:'someinfo',
values:[
{
id: 'someid',
name: 'some category name',
count: 999
},
{...},
{...}
],
},
{...},
{...}
]
}
and I have to "extract" the data from "results" and the first array of "additional_info".
My endpoint has to return data in this format:
{
brand: {name: "Any brand", country: "Germany"},
categories: ["category one", "category two", "category three"],
items: [
0: {id: "olmk23238777", name: "item one", imgUrl: 'img/34341.jpg', price: {total:424, currency: "USD"}, shipping: 'fast'},
1: {id: "olmk23239348", name: "item two", imgUrl: 'img/34764.jpg', price: {total:47, currency: "USD"}, shipping: 'slow'},
…]
}
I could achieved with this:
const axios = require('axios');
exports.products = async query => {
const url = `${process.env.BASE_URL}${query}`;
let productsData = {
brand: {
name: 'Any Brand',
country: 'Germany',
},
};
try {
const result = await axios({
method: 'GET',
url,
});
const data = result.data;
productsData.categories = data.additional_info[0].values.map(
({ categoryName }) => categoryName
);
productsData.items = data.results.map(item => ({
id: item.id,
name: item.name,
imgUrl: item.imgSrc,
price: {
total: parseInt(item.price),
currency: item.currency,
},
shipping: item.shipping_method,
}));
return productsData;
} catch (error) {
console.log(error);
}
};
This is the controller:
const { products } = require('../utils/products');
exports.searchItem = async (req, res) => {
const { search } = req.query;
try {
const response = await products(search);
res.send(response).json();
} catch (error) {
console.log(error);
}
};
and the endpoint look like this:
http://localhost:4000/api/products?search=shirt
This is the error
Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
I tried different things but I can't fixe it
First of all, your error has an explanation here:
Error: Can't set headers after they are sent to the client
And for your code:
look this:
res.send(response).json();
it should be one of these:
res.send(response);
// or
res.json(response);
For the parameter type/structure, please refer to documentation of your selected library.

Authentication failed due to invalid authentication credentials or a missing Authorization header. in nodejs paypal sdk

I am trying to implement paypal subscription api in react-nodejs project.i refer https://developer.paypal.com/docs/api/subscriptions/v1/. after that i got id wit "P-*********".
What i have tried is:
in Ui Side(React) i created an event for requesting server side to create the billing plans.
in server side(nodejs) i do billingPlan create and update actions.
The code is:(nodejs)
export const paypalSubscribe = async (user, data) => {
const customerId = user.customer,
{ invoice: invoiceId } = data;
try {
const billingPlanAttributes = {
description: "Create Plan for Regular",
merchant_preferences: {
auto_bill_amount: "yes",
cancel_url: "http://www.cancel.com",
initial_fail_amount_action: "continue",
max_fail_attempts: "1",
return_url: "http://www.success.com",
setup_fee: {
currency: "USD",
value: "25"
}
},
name: "Testing1-Regular1",
payment_definitions: [
{
amount: {
currency: "USD",
value: order.price.recurringAmount
},
charge_models: [
{
amount: {
currency: "USD",
value: "10.60"
},
type: "SHIPPING"
},
{
amount: {
currency: "USD",
value: "20"
},
type: "TAX"
}
],
cycles: "0",
frequency: "MONTH",
frequency_interval: order.billingCycle,
name: "Regular 1",
type: "REGULAR"
}
],
type: "INFINITE"
};
const createdBillingPlan = await new Promise((resolve, reject) => {
Paypal.billingPlan.create(billingPlanAttributes, function (
error,
billingPlan
) {
if (error) {
reject(error);
} else {
resolve(billingPlan);
}
});
});
console.log("data123....", createdBillingPlan);
// update
var billing_plan_update_attributes = [
{
op: "replace",
path: "/",
value: {
state: "ACTIVE"
}
}
];
console.log(
"billing_plan_update_attributes",
billing_plan_update_attributes
);
const updateBillingPlan = await new Promise((resolve, reject) => {
Paypal.billingPlan.update(
createdBillingPlan.id,
billing_plan_update_attributes,
function (error, response) {
if (error) {
reject(error);
} else {
resolve(response);
}
}
);
});
const getBillingPlan = await new Promise((resolve, reject) => {
Paypal.billingPlan.get(createdBillingPlan.id, function (
error,
updatedBillingPlan
) {
if (error) {
console.log("errr", error.response);
reject(error);
} else {
console.log("updatedBillingPlan", JSON.stringify(updatedBillingPlan));
resolve(updatedBillingPlan);
updatedBillingPlan.redire
}
});
});
console.log("getBillingPlan", getBillingPlan);
return { ok: true, data: getBillingPlan };
} catch (error) {
console.log("error", error);
}
};
And i got getBillingPlan is like this:
{ id: 'P-**************',
state: 'ACTIVE',
name: 'Testing1-Regular1',
description: 'Create Plan for Regular',
type: 'INFINITE',
payment_definitions:
[ { id: 'PD-0EF41434TA3045459BCMIRMA',
name: 'Regular 1',
type: 'REGULAR',
frequency: 'Month',
amount: [Object],
cycles: '0',
charge_models: [Array],
frequency_interval: '1' } ],
merchant_preferences:
{ setup_fee: { currency: 'USD', value: '25' },
max_fail_attempts: '1',
return_url: 'http://www.success.com',
cancel_url: 'http://www.cancel.com',
auto_bill_amount: 'YES',
initial_fail_amount_action: 'CONTINUE' },
create_time: '2020-07-01T04:18:01.008Z',
update_time: '2020-07-01T04:18:02.031Z',
links:
[ { href:
'https://api.sandbox.paypal.com/v1/payments/billing-plans/P-***********',
rel: 'self',
method: 'GET' } ],
httpStatusCode: 200
}
And when i trying to open the links in links array
ie,https://api.sandbox.paypal.com/v1/payments/billing-plans/P-***********' i got the error:
"Authentication failed due to invalid authentication credentials or a missing Authorization
header."
Where i went wrong? How can i resolve this and implement subscription of paypal in my Project.
REST Api
i changed my code to rest api calls finaly i got response like this:
{ status: 'APPROVAL_PENDING',
id: 'I-1FU83BNMBCFS',
create_time: '2020-07-06T09:47:02Z',
links:
[ { href:
'https://www.sandbox.paypal.com/webapps/billing/subscriptions? ba_token=BA-3D945638N1691194P',
rel: 'approve',
method: 'GET' },
{ href:
'https://api.sandbox.paypal.com/v1/billing/subscriptions/I- 1FU83BNMBCFS',
rel: 'edit',
method: 'PATCH' },
{ href:
'https://api.sandbox.paypal.com/v1/billing/subscriptions/I-1FU83BNMBCFS',
rel: 'self',
method: 'GET' } ],
responseCode: 201 }
and in my ui side i opened the approval link in new window after submitting it shows 404. Why?
code:
window.open(URL, "_blank");
UPDATE:Subscription:
const subscriptionString = {
plan_id: result.id,
start_time: "2021-11-01T00:00:00Z",
shipping_amount: {
currency_code: "USD",
value: "10.00"
},
subscriber: {
name: {
given_name: "John",
surname: "Doe"
},
email_address: "customer#example.com",
shipping_address: {
name: {
full_name: "John Doe"
},
address: {
address_line_1: "2211 N First Street",
address_line_2: "Building 17",
admin_area_2: "San Jose",
admin_area_1: "CA",
postal_code: "95131",
country_code: "US"
}
}
},
application_context: {
brand_name: "walmart",
locale: "en-US",
shipping_preference: "SET_PROVIDED_ADDRESS",
user_action: "SUBSCRIBE_NOW",
payment_method: {
payer_selected: "PAYPAL",
payee_preferred: "IMMEDIATE_PAYMENT_REQUIRED"
},
return_url: "https://example.com/returnUrl",
cancel_url: "https://example.com/cancelUrl"
}
},
options = {
url: "https://api.sandbox.paypal.com/v1/billing/subscriptions",
method: "POST",
headers: headers,
body: JSON.stringify(subscriptionString)
},
activateResult = await payment.callPayaplApi(options);
return {
ok: true,
data: activateResult
};
}
There is no SDK for a Subscriptions API integration, you need to implement direct REST API calls.
The PayPal-Node-SDK never supported the Subscriptions API, only the previous billing APIs which are not compatible. Also, the PayPal-Node-SDK is no longer maintained.
You particular authentication error is due to something else, but due to the above issues it is not worth troubleshooting.
Start over and integrate correctly with direct REST API calls.

Categories