node.js - how to work with flexible numbers of parameters? - node.js

Take a look in this call:
//http://myserver.com/products/list/categories/
//http://myserver.com/products/list/categories/shoes/
//http://myserver.com/products/list/categories/shoes/woman
//http://myserver.com/products/list/categories/shoes/woman/leather
It's like a webshop where you will have a root category and undefined number of categories
So, on my node.js code, I'd like to implement a sort of flexible number of categories and I don't know how to work in this way. Never did it before.
I've the sentence bellow, but this will allow me to work with a single argument.
app.get('/arg1:/products/list/categories/:argument', productsCategories.index);
I can do such things like place a very good amount of parameters such as:
app.get('/arg1:/products/list/categories/:par1:', productsCategories.index);
app.get('/arg1:/products/list/categories/:par1:/par2', productsCategories.index);
app.get('/arg1:/products/list/categories/:par1:/par2:/par3', productsCategories.index);
//...par4, par5,par6......par20
and mat to the same file and test the parameters. but I don't this that's the best way. Any clue ?

You could possibly use a regex to capture the routes and then split them.
app.get(/^\/(.+?)\/products\/list\/categories\/((?:[^\/]+\/?)+)/, function(req, res) {
// /test/products/list/categories/shoes/woman/leather would return [['test'],['shoes','woman','leather']]
var webShopId = req.params[0];
var categories = req.params[1].split('/');
});

Related

How do I query the vimeo api for a specific video title?

