Axios get with param array - javascript

I create one get request with axios:
this.$axios.get('/cidade/',{
params: {
q: result,
}
})
.then((response) => {
this.cidades = response.data;
})
.catch(function (error) {
// handle error
// eslint-disable-next-line
console.log(error);
})
.then(function () {
// always executed
});
but my result is an array [123asdas1,asdasd2312] and when the axios excute the request he create that url:
http://localhost:8081/cidade/?q[]=5b9cfd0170607a2e968b0a1e&q[]=5b9cfd0170607a2e968b0a1d
so It's possible to remove the [] from q param? how?
tks

When composing a query string where one field has multiple values (i.e. if it were an array), then there is no standard that says how it must be encoded in the query string, however most web servers accept this syntax:
http://localhost:8081/cidade/?q[]=value1&q[]=value2
which is why axios defaults to it. Check your web server to see if it is reading the parameter as an array correctly.
If you want to force it to be encoded in some other way, just convert the array to a string in whatever format you want and send it as a single value:
this.$axios.get('/cidade/', {
params: {
q: JSON.stringify(result)
}
})
http://localhost:8081/cidade/?q=[value1,value2]
(The [ and ] characters may be percent-encoded.)
In general, this syntax cannot distinguish between the string "[value1,value2]" and the array [value1, value2], so the web server will have to choose one or the other. Again, this is all dependent on your web server.

Related

How do I allow url string to alter JSON message returned when creating a REST API using express?

I'm relatively new to express and I'm trying to create a locally hosted API that contains my resume. I understand that in a call such as:
app.get("/url", (res, req, next) => {
res.json({
//json body
});
});
the "url" can be used to return a different JSON based upon the html string. However, I'm hoping that there's a way for me to make it so that if the url is just "/", it returns the whole JSON object. Otherwise, if it contains an identifier like: "/experience", then it'll just return a JSON object containing the experience section of the JSON. However, I don't want to copy and paste each section of the JSON for every different possible "GET" call. Does anyone know a way I can do this?
If you have the object, iterate over its keys to make a route for each.
app.get("/", (res) => {
res.json(theObj);
});
for (const [key, value] of Object.entries(theObj)) {
app.get("/" + key, (res) => {
res.json(value);
});
}

Adyen Drop-in - how to pass unique order ID?

I have been trying to use the Adyen Drop-in component to make payments on the Razor pages site I am developing. I have got a test version running that makes a payment for a hard-coded amount but I have yet to figure out how to pass a unique order ID to my API endpoint making the payment request.
Taking the examples from https://docs.adyen.com/online-payments/drop-in-web, the drop-in component is mounted via JavaScript using
const checkout = new AdyenCheckout(configuration);
const dropin = checkout.create('dropin').mount('#dropin-container');
where the configuration object is created with something like
const configuration = {
paymentMethodsResponse: paymentMethodsResponse, // The `/paymentMethods` response from the server.
clientKey: "YOUR_CLIENT_KEY", // Web Drop-in versions before 3.10.1 use originKey instead of clientKey.
locale: "en-US",
environment: "test",
onSubmit: (state, dropin) => {
// Your function calling your server to make the `/payments` request
makePayment(state.data)
.then(response => {
if (response.action) {
// Drop-in handles the action object from the /payments response
dropin.handleAction(response.action);
} else {
// Your function to show the final result to the shopper
showFinalResult(response);
}
})
.catch(error => {
throw Error(error);
});
},
onAdditionalDetails: (state, dropin) => {
// Your function calling your server to make a `/payments/details` request
makeDetailsCall(state.data)
.then(response => {
if (response.action) {
// Drop-in handles the action object from the /payments response
dropin.handleAction(response.action);
} else {
// Your function to show the final result to the shopper
showFinalResult(response);
}
})
.catch(error => {
throw Error(error);
});
}
};
Adyen's own JavaScript then supplies the state object for the onSubmit method, so that my API endpoint gets called with a PaymentRequest object created (somehow) from the state.data.
However, without being able to get a unique order ID into this PaymentRequest object, my server-side code does not know what amount to set. Note that one can set an Amount object in the configuration object but this is just used to display the value on the Drop-in component - the value is not passed to the server.
So how does one pass a unique order ID via the Drop-in component?
The Adyen docs don't explicitly provide an example here, but the makePayment() and makeDetailsCall() presume that you will take the state.data and post back to your server. You need to implement your own code here. At that point, you could add additional information like any identifiers.
Here is an example implementation as a reference:
async function makePayment(state_data) {
const order_id = ""; // You need to provide this however your client stores it.
const json_data = {
order_id,
state_data,
};
const res = await fetch("[url to your server's endpoint]", {
method: "POST",
body: JSON.stringify(json_data),
headers: {
"Content-Type": "application/json",
},
});
return await res.json();
}
Another helpful resource could be the Adyen node.js/express tutorial. It is more explicit on implementation details so might help remove some ambiguity.

