export const getCharactersAsync = createAsyncThunk('getCharactersAsync', async (data) => {
const response = await axios.get('users', { params: { limit: data.limit } });
return response.data;
});
this code block allows me to control limit attribute.
export const getCharactersAsync = createAsyncThunk('getCharactersAsync', async (data) => {
const params = new FormData();
// const params = new URLSearchParams();
params.append('limit', data.limit);
const response = await axios.get('users', params);
console.log(response);
return response.data;
});
However I cannot control limit with using params.append. I tried URLSearchParams instead of FormData but still cannot manipulate limit attribute of the response. Why they differ from each other?
EDIT: This question has missleading information. I should have mention that i am using react-native. I found that react native doesn't fully support everything the web supports. So i need to install package called react-native-url-polyfill.Here is a github issues link
https://github.com/facebook/react-native/issues/23922#issuecomment-648096619
docs
params are the URL parameters to be sent with the request. Must be a plain object or a URLSearchParams object
It can't be FormData
Solution
You wanted to use { params }, not params
export const getCharactersAsync = createAsyncThunk('getCharactersAsync', async (data) => {
const params = new URLSearchParams();
params.append('limit', data.limit);
const response = await axios.get('users', { params });
console.log(response);
return response.data;
});
Related
I'm using Got to make requests to a Strapi API from Node, like so:
res.setHeader('Content-Type', 'application/json')
try {
const request = req.query.request
const decodedRequest = Buffer.from(request, 'base64').toString()
const api = process.env.API_URL ? process.env.API_URL.replace(/\/$/, '') : ''
const url = `${api}${decodedRequest}`
const response = await got.get(url)
const body = await got.get(url).json()
const headers = JSON.parse(JSON.stringify(response.headers))
res.status(200).json({
headers: headers,
data: body
})
} catch (e) {
res.status(500).json({})
}
This works but note that I have the request twice because if I do:
res.setHeader('Content-Type', 'application/json')
try {
const request = req.query.request
const decodedRequest = Buffer.from(request, 'base64').toString()
const api = process.env.API_URL ? process.env.API_URL.replace(/\/$/, '') : ''
const url = `${api}${decodedRequest}`
const response = await got.get(url)
const body = response.json()
const headers = JSON.parse(JSON.stringify(response.headers))
res.status(200).json({
headers: headers,
data: body
})
} catch (e) {
res.status(500).json({
error: e
})
}
it Just crashes and the e from the catch returns an empty error so I have no idea what's going on
I need the headers because the pagination info from Strapi is returned there:
This works because of the value you're awaiting. The conventional example:
const body = await got.get("...").json();
is equivalent to:
const res = got.get("...");
const body = await res.json();
// ^ note
but not:
const res = await got.get("...");
// ^ note
const body = res.json();
From the Promise API docs:
The main Got function returns a
Promise.
Although in order to support cancelation,
PCancelable is used
instead of pure Promise.
The json method is attached to this PCancelable object, not the value it resolves to. If you try to call it on the response, therefore, you get TypeError: res.json is not a function.
What you want is something like:
const res = await got.get("...");
const body = JSON.parse(res.body);
const headers = res.headers;
// ...
That said, if you're doing this for pagination reasons you could also look into their API for that.
I am retrieving a file from an S3 bucket and then forwarding it to another API. It's causing the following error:
DataCloneError: function httpAdapter(config) {
return new Promise(function dispatchHttpRequest(resolvePromise, rejectPromise)...<omitted>...
} could not be cloned.
at MessagePort.<anonymous> (file:///D:/Dev/beep/node_modules/serverless-offline/src/lambda/handler-runner/worker-thread-runner/workerThreadHelper.js:24:10)
at processTicksAndRejections (node:internal/process/task_queues:96:5)
The code used is here:
module.exports.fileUpload = async (event) => {
const bodyForm = JSON.parse(event.body);
const s3 = getS3Client();
const getObjectCommand = new GetObjectCommand({
Bucket: 'bucket-name',
Key: path.parse(bodyForm.name).name
});
const signedUrl = await getSignedUrl(s3, getObjectCommand);
const response = await axios.get(signedUrl, { responseType: 'stream' });
const form = new FormData();
form.append('file', response.data, bodyForm.edf_name);
await axios.post('https://api-url', form).then(res => {
console.log(res)
})
}
This issue happens (most probably) because your form object has methods in it (like your append method), and methods cannot be serialised.
You have two options here:
The hacky way, forcing a serializable form:
const serializableForm = JSON.parse(JSON.stringyfy(form));
await axios.post('https://api-url', serializableForm).then(res => {
console.log(res)
})
The better way, in which you map what form fields you need in your request
const serializableForm = {
foo: form.foo,
bar: form.bar
// ...
};
await axios.post('https://api-url', serializableForm).then(res => {
console.log(res)
})
I have a series of API calls I need to make in order to render a grid of image tiles for selection by the user. Right now it takes 3-5 seconds for the page to load and I think it's because I've accidentally added some extra loops, but I'm struggling to discern where the wasted flops are. This is technically a question about NFT data, but the problem is algorithmic not crypto related.
The call sequence is:
Call "Wallet" API to get all assets associated with an address - API doc
On success, call "Asset Metadata" API to get further info about each asset API Doc
Loop step 2 until all assets have a metadata response
This is my code that works (unless there is no assets associated with a wallet), but is just very slow. I'm sure there is a better way to handle this, but I'm struggling to see how. Thanks for your time!
// API Request
var myHeaders = new Headers();
myHeaders.append("X-API-Key", CENTER_API_KEY); //API Key in constants file
var requestOptions = {
method: 'GET',
headers: myHeaders,
redirect: 'follow'
};
const [nftData, updatenftData] = useState();
const [apiState, updateapiState] = useState("init");
const [renderNFT, updaterenderNFT] = useState([]);
useEffect(() => {
const getData = async () => {
let resp = await fetch(walletAPICall, requestOptions);
let json = await resp.json()
updatenftData(json.items);
updateapiState("walletSuccess");
}
const getRender = async () => {
let nftTemp = [];
for (let i=0;i<nftData.length;i++) {
let tempAddress = nftData[i].address;
let tempTokenId = nftData[i].tokenId;
let resp = await fetch(`https://api.center.dev/v1/ethereum-mainnet/${tempAddress}/${tempTokenId}`, requestOptions)
let json = await resp.json()
// console.log(json);
nftTemp.push(json);
}
updaterenderNFT(nftTemp);
updateapiState("NftDataSuccess");
}
if (apiState=="init") {
getData();
}
else if (apiState=="walletSuccess") {
getRender();
}
}, [requestOptions]);
getRender fetches data items sequentially.
You should do it in parallel using Promise.all or Promise.allSettled
Something like this...
function fetchItem(item) {
const res = await fetch(item.url);
return res.json();
}
await Promise.all[...data.map(fetchItem)]
I am trying to implement filter on API before fetching.
I have a dynamic API route([productType]), which works fine. But when I try to filter the API, it doesn't work.
So the syntax for filtering API looks like this ?$filter=name eq 'Milk' and adding this to the url doesn't work.
As in docs says, I have a tried to change the filename like this [...productType] or [[...productType]] but none of them helps. It returns the api data without filtering.
Here is my code in API dynamic route[productType]. pages/api/[productType]
import axios, { AxiosRequestConfig, Method } from 'axios'
import { pick } from 'lodash'
import { NextApiRequest, NextApiResponse } from 'next'
const baseUrl ='https://myUrl...'
const getFromAPIServer = async (
req: NextApiRequest,
res: NextApiResponse,
) => {
const { productType } = req.query
const param = req.query.params //here I tried to add the parameter for filter, which doesn't work
const url = `${baseUrl}/${productType}?${param}?`
const method = req.method as Method
const { body } = req
const allowedHeaders = ['If-Match']
const headers = pick(req.headers, allowedHeaders) as Record<string, string>
try {
const request: AxiosRequestConfig = {
method,
url,
headers: {
...headers,
Authorization: `Basic ${process.env.TOKEN}`,
'Content-Type': 'application/json',
},
}
if (method !== 'GET' && body) {
request.data = body
}
const { data } = await axios.request(request)
res.status(200).json(data)
} catch (error) {
if (!axios.isAxiosError(error)) {
throw error
}
// Return AxiosError to the client
res.status(error?.response?.status || 500).json(error?.response?.data)
}
}
export default getFromAPIServer
And in components I have the fetching function where I try to fetch the api with filter
export const getApiRequest = (url: string) => {
const { data } = useQuery(['key', url], async () => {
const response = await fetch(url, {
method: 'get',
})
if (!response.ok) throw new Error(response.statusText)
return await response.json()
})
return { data }
}
const { data } = getApiRequest(`${productTypeUrl}?$filter=name eq 'Milk'`)
Forgot to mention: In Postman filtering, the API works fine. It works also fine when I try to fetch with the filter url in components, not importing from api folder.
Update
Doing the filtering in api folder works as below
const url = `${baseUrl}/${productType}?$filter=name eq 'Milk'?`
However, this is not what I want. I want to have filter as params on API folder, like productType so that I can use it on client side.
Any help will be appreciated
Using Next API routes and Knex + MySQL, and using React and SWR for fetching, I get a strange bug. If a request fails, my queries start appending , * to the select statement, resulting in SQL syntax errors. For example, the query should use select *, but comes out as select *, * and then select *, *, * and so on. Does anyone have any idea why this might happen?
SWR fetch:
export const swrFetcher = async (...args) => {
const [url, contentType = 'application/json'] = args;
const res = await fetch(url, {
method: 'GET',
headers: {
'Content-Type': contentType,
},
});
if (!res.ok) throw new Error(res.statusText);
const json = await res.json();
return json;
};
const { data, error } = useSWR('/api/user/me', swrFetcher, {
revalidateOnFocus: false,
revalidateOnReconnect: false,
revalidateOnMount: true,
});
knex query:
const User = knex(TABLE_NAMES.user);
export const readById = (id) => User.select('*').where({ id });
You probably need to create the knex instance within the function call and not reuse the same every time, like it's currently happening.
export const readById = (id) => {
const User = knex(TABLE_NAMES.user);
return User.select('*').where({ id });
}