Hi I'm querying for a specific video by title - and at the moment I get mixed results.
my videos are all named with a consecutive number at the end ie ANDNOW2022_00112, ANDNOW2022_00113 etc
When I search /videos/?fields=uri,name&query=ANDNOW2022_00112 I get all of the videos returned
I've also tried the query_fields using
/me/videos?query_fields=title&sort=alphabetical&query=ANDNOW2022_00112
I just want the one I've searched for - or a no results returned.
At the moment I get all of the videos with AN2022 in the title/name. Now 'usually' the one I searched for is at the top of the list but not everytime.
Any tips appreciated.
Okay I'm not going mad :)
This is from Vimeo and is here for those with the same issue - basically to get t to work you need to understand that:
After speaking with our engineers, the current search capability are not "Exact" search.
When adding numbers or underscores the search is split into parts so "ANDNOW2022_00112" is transforming the query into the parts "andnow2022", "andnow", "2022", and "00112". So this is why your seeing these results. Our engineering team are in the process of improving the search capabilities and hope to provide a release in the near future.
Which means for now I'll have to rename my files.
Preface:
Vimeo does not currently offer an API endpoint for exact title search — but even if it did — it's possible to upload multiple videos and assign them identical titles. There's no way to use the API to positively identify a video by title — this is why every uploaded video is assigned a unique ID.
Solution:
Because the API returns data which includes an array of video objects, you can solve this problem in the same way you'd solve any similar problem in JavaScript where you have to find an element in an array: Array.prototype.find()
Here's how you can apply it to your problem:
Query the API using the parameters you described in your question.
You might also be interested in using the sort and direction parameters for greater control over a deterministic sort order.
Find the first item in the returned array of video objects that match your expected text exactly, and return it (or undefined if it doesn't exist)
Here's a code example with some static data from the API that was used to search for the video Mercedes Benz from the user egarage — note that I've omitted quite a few (irrelevant) fields from the response in order to keep the example small:
// Mocking fetch for this example:
function fetch (_requestInfo, _init) {
const staticJson = `{"total":2,"page":1,"per_page":25,"paging":{"next":null,"previous":null,"first":"/users/egarage/videos?query_fields=title&query=Mercedes%20Benz&sort=alphabetical&direction=asc&page=1","last":"/users/egarage/videos?query_fields=title&query=Mercedes%20Benz&sort=alphabetical&direction=asc&page=1"},"data":[{"uri":"/videos/61310450","name":"50th Anniversary of the Pagoda SL -- Mercedes-Benz Classic Vehicles","description":"Penned by designer Paul Bracq, the W113 SL had big shoes to fill: it had the incredible task of succeeding the original and instantly iconic 300 SL Gullwing. But you can't copy a legend, so Bracq designed one of his own. Straight lines replaced curves and a low-slung roof was replaced by a high top design that gave the car its nickname: the Pagoda.\\n\\nMUSIC: Developer Over Time","type":"video","link":"https://vimeo.com/61310450"},{"uri":"/videos/55837293","name":"Mercedes Benz","description":"To celebrate Mercedes Benz 125th birthday, the 2011 Pebble Beach Concours d’Elegance showcased the models that trace the lineage to Benz and Daimler —particularly Mercedes-Benz. This tribute chronicled early racing greats, coachbuilt classics, and preservation cars. Produced in association with DriveCulture.","type":"video","link":"https://vimeo.com/55837293"}]}`;
return Promise.resolve(new Response(staticJson));
}
async function fetchVideoByTitle (token, userId, videoTitle) {
const url = new URL(`https://api.vimeo.com/users/${userId}/videos`);
url.searchParams.set("query_fields", "title");
url.searchParams.set("query", videoTitle);
url.searchParams.set("sort", "alphabetical");
url.searchParams.set("direction", "asc");
const headers = new Headers([
["Authorization", `Bearer ${token}`],
]);
const response = await fetch(url.href, {headers});
const parsedJson = await response.json();
// Find the video that matches (if it exists):
const maybeFirstVideoObj = parsedJson.data.find(video => video.name === videoTitle);
return maybeFirstVideoObj;
}
async function main () {
const video = await fetchVideoByTitle(
"YOU_ACTUAL_TOKEN",
"egarage",
"Mercedes Benz",
);
console.log(video); // {name: "Mercedes Benz", link: "https://vimeo.com/55837293", ...}
}
main();

Different variable name case convention in one application

This is a really trivial problem. I am just curious on how to deal with this in a "professional" manner.
I am trying to stick to variable naming convention. For NodeJs I am doing camelCasing. For database, I am using PostgreSQL and using underscore_casing.
Now the problem arises when I query data from PostgreSQL. I'll get a user object with following format,
{user_id: 1, account_type : "Admin"}
I can pass this object directly to server side-render and will have to use underscore casing to access account_type. Of course, I can manually create a new user JSON object with property userId and accountType but that is unnecessary work.
Is it possible to follow variable naming convention for both language and avoid having mixed variable names casing in some files? What is a good way to stay organized?
The are two good ways to approach this issue. The simplest one - do no conversion, use the exact database names. And the second one is to camel-case columns automatically.
Either way, you should always follow the underscore notation for all PostgreSQL declarations, as it will give you the option to activate camel-casing in your app at a later time, if it becomes necessary. Never use camel-case inside the database, or you will end up in a lot of pain later.
If you want the best of both worlds, follow the underscore notation for all PostgreSQL declarations, and convert to camel-case as you read data.
Below is an example of how to do it properly with pg-promise, copied from event receive example:
// Example below shows the fastest way to camelize column names:
const options = {
receive(e) {
camelizeColumns(e.data);
}
};
function camelizeColumns(data) {
const template = data[0];
for (var prop in template) {
const camel = pgp.utils.camelize(prop);
if (!(camel in template)) {
for (var i = 0; i < data.length; i++) {
const d = data[i];
d[camel] = d[prop];
delete d[prop];
}
}
}
}
Also see the following article: Pg-promise and case sensitivity in column names.
UPDATE
The code above has been updated for use of pg-promise v11 or later.
I've struggled with this too, and I've concluded that there's really no way to avoid this kind of ugliness unless you rewrite the objects that come from the database. Fortunately, that's not too difficult in Javascript:
const fromDBtoJS = (obj) => {
// declare a variable to hold the result
const result = {};
// iterate over the keys on the object
Object.keys(obj).forEach((key) => {
// adjust the key
const newKey = key.replace(/_[a-z]/g, (x) => x[1].toUpperCase());
// add the value from the old object with the new key
result[newKey] = obj[key];
});
// return the result
return result;
};
Here's a JSFiddle. The "replace" code above was found here
If you wanted to use classes for models in your application, you could incorporate this code into the constructor or database load method so it's all handled more-or-less automatically.

How can I know which input send a certain opnedfiles in formidable?

After this question:
How set a function into limits parameters on multer?
that it doesn't receive an answer, I'm looking for an alternative and I'm seeing formidable.
I found different tutorial and now I have this code:
exports.formidable= function (req, res, cb){
        var form = new formidable.IncomingForm();
        form.multiples = true;
        form.parse(req, function(err, fields, files) {
            res.end(util.inspect({fields: fields, files: files}));
        });
        form.on('end', function(fields, files) {
            for(var i = 0; i < this.openedFiles.length; i++) {
                /* Temporary location of our uploaded file /
                var temp_path = this.openedFiles[i].path;
                / The file name of the uploaded file /
                var file_name =Date.now()+"-"+ this.openedFiles[i].name;
                / Location where we want to copy the uploaded file */
                var new_location = './files/';
                fs.move(temp_path, new_location + file_name, function (err) {
                    if (err) {
                        console.error(err);
                    } else {
                        console.log("success!")
                    }
                });
            }
        });
        return;
};
Now, if I iterate files in the first part of the code I receive some thing like [{input_file1:{file's attributes}},
{input_file2:{file's attributes}}]
and iterating openedFiles:
[{0: {file's attributes},
{1:file's attributes}}]
Now, can I be certain the both objects are in the same order?
And, if the answer, as I suppose, is not, can I retrieve the input name from the second object?
If it's impossible, there are some workaround to do that?
Thanks for your help!
I found a "dirty" solution but for now it works fine so I want share with you my code.
In rules_upload.js I add this code:
var tmp='';
var x=0;
form.on('fileBegin', function(name, file) {
if(x>0)
{
this.openedFiles[(x-1)].fieldName=tmp;
}
x++;
tmp=name;
});
        form.on('end', function(fields, files) {
this.openedFiles[(this.openedFiles.length-1)].fieldName=tmp;
So I adda new attribute called fieldName to retrieve this information!

Setting a model attribute to a value based on, but not equal to, the input in angular-formly

I'm trying to figure out how to parse a form entry to set the model attribute to something else; e.g., extracting the video ID of a youtube video from a URL input. Is there a way to use parsers/formatters (6.21 features?) to accomplish this easily? I hoped to find a good example for this, and maybe there is one somewhere, but perhaps this would make a good one if there's not.
Here is a working example of what I'm attempting to accomplish, but in multiple steps and without the use of parsers. Any help adapting the code to set model.videoID from a URL in a single step (or fewer than 3 steps, at least) would be very appreciated. Thank you for your help with this and my other past questions. :)
Wow, this was much easier than I expected to implement. Here is the modification of the JS Bin which uses parsers, recently added with angular-formly#6.21.0, to extract the video ID from a YouTube URL in one function. It also, conveniently, validates itself!
Here is the relevant code, to summarize:
{
key: 'vidid',
type: 'input',
parsers: [extractID],
templateOptions: {
label: 'YouTube Video',
placeholder: 'Insert video URL here'
},
...
function extractID(value) {
if (value != undefined || value != '') {
var regExp = /^.*(youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=|\&v=|\?v=)([^#\&\?]*).*/;
var match = value.match(regExp);
if (match && match[2].length == 11) {
return match[2];
}
}
};

How can i pass input argument when writing loopback-testing

I am writing a test driven development for my strongloop API code with the help of loopback-testing .
Here they do not have any detailed document on this, so i am stuck with case of argument passing with the API call
Example i have a below case,
Method : PUT
URL : /api/admin/vineyard/<vineyard_id>
i need to pass the below arguments with this URL
1. 'vineyard_id' is a id of vine, it should be an integer .
2. in header = 'token'
3. in body = '{'name':'tastyWine','price':200}'
How can i pass these three arguments with this API ?
I can easily handle ,if there is only two types of arguments
Example :
Method : POST
`/api/user/members/<test_username>/auth'`
arguments : test_username and password
I can handle this like this ,
lt.describe.whenCalledRemotely('POST',
'/api/user/members/'+test_username+'/auth', {
'password': test_passwords
},
But how can i handle the above case , Many thanks for your answers for this example.
I'm not entirely sure what your specific problem is, but I will attempt to walk through everything you should need.
I am assuming you are using the predefined prototype.updateAttributes() method for your model as described here.
Next assumption is that you want to use the built-in authentication and authorization to allow the user to call this method. Given that assumption, you need something like this in your test code:
var vineyard_id = 123; //the id of the test item you want to change
var testUser = {email: 'test#test.com',password: 'test'};
lt.describe.whenCalledByUser(testUser, 'PUT', '/api/admin/vineyard/'+vineyard_id,
{
'name':'tastyWine',
'price':200
},
function () {
it('should update the record and return ok', function() {
assert.equal(this.res.statusCode, 200);
});
}
);
If you are using the out-of-the-box user model, you should be fine, but if you extended the model as is commonly done, you may need something like this early on in your test file:
lt.beforeEach.withUserModel('user');
Also, be aware of a few (currently incomplete) updates to will allow for better handling of built-in model extensions: Suggestions #56, Add support for non-default models #57, and givenLoggedInUser() function throws error #59.

Resources