Firebase and Algolia secured search no search hits

I'm having some issues implementing a secured search with Firebase and Algolia.
I've been following the guide at https://firebase.google.com/docs/firestore/solutions/search -> Adding security
My problem is that everything seems to be working fine, however I do not receive any search hits.
When a user searches for an item, it invokes a function which first hits a firebase function to generate a Secured API Key, which also includes the security filter for the queries.
The firebase function:
app.use(getFirebaseUser);
app.get('/', (req, res) => {
// #ts-ignore
const uid = req.user.uid;
// Create the params object as described in the Algolia documentation:
// https://www.algolia.com/doc/guides/security/api-keys/#generating-api-keys
const params = {
// This filter ensures that only documents where author == uid will be readable
filters: `ownerID:${uid}`,
// We also proxy the uid as a unique token for this key.
userToken: uid,
};
// Call the Algolia API to generate a unique key based on our search key
const key = client.generateSecuredApiKey(ALGOLIA_SEARCH_KEY, params);
// Then return this key as {key: '...key'}
res.json({key});
});
This is literally copy/pasted from the firebase example, except I've replaced "author" with "ownerID", which is the term I want to match in my indices.
The getFirebaseUser() is an exact copy/paste from the official firebase example.
Once the client has received the secured API key, it get passed to algolia with the query:
const getSearchResults = async (query: string) => {
const index = client.initIndex('things');
try {
const userToken = await auth.currentUser?.getIdToken();
const response = await fetch(GOOGLE_URL, {
headers: { Authorization: `Bearer ${userToken}` },
});
const data = await response.json();
const client = algoliasearch(ALGOLIA_APP_ID, data.key);
const responses = await index.search(query);
console.log(responses);
} catch (err) {
console.error(err.message);
}
};
This is also the same function as the example, except written with async/await. (I did try an exact copy/paste, and the result is the same).
Also, the example shows index.search({query}) where the query string gets passed in as an object. This does not work either, and Typescript states that a string is expected.
If I try to change the initIndex to an index that doesn't exist, I get an error stating that it doesn't exist. This tells me the connection between my app and algolia is working as expected.
The returned object looks like this:
exhaustiveNbHits: true
hits: []
hitsPerPage: 20
nbHits: 0
nbPages: 0
page: 0
params: "query=test&filters=ownerID%3AKK3oXEkrIKb31BECDSJPMdgvTBz2&userToken=KK3oXEkrIKb31BECDSJPMdgvTBz2"
processingTimeMS: 1
query: "test"
If I do a regular search:
const getSearchResults = async (query: string) => {
const client = algoliasearch(ALGOLIA_APP_ID, ALGOLIA_SEARCH_API_KEY);
const index = client.initIndex('things');
const responses = await index.search(query);
console.log(responses);
};
I do get hits:
exhaustiveNbHits: true
hits: Array(1)
0: {productName: "test ja", purchaseDate: "15.03.2021", purchasedFrom: "ok", ownerID: "KK3oXEkrIKb31BECDSJPMdgvTBz2", objectID: "25BadjQxUjRjkjH9ZnwW", …}
length: 1
__proto__: Array(0)
hitsPerPage: 20
nbHits: 1
nbPages: 1
page: 0
params: "query=test"
processingTimeMS: 1
query: "test"
This is literally bypassing the whole cloud function, which means the problem must be with generating the Secured API Key, the parameters or something.
The index data stored in Algolia looks like this:
objectID "25BadjQxUjRjkjH9ZnwW"
productName "test ja"
purchaseDate "15.03.2021"
purchasedFrom "ok"
ownerID "KK3oXEkrIKb31BECDSJPMdgvTBz2"
Which means I should get hits on ownerID, which I have in the cloud function.
EDIT:
When setting the filter from the parameter object to an empty string, I receive search hits. There might be something wrong with the way the filter is implemented.
Thanks for looking into this. I would appreciate all the help I can get!
Stephan Valois
I was in contact with algolia, and figured out what was wrong.
There was nothing wrong with the code, or the way the search was set up.
One thing that wasn't mentioned in the documentation is that the attribute I was matching (ownerID) wasn't declared as an attribute for faceting.
By going to Configuration -> Facets in the Algolia app, and adding the object key there, everything works as expected. (Sat it as 'not searchable'). This attribute is not supposed to be searchable. It should only be used to match the index to the correct user.
If anyone is using Algolia for secure search, whether or not you're using a Firebase function or another backend, the attribute in your filter must be set in Facets.

