Sending an array with axios.get as params is undefined - javascript

I am making a get request with additional params options, since I am using that request on a filter, so the params are filters for what to get back:
const res = await axios.get("http://localhots:3000/getsomedata", {
params: {
firstFilter: someObject,
secondFilter: [someOtherObject, someOtherObject]
}
});
The request goes through just fine, on the other end, when I console.log(req.query); I see the following:
{
firstFilter: 'someObject',
'secondFilter[]': ['{someOtherObject}', '{someOtherObject}'],
}
If I do req.query.firstFilter that works just fine, but req.query.secondFilter does not work and in order for me to get the data, I have to do it with req.query["secondFilter[]"], is there a way to avoid this and be able to get my array of data with req.query.secondFilter?
My workaround for now is to do:
const filter = {
firstFilter: req.query.firstFilter,
secondFilter: req.query["secondFilter[]"]
}
And it works of course, but I don't like it, I am for sure missing something.

Some tools for parsing query strings expect arrays of data to be encoded as array_name=1&array_name=2.
This could be a problem if you have one or more items because it might be an array or might be a string.
To avoid that problem PHP required arrays of data to be encoded as array_name[]=1&array_name[]=2 and would discard all but the last item if you left the [] out (so you'd always get a string).
A lot of client libraries that generated data for submission over HTTP decided to do so in a way that was compatible with PHP (largely because PHP was and is very common).
So you need to either:
Change the backend to be able to parse PHP style
Change your call to axios so it doesn't generate PHP style
Backend
The specifics depend what backend you are using, but it looks like you might be using Express.js.
See the settings.
You can turn on Extended (PHP-style) query parsing by setting it to "extended" (although that is the default)
const app = express()
app.set("query parser", "extended");
Frontend
The axios documentation says:
// `paramsSerializer` is an optional function in charge of serializing `params`
// (e.g. https://www.npmjs.com/package/qs, http://api.jquery.com/jquery.param/)
paramsSerializer: function (params) {
return Qs.stringify(params, {arrayFormat: 'brackets'})
},
So you can override that
const res = await axios.get("http://localhots:3000/getsomedata", {
params: {
firstFilter: someObject,
secondFilter: [someOtherObject, someOtherObject]
},
paramsSerializer: (params) => Qs.stringify(params, {arrayFormat: 'repeat'})
});
My example requires the qs module

This has to do with params not being serialized correctly for HTTP GET method. Remember that GET has no "body" params similar to POST, it is a text URL.
For more information I refer to this answer, which provides more detailed info with code snippets.

Related

Let Strapi CMS create pages based on html template file

So probably my explanation is awful, but i really don’t know how to express my problem or what to search for.
I got a site (www.example.com/blog.html) showing all blog post entries created in a headless cms (Strapi). The site receives the posts by making an url request and parsing the resulting JSON data. This data also contains an unique url slug for each post serving as an identifier.
I want to create one page for each blog post created in the headless cms based on a „template“ html.
What I tried is passing the urlslug as a url parameter (www.example.com/blog/article.html?id=*URLSLUG*) and then using this url parameter to fetch the corresponding post data from the cms. I followed this guide: https://strapi.io/blog/build-an-editorial-website-with-vanilla-java-script-and-strapi
It works, but I don’t want to rely on url parameters for seo reasons. Instead I want something like www.example.com/blog/*URLSLUG*. In other words: I want to have one page for each blog post entry in my headless cms based on a „template“ html.
Any suggestions?
Code can be added if necessary
well there is few options here:
The first one is most reliable, and easy but seems not that fancy as you want:
https://market.strapi.io/plugins/strapi-plugin-slugify
The main reason to use this solution is that it handles slug creation when you create post via REST api. The uuid field needs extra work when post created not from admin panel.
So second option is do it yourself style:
/api/article/controller/article.js
module.exports = createCoreController('api::article.article', ({strapi}) => ({
findOne(ctx){
const { slug } = ctx.params;
return strapi.db.query('api::article.article').findOne({where: {slug});
}
});
then in the routes create routes.js file
/api/article/routes/routes.js
module.exports = {
routes: [
{
method: 'GET',
path: '/articles/:slug'
handler: 'article.findOne'
}
]
}
then if you want to create articles for outside of admin, create lifecycles.js in
/api/article/content-types/article/lifecycles.js
module.exports = {
async beforeCreate(event) {
// here you have to do something like
let slug = slugify(event.result.name);
let isNotFree = await strapi.db.query("api::article.article").findOne({where: {slug}});
if (Boolean(!isNotFree)) // < not sure prolly need an empty object check
for (let i = 1; i < 9999 ; i++) {
slug = `${slug}-${i}`;
isNotFree = await strapi.db.query("api::article.article").findOne({where: {slug}});
if (Boolean(!isNotFree))
break;
}
event.result.slug = slug
}
}
pleas note the lifecycle code is just a first thing came to my mind, should be tested and optimized prolly
the implementation gives you the findOne controller, you gonna need to do it for each other update, delete, etc...

js function calling an api doesn't respond with expected values

I am trying to collect all the market pairs from a crypto exchange using its API, but I'm not sure how to select the proper line in the JSON object as it does not seem to work.
the api : https://ftx.com/api/markets
my code :
requests.js
import axios from 'axios';
import parsers from './parsers';
async function ftxMarkets() {
const ftxResponse = await axios.get('https://ftx.com/api/markets');
return parsers.ftxMarkets(ftxResponse.data);
}
parsers.js
function ftxMarkets(data) {
const [ftxMarketPairs] = data;
let ftxPairs = data.map(d => d.name );
console.log(ftxPairs);
};
I'm not sure about d.name in the parsers.js file, but I tried with another exchange with the same code, changing just that part and it worked, so I guess that's where the problem comes from, although can't be sure and I don't know by what to replace it.
Thanks
I ran the api call and after looking at the response I see a result key with the list of all crypto data. So I am guessing it'll work if you call the parser with the result object like this
return parsers.ftxMarkets(ftxResponse.result);
// try parsers.ftxMarkets(ftxResponse.data.result) if the above one doesnt work
and then in the parser it should work normally
function ftxMarkets(data) {
let ftxPairs = data.map(d => d.name );
console.log(ftxPairs);
};
Update:
Since fxtResponse.data.result works. Your issue should be a CORS issue and to fix that there are two options.
CORS plugin in web browser(not recommended in production)
Proxy it through a server. By requesting the resource through a proxy - The simplest way, what you can do is, write a small node server (or if you already have a back-end associate it with your front-end you can use it) which does the request for the 3rd party API and sends back the response. And in that server response now you can allow cross-origin header.
For 2 If you already have a nodeJs server. You can use CORs Npm package and call the third party api from the server and serve the request to the front end with CORS enabled.

How to limit the amount of data returned from a JSON file using fetch?

I have this fetch statement that returns 19 building names, but I only want 10; the following is what I attempted, but I still get 19 building names.
fetchBuildings(energyProgramId) {
fetch(`http://localhost:1001/api/energyprograms/${energyProgramId}/buildings/?results=10`)
.then(res => res.json())
.then(json => {
this.setState({
isLoaded: true,
buildings: json,
})
});
}
Is there something extra I need to add?
Here is an example:
1.fetch('http://jsonplaceholder.typicode.com/posts/')
The above URL gives array of objects with 100 elements because it originally is an array of 100 elements.
2.fetch('http://jsonplaceholder.typicode.com/posts/?_limit=10')
This URL gives array of objects with 10 elements.
Notice the difference?
I only did this : ?_limit=10 ----> Add any number in place of 10 and hopefully you will get desired results.
As the other answer already points out the best/most normal solution would be to change on the backend how the API returns data. Typically REST API's support query parameters such as limit and start or page and resultsPerPage.
If this is not available - e.g. when you're fetching an external resource - an alternative which is often supported by static file servers and sometimes by API's is the Range header which allows you to retrieve only a specific byte range of the resource (do note, in the case that an API supports this it will still load the entire resource on the server, but it will not transmit the entire resource). An example with fetch would look like
fetch('', { headers: { range: 'bytes=0-1000'} })
When doing this on XML or JSON resources it can be somewhat difficult to work with, but with for example CSV files it's ideal.
No different from fetch to XHR or axios or anything else. actually, no different from react or angular or vue or anything else.
This is an API that backend developers wrote it and it is based on REST API, so when you call it as GET or POST and anything else you just fetch the JSON that the backend developers designed it. BUT
There is a new technology that name is GraphQL. you can call API and then you just fetch the JSON what you want. Also, it must be implemented in backend but it is possible.
It's not closely bound up with React. If you need less data you must reduce data before set the state.
const reducedBuildings = [];
fetch(`http://localhost:1001/api/energyprograms/${energyProgramId}/buildings/?results=10`)
.then(res => res.json())
.then(json => {
json.forEach(building => {
if (reducedBuildings.length < 10) {
reducedBuildings.push(building);
}
});
this.setState({
isLoaded: true,
buildings: reducedBuildings,
})
});

Zapier code: trigger multiple webhooks

I'm trying to send multiple webhooks based on the number of items in a JSON array. I'm using a example from:
how to trigger webhook from zapier code
I tried it and it almost works as planned. I have a problem that when I have a JSON array of 4 items, it sends 16 webhooks instead of 4. If I have A JSON array of 3 items, it sends out 9 webhooks instead of 3.
I use inputData.items for insertion of the JSON array. Does anyone know why the items in the JSON array are multiplied?
I used:
const elements = JSON.parse(inputData.items)
var body = elements;
var options = {
"url": "URL.COM",
"method": "POST",
"headers": {'Content-Type': 'application/json'},
"body": JSON.stringify(body)
},
requests = elements.map(mapDataToSettings);
function mapDataToSettings(elem) {
var settings = Object.assign({}, options);
settings.data = JSON.stringify(elem);
return settings;
};
Promise.all(requests.map(grabContent))
.then(function(data){ callback(null, {requestsMade: data});});
function grabContent(options) {
return fetch(options.url, options)
.then(function(res) {return res.json();});
};
Does anyone see why my webhooks are triggering to often?
Thanks
David here, from the Zapier Platform team.
It's hard to say for sure without seeing your zap, but my guess is that you're feeding .items in from a previous Code step where it's returned as an array? If so, you're running into an undocumented code feature where subsequent steps are run for each item in the array. This is usually desirable, but since you're doing a loop in the code, you don't need it.
Assuming that's the case, you've got two options:
Return a sjon string from the previous step (instead of an array) so this code step only runs once.
Change this code to only receive one item and perform a request with it.
If something else is going on, update your question with the zap id (it's not sensitive info) and I can take a look!

Node JS sending data via URL

Recently i started programming with Node JS and found it an amazing replacement for php . In php i used to send get requests with Data in the url .
Something like : http://sample.com/public.php?x=helloworld
How to perform something like this in Node JS or is there a better way to send data to node unlike using the url in the above case .
Also , I have noticed that in some cases like stackoverflow , queries are different and dont include the file name
like /public?= instead of /public.php?=
How is this achieved , i always thought this was something related to REST . Also , if you have the answer you might as well guide me if it could be done with Node and a few sources to learn could be of help too .
the most regular way to use REST api
req.query
// GET /search?q=foo+bar
req.query.q
// => "foo bar"
// GET /phone?order=desc&phone[color]=black&shoe[type]=apple
req.query.order
// => "desc"
req.query.phone.color
// => "black"
req.params
// GET /user/william
req.params.name
// => "william"
req.body(for form data)
// POST /login
req.body.username
// => "william"
req.body.password
// => "xxxxxx"
You'll probably be much better off using a pre-existing module as your web server. You can set one up manually, but you have to know about a lot of potential edge cases and really understand web servers. Most people in node use express. In node, as in any server-side language, you can pass data around in a few ways. The query string is one. You can also put some parameters directly in the url (like "/users/12" where 12 is a user id). Depending on the type of request, you can put data in the body of the request. You can also pass cookies. These are not node-specific. Explaining how express works in a post like this would be crazy, so I'll just give you a short example of a what a route handler matching your example route might look like:
var express = require('express');
var app = express();
app.get('/public', function(req, res, next) {
// Get the value from the query string. Express makes the query
// available as an object on the request parameter.
var x = req.query.x;
// Execute your main logic
doSomethingWithX(x);
// Send a response
res.status(200).json({ foo: 'bar' });
});

Categories