Related
I am using Cloudinary to host my media on the cloud for my NodeJS project.
To delete an image from the Clodinary Cloud, I need to pass a Public Id for that image, to the Cloudinary API.
I realised, Public ID is embedded into the url, how to I extract it out from the URL?
Because, I don't want to store my data in this format :
image : {
url : `http://res.cloudinary.com/cloud_name/image/upload/v1647610701/rsorl4rtziefw46fllvh.png`,
publicId : `rsorl4rtziefw46fllvh`
}
Rather, I find it better to store it like this :
image : `http://res.cloudinary.com/cloud_name/image/upload/v1647610701/rsorl4rtziefw46fllvh.png`
The solution to this problem is to implement a funciton which extracts the publicId for every URL passed in as argument.
Here's the function :
const getPublicId = (imageURL) => imageURL.split("/").pop().split(".")[0];
Edited after #loic-vdb 's suggestion
Explanation :
It splits the string in an array using "/" as seperator.
imageURL="http://res.cloudinary.com/cloud_name/image/upload/v1647610701/rsorl4rtziefw46fllvh.png";
becomes,
imageURL = [ 'http:',
'',
'res.cloudinary.com',
'cloud_name',
'image',
'upload',
'v1647610701',
'rsorl4rtziefw46fllvh.png' ]
Next, pop the array (returns the last element of the array)
imageURL = 'rsorl4rtziefw46fllvh.png';
Now, split this string into array using "." as seperator, we get :
imageURL = [ 'rsorl4rtziefw46fllvh', 'png' ]
Finally select the 0th element that is our PublicId return that
imageURL = 'rsorl4rtziefw46fllvh';
Based on the answer by a Cloudinary support team member
... the public_id contains all folders and the last part of the public_id is the filename.
Here is what I tried and worked
const path = require("path");
const getPublicId = (imageURL) => {
const [, publicIdWithExtensionName] = imageURL.split("upload/");
const extensionName = path.extname(publicIdWithExtensionName)
const publicId = publicIdWithExtensionName.replace(extensionName, "")
return publicId
};
especially for cases where you store your assets in folders
I'm trying to pass 'slug' in the URL by adding 'id' and 'type'.
Code:
`/${category.slug}?cid=${category._id}&type=${category.type}`
<Route path="/:slug" element={<ProductListPage />} />
URL
http://localhost:3000/Samsung-3whQlbAYpm?cid=61ed050cab3efd275d49efd6&type=store
Problem : However, in the useParam() I received only slug not addition parameters such as 'cid' and 'type'
For example,
let params = useParams();
Its params have only 'slug' value which is 'Samsung-3whQlbAYpm'
How can I get addition value ?
The useParams hook only gets you the defined route params from the path part of the URL. If you want to access the queryString then use the useSearchParams hook from react-router-dom.
const [searchParams] = useSearchParams();
const cid = searchParams.get("cid");
const type = searchParams.get("type");
If you happen to still be using react-router-dom v5 then use the location object to get the search string to be passed to a URLSearchParams constructor.
const { search } = useLocation();
const searchParams = new URLSearchParams(search);
I am using Axios with NodeJs and trying to pass path parameters in axios.get() method. For example, if URL is url = '/fetch/{date}', I want to replace {date} with the actual date while calling axios.get(url).
I went through the source code on Github and StackOverflow, but couldn't find any method.
Is it possible to keep URLs with parameters as a placeholder and replace them while actually calling the get method of Axios?
Axios doesn't have this feature and it looks like the team don't want to add it.
With credit to previous responders for inspiration, to me this seems like the solution closest to what you (and me) are looking for:
1 - Where you want to store all your URLs and their parameters, define them as functions which use a template string to return the composed URL:
export var fetchDateUrl = (date) => `/fetch/${date}`;
If you need any type-specific formatting of the value being concatenated into the URL, this function is a good place to do it.
2 - Where you want to make the request, call the function with the correct parameters:
import { fetchDateUrl } from 'my-urls';
axios.get(fetchDateUrl(someDateVariable))...;
Another variation, if you really like the idea of naming the parameters at the call site, you can define the URL function to destructure an object like this:
var fetchDateUrl = ({date}) => `/fetch/${date}`;
which you'd then use like this:
axios.get(fetchDateUrl({date: someDateVariable}));
Use template strings
url = `/fetch/${date}`
Or just tag it on
url = '/fetch/'+ date
I think using axios interceptors is better to do this :
//create your instance
const instanceAxios = axios.create({
baseUrl: 'http://localhost:3001'
]);
instanceAxios.interceptors.request.use(config => {
if (!config.url) {
return config;
}
const currentUrl = new URL(config.url, config.baseURL);
// parse pathName to implement variables
Object.entries(config.urlParams || {}).forEach(([
k,
v,
]) => {
currentUrl.pathname = currentUrl.pathname.replace(`:${k}`, encodeURIComponent(v));
});
const authPart = currentUrl.username && currentUrl.password ? `${currentUrl.username}:${currentUrl.password}` : '';
return {
...config,
baseURL: `${currentUrl.protocol}//${authPart}${currentUrl.host}`,
url: currentUrl.pathname,
};
});
// use like :
instanceAxios.get('/issues/:uuid', {
urlParams : {
uuid: '123456789'
}
})
For typescript users, you will need to add this, in one of your .d.ts
declare module 'axios' {
interface AxiosRequestConfig {
urlParams?: Record<string, string>;
}
}
( this is a POC, not really tested, doesn't hesitate if you see something wrong )
You can use template strings ie:
let sellerId = 317737
function getSellerAnalyticsTotals() {
return axios.get(`http://localhost:8000/api/v1/seller/${sellerId}/analytics`);
}
Given some API /fetch/${date} you likely want to wrap your axios call in a function.
const fetchData = (date) => axios.get(`/fetch/${date}`);
fetchData(dateObject.toFormat('yyyy-mm-dd'))
.then(result => { ... });
This requires the calling code to format date correctly however. You can avoid this by using a DateTime library that handles date string parsing and do the format enforcement in the function.
const fetchData = (date) => axios.get(`/fetch/${date.toFormat('yyyy-mm-dd')}`);
fetchData(dateObject)
.then(result => { ... });
you can do like this:
getProduct = (id) => axios.get(`product/${id}`);
I always do it like this:
const res = await axios.get('https://localhost:3000/get', { params: { myParam: 123 } });
I find this to be much clearer than template strings.
More explanation here
Developing web app with node.js and express.
I have following two urls to distinguish:
/api/v1/source?id=122323
/api/v1/source?timestamp=1555050505&count=10
I come up a naive solution. I leave such similar urls to one route method and use if eles to specify solutions, i.e:
if(id){
//solution with id
}
if(timestamp&&count){
//solution with timestamp and count but without id
}
Apparently, this is not clean. Because in the future,I may want to add new field which will make this router huge and ugly.
So How can I overcome this? Or to change url structure.I want to build a Restful api.
Try to put together all the properties in a list and use Array#every to check if all the values in Array evaluates to true.
Maybe something like this:
(( /* req, res */)=>{
// Dummy express Request Object
const req = {
params : {
//id : '123',
count : 10,
timestamp : 1555050505,
newParameter : 'whatever value'
}
}
let { params } = req;
let {
id
, count
, timestamp
, newParameter
} = params;
if(id){
console.log('Action with id');
return;
}
let secondConditionArray = [
count, timestamp, newParameter
];
if( secondConditionArray.every(Boolean) ){
console.log('Second Action')
} else {
console.log('Some values are no truthy')
}
})()
You can get Url parameters with req.params
if(req.params.id){
//solution with id
}
if(req.params.timestamp && req.params.count){
//solution with timestamp and count but without id
}
I need to create url for get which is going to accept array, how in node.js/express extract array from request ?
I need to pass array with names which parametes I need to back from Person
model.
/api/person # here I need to pass which fields I want to see but to be generic.
One option is using a JSON format.
http://server/url?array=["foo","bar"]
Server side
var arr = JSON.parse(req.query.array);
Or your own format
http://server/url?array=foo,bar
Server side
var arr = req.query.array.split(',');
Express exposes the query parameter as an array when it is repeated more than once in the request URL:
app.get('/', function(req, res, next) {
console.log(req.query.a)
res.send(200)
}
GET /?a=x&a=y&a=z:
// query.a is ['x', 'y', 'z']
Same applies for req.body in other methods.
You can encode an array in percent encoding just "overwriting" a field, formally concatenating the values.
app.get('/test', function(req,res){
console.log(req.query.array);
res.send(200);
});
localhost:3000/test?array=a&array=b&array=c
This query will print ['a','b','c'].
Using next code:
app.use('/', (req, res) => {
console.log(req.query, typeof req.query.foo, Array.isArray(req.query.foo));
res.send('done');
});
On backend, you have two standard approaches. For next requests:
/?foo=1&foo=2
/?foo[]=1&foo[]=2
your NodeJS backend will receive next query object:
{ foo: [ '1', '2' ] } 'object' true
{ foo: [ '1', '2' ] } 'object' true
So, you can choose the way you want to. My recommendation is the second one, why? If you're expect an array and you just pass a single value, then option one will interpret it as a regular value (string) and no an array.
[I said we have two standards and is not ok, there is no standard for arrays in urls, these are two common ways that exist. Each web server does it in it's own way like Apache, JBoss, Nginx, etc]
If you want to pass an array from url parameters, you need to follow the bellow example:
Url example:
https://website.com/example?myarray[]=136129&myarray[]=137794&myarray[]=137792
To retrieve it from express:
console.log(req.query.myarray)
[ '136129', '137794', '137792' ]
Express has a tool to check if your path will match the route you are creating : Express.js route tester.
As Jose Mato says you have to decide how to structure your url:
?foo=1&foo=2
?foo[]=1&foo[]=2
The http request should look like this, if you chose method 1:
http://baseurl/api/?foo=1&foo=2
Your route should have this logic:
app.get('/api/:person', (req, res) => {
/*This will create an object that you can iterate over.*/
for (let foo of req.params.foo) {
/*Do some logic here*/
}
});
You can pass array elements separated by slashes -
GET /api/person/foo/bar/...
Define your route as '/api/person/(:arr)*'
req.params.arr will have the first parameter.
req.params[0] will have the rest as string.
You split and create an array with these two.
app.get('/api/person/(:arr)*', function(req, res) {
var params = [req.params.arr].concat(req.params[0].split('/').slice(1));
...
});
GET /api/person/foo
params = ["foo"]
GET /api/person/foo/bar
params = ["foo", "bar"]
...
Here use this, '%2C' is the HTML encoding character for a comma.
jsonToQueryString: function (data) {
return Object.keys(data).map((key) => {
if (Array.isArray(data[key])) {
return encodeURIComponent(`${key}=${data[key].map((item) => item).join('%2C')}`);
}
return encodeURIComponent(`${key}=${data[key]}`);
}).join('&');
}
To access the query params
const names = decodeURIComponent(req.query.query_param_name);
const resultSplit = names.split(',');
Theres a problem when the array param contains only one value, because then it behaves like a simple string. Or when it doesn't contain any value.
Eg.:
?arrayParam=5
?
?arrayParam=5&arrayParam=6
Here's a function that always extracts the param with the given name, as an array:
export function extractArrQueryParams(
req: express.Request,
paramName: string
) {
let param = req.query[paramName];
let returnArray = [];
if (Array.isArray(param)) {
for (let e of param) {
returnArray.push(e);
}
} else {
if (param) {
returnArray.push(param);
}
}
return returnArray;
}