Boolean params in Axios get request automatically getting converted to string in server side

I have a json object which I'm passing as params to axios get api. This is the Json object
obj = {
name: "device"
value: true,
}
And I'm calling the axios get request with the above object like this -
tableFilter = (obj) => {
console.log(typeof obj.value);
axios
.get("http://localhost:3200/getFilter/", { params: obj })
.then((res) => {
console.log(res.data);
});
};
In the above code the type of 'obj.value' shows as 'boolean' in console. Now I handle this request in server side like this-
Router.get("/getFilter", async (req, res) => {
console.log(typeof req.query.value);
dbase.collection("employee").find(
{ [req.query.filter]: req.query.value },
{ projection: { _id: 0 } })
.toArray().then((result) => {
console.log(result);
});
}
});
'Router' is the express router object and 'dbase' is the mongoclient object of my database(They don't matter to my question). In the above code if I console the object 'value' key it shows type as "String". Why is the boolean automatically getting converted to String?
I need to query mongodb documents based on the field "device: true" So I need boolean value not string.
Axios will put the parameters in the URL when using get, so they are passed as text to the server.
You could (on the server side):
check for the presence of the parameter, if it's NOT present assume value is boolean false (careful, as on the other hand, its presence does NOT mean it's boolean true)
if present, check if the value of parameter value is string "true" (potentially a good idea to lowercase it first, so to avoid any shenanigans due to case difference.
-> If it is, then assume boolean true.
-> If it is anything else, assume boolean false
You can't add an object or data in axios.get(). It takes only the URL;
If you want to send data in get request via axios, then you must add them as query params.
Your URL should look like this:
axios.get("http://localhost:3200/getFilter/?name="+name+"&value="+value)
//here name and values are const added dynalically
Try to JSON encode the payload on the client-side and then JSON decode the request payload on the server. It will preserve the Boolean values so you won't see a boolean turned into a string "1" or "true".

How do I stream JSON objects from ExpressJS?

I'm trying to stream JSON objects from an ExpressJS / Node backend API to a frontend site.
I do not want to use Sockets.IO for various reasons. As I understand it, the native streaming libraries should support streaming objects, it appears that just Express is complicating this.
My frontend code seams straight forward. I use Fetch to get my target URL, get a read stream from the response object, and set that read stream to objectMode: true.
Frontend Example:
async function () {
let url = "myurl";
let response = await fetch( url, {
method: 'GET',
mode: 'cors',
wtihCredentials: 'include'
}
const reader = response.body.getReader({objectMode: true });
// Where things are a bit ambiguous
let x = true;
while (x) {
const {done, value} = reader.read()
if (done) { break; }
// do something with value ( I push it to an array )
}
}
Backend Bode Example ( fails because of I cannot change the stream to objectMode )
router.get('/', (request, response) => {
response.writeHead(200, { 'Content-Type' : 'application/json' });
MongoDB.connection.db.collection('myCollection').find({}).forEach( (i) => {
response.write(i);
}).then( () => {
response.end()
})
})
Now my problem is that there does not appear to be anyway to change the ExpressJS write stream to objectMode: true. To my dismay, the ExpressJS documentation doesn't even acknoledge the existence of the write() function on the response object: https://expressjs.com/en/api.html#res
How do I change this over to objectMode: true ?
conversely, I tried to work with the writeStream as a string. The problem that I run into is that when the send buffer fills up, it does it by characters, not by the object. These means that at some point invalid JSON is passed to requester.
A suggested solution that I run into often is that I could read all of the chunks on the client and assemble valid JSON. This defeats the purpose of streaming, so Im trying to find a better way.
For what I believe is the same problem, I cannot figure out how to talk directly to the write stream object from the express code so I am unable to use the native writeStream operation writable.length in order to manually check to see if there is space for the entire JSON object as a string. This is preventing me from using stringified JSON with new line terminators.
https://nodejs.org/api/stream.html#stream_writable_writablelength
https://nodejs.org/api/stream.html#stream_writable_writableobjectmode
Could someone set me straight? I am working with 100k + records in my Mongo database, I really need partical page loading to work so that the users can start picking through the data.

Categories

Resources