URL Encoding and bit.ly - json

I have to shorten the following URL:
https://example.com/engine?key=5&currency=EUR&language=EN&user=&system=HPH&tracking=%7B%22gtm%22%3A%22GTM-WR29KDC%22%7D&navigation=%7B%22ipAddress%22%3A%2284.126.214.206%22%2C%22countryCode%22%3A%22ES%22%2C%22domain%22%3A%22example.com%22%2C%22landingPage%22%3A%22http%3A%2F%2Fexample.com%2Fen%2F%22%2C%22userAgent%22%3A%22Mozilla%2F5.0+%28Macintosh%3B+Intel+Mac+OS+X+10_15_7%29+AppleWebKit%2F537.36+%28KHTML%2C+like+Gecko%29+Chrome%2F109.0.0.0+Safari%2F537.36+Edg%2F109.0.1518.52%22%2C%22device%22%3A%22desktop%22%7D&availability=%7B%22dateFrom%22%3A%222023-01-18T23%3A00%3A00.000Z%22%2C%22dateTo%22%3A%222023-01-20T23%3A00%3A00.000Z%22%2C%22distribution%22%3A%5B%7B%22id%22%3A1%2C%22person%22%3A%5B%7B%22id%22%3A1%2C%22type%22%3A%22Adult%22%2C%22age%22%3A30%7D%2C%7B%22id%22%3A2%2C%22type%22%3A%22Adult%22%2C%22age%22%3A30%7D%5D%7D%5D%2C%22selectedFareProperty%22%3Anull%2C%22mealPlan%22%3Anull%2C%22selectedItem%22%3A%7B%22type%22%3A%22Hotel%22%2C%22code%22%3A%2252774%22%2C%22name%22%3A%22Hotel+de+la+RIERA+Hotel%22%7D%2C%22logged%22%3Atrue%2C%22execute%22%3Atrue%2C%22fromLink%22%3Atrue%7D
It's not pretty, but it's the URL we have to redirect to an hotel availability engine, and it works when not shortened. This is the code that generates it:
const urlParameters = new URLSearchParams(
{
key: key,
currency: currency,
language: language,
user: user || '',
system: system,
tracking: JSON.stringify(tracking || {}),
navigation: JSON.stringify(navigation || {}),
availability: JSON.stringify(parameters)
},
);
return urlParameters.toString();
The problem comes with bit.ly, because when using the shortened URL, it redirects to:
https://example.com/engine?key%3D5%26currency%3DEUR%26language%3DEN%26user%3D%26system%3DHPH%26tracking%3D%257B%2522gtm%2522%253A%2522GTM-WR29KDC%2522%257D%26navigation%3D%257B%2522ipAddress%2522%253A%252284.126.214.206%2522%252C%2522countryCode%2522%253A%2522ES%2522%252C%2522domain%2522%253A%2522example.com%2522%252C%2522landingPage%2522%253A%2522http%253A%252F%252Fexample.com%252Fen%252F%2522%252C%2522userAgent%2522%253A%2522Mozilla%252F5.0%2B%2528Macintosh%253B%2BIntel%2BMac%2BOS%2BX%2B10_15_7%2529%2BAppleWebKit%252F537.36%2B%2528KHTML%252C%2Blike%2BGecko%2529%2BChrome%252F109.0.0.0%2BSafari%252F537.36%2BEdg%252F109.0.1518.52%2522%252C%2522device%2522%253A%2522desktop%2522%257D%26availability%3D%257B%2522dateFrom%2522%253A%25222023-01-18T23%253A00%253A00.000Z%2522%252C%2522dateTo%2522%253A%25222023-01-20T23%253A00%253A00.000Z%2522%252C%2522distribution%2522%253A%255B%257B%2522id%2522%253A1%252C%2522person%2522%253A%255B%257B%2522id%2522%253A1%252C%2522type%2522%253A%2522Adult%2522%252C%2522age%2522%253A30%257D%252C%257B%2522id%2522%253A2%252C%2522type%2522%253A%2522Adult%2522%252C%2522age%2522%253A30%257D%255D%257D%255D%252C%2522selectedFareProperty%2522%253Anull%252C%2522mealPlan%2522%253Anull%252C%2522selectedItem%2522%253A%257B%2522type%2522%253A%2522Hotel%2522%252C%2522code%2522%253A%252252774%2522%252C%2522name%2522%253A%2522Hotel%2Bde%2Bla%2BRIERA%2BHotel%2522%257D%252C%2522logged%2522%253Atrue%252C%2522execute%2522%253Atrue%252C%2522fromLink%2522%253Atrue%257D
Which seems to be encoded again, and the link doesn't work.
If I try to shorten the decoded URL, it doesn't work either, because not everything is encoded:
/engine?key=5&currency=EUR&language=en&user=&system=HPH&tracking={%22gtm%22:%22GTM-WR29KDC%22}&navigation={%22ipAddress%22:%2284.126.214.206%22,%22countryCode%22:%22ES%22,%22domain%22:%22demo.pre.new.hotetec.com%22,%22landingPage%22:%22http://demo.pre.new.hotetec.com/en/%22,%22userAgent%22:%22Mozilla/5.0+(Macintosh%3B+Intel+Mac+OS+X+10_15_7)+AppleWebKit/537.36+(KHTML,+like+Gecko)+Chrome/109.0.0.0+Safari/537.36+Edg/109.0.1518.52%22,%22device%22:%22desktop%22}&availability={%22dateFrom%22:%222023-01-18T23:00:00.000Z%22,%22dateTo%22:%222023-01-20T23:00:00.000Z%22,%22distribution%22:[{%22id%22:1,%22person%22:[{%22id%22:1,%22type%22:%22Adult%22,%22age%22:30},{%22id%22:2,%22type%22:%22Adult%22,%22age%22:30}]}],%22selectedFareProperty%22:null,%22mealPlan%22:null,%22selectedItem%22:{%22type%22:%22Hotel%22,%22code%22:%2252774%22,%22name%22:%22Hotel+de+la+RIERA+Hotel%22},%22logged%22:true,%22execute%22:true,%22fromLink%22:true}
I'm very likely doing something wrong here, but I don't see how to fix it. I'm using node-bitly 7.1.2 and calling bitly.shorten(myUrl).

Related

IPFS file extension for GLB

I'm using the ipfs-http-client module to interact with IPFS. My problem is that I need the file extension on the link that I generate, and it seems that I can only get it with the wrapWithDirectory flag (-w with the command line). But this flag makes the result empty so far. The documentation on IPFS is only about the command line, and I've only found out a few tutorials about how to do it, but with other tool than JS, or by uploading folders manually. I need to do it from a JS script, from a single file. The motivation is that I want to generate metadata for an NFT, and a metadata field requires to point to a file with a specific extension.
Full detail: I need to add a GLB file on Opensea. GLB are like GLTF, it's a standard for 3D file. Opensea can detect the animation_url field of the metadata of an NFT and render that file. But it needs to end with .glb. Translation, my NFT needs its metadata to look like that:
{
name: <name>,
description: <description>,
image: <image>,
animation_url: 'https://ipfs.io/ipfs/<hash>.glb' // Opensea requires the '.glb' ending.
}
The way I do this so far is as follows:
import { create } from 'ipfs-http-client';
const client = create({
host: 'ipfs.infura.io',
port: 5001,
protocol: 'https',
headers: { authorization },
});
const result = await client.add(file); // {path: '<hash>', cid: CID}
const link = `https://ipfs.io/ipfs/${result.path}` // I can't add an extension here.
In that code, I can put animation_url: link in the metadata object, but OpenSea won't recognize it.
I have tried adding the option mentioned above as well:
const result = await client.add(file, {wrapWithDirectory: true}); // {path: '', cid: CID}
But then result.path is an empty string.
How can I generate a link ending with .glb?
Found out the solution. It indeed involves creating a directory, which is the returned CID, so that we can append the file name with its extension at the end. The result is https://ipfs.io/ipfs/<directory_hash>/<file_name_with_extension>.
So, correcting the code above it gives the following:
import { create } from 'ipfs-http-client';
const client = create({
host: 'ipfs.infura.io',
port: 5001,
protocol: 'https',
headers: { authorization },
});
const content = await file.arrayBuffer(); // The file needs to be a buffer.
const result = await client.add(
{content, path: file.name},
{wrapWithDirectory: true}
);
// result.path is empty, it needs result.cid.toString(),
// and then one can manually append the file name with its extension.
const link = `https://ipfs.io/ipfs/${result.cid.toString()}/${result.name}`;

How to send selected Radio Button through JSON

I am creating a REST API and that will receive JSON data through POST. I'm creating the structure of the JSON now and was wondering what is considered best practice for how to send data signifying which Radio Button was selected on the sender's side. I thought of 3 possible ways to do it, but I'm open to other options if there's something better. Here are the 3 ways with UPS, FedEx and USPS being the sample options:
"UPS": false,
"FedEx": true,
"USPS": false
"ShippingCompany": 2 // 1 for UPS, 2 for FedEx, 3 for USPS
"ShippingCompany": "FedEx"
It depends on the use case and on who's consuming the API.
Your first solution is the least favorable of these three, since you want to implement a radio button. This would be more of a checkbox situation.
Variant 2 and 3 are interchangeable, but I'd use 3, since it's obvious what company you mean, instead of having to look up the meaning of the integers.
To go even further you could take a look at enums and their definition in openapi.
You can get it easily with querySelector:
let el = document.querySelector("input[name=radioName]:checked");
let val = el !== null ? el.value : "";
In your json you use like:
json = {
radioName: val
}
And then, to post, perhaps you may have to stringfy the json. Here is a sample code using the Fetch Api and recieves a json from the backend.
const getAllIncidents = () => {
var reqHeaders = new Headers();
var reqInit = { method: 'GET',
headers: reqHeaders,
mode: 'cors',
cache: 'default' ,
body: JSON.stringify( {
radioName: val
})
};
fetch(service_url, reqInit)
.then( r => {
return r.json();
}).then( json => {
console.log(json);
});
}
Obs 1.: querySelector returns null if the selector returns no element.
Obs 2.: remember using the same name for the radio button collection and diferent id for each one.

How to capture an attribute from a random JSON index in serverless artillery

In Artillery, how can I capture the attribute of a random index in a JSON array returned from a GET, so my subsequent POSTs are evenly distributed across the resources?
https://artillery.io/docs/http-reference/#extracting-and-reusing-parts-of-a-response-request-chaining
I'm using serverless artillery to run a load test, which under the hood uses artillery.io .
A lot of my scenarios look like this:
-
get:
url: "/resource"
capture:
json: "$[0].id"
as: "resource_id"
-
post:
url: "/resource/{{ resource_id }}/subresource"
json:
body: "Example"
Get a list of resources, and then POST to one of those resources.
As you can see, I am using capture to capture an ID from the JSON response. My problem is that it is always getting the id from the first index of the array.
This will mean in my load test I end up absolutely battering one single resource rather than hitting them evenly which will be a more likely scenario.
I would like to be able to do something like:
capture:
json: "$[RANDOM].id
as: "resource_id"
but I have been unable to find anything in the JSONPath definition that would allow me to do so.
Define setResourceId function in custom JS code and to tell Artillery to load your custom code, set config.processor to the JS file path:
processor: "./custom-code.js"
- get:
url: "/resource"
capture:
json: "$"
as: "resources"
- function: "setResourceId"
- post:
url: "/resource/{{ resourceId }}/subresource"
json:
body: "Example"
custom-code.js file containing the below function
function setResourceId(context, next) {
const randomIndex = Math.round(Math.random() * context.vars.resources.length);
context.vars.resourceId = context.vars.resources[randomIndex].id;
}
Using this version:
------------ Version Info ------------
Artillery: 1.7.9
Artillery Pro: not installed (https://artillery.io/pro)
Node.js: v14.6.0
OS: darwin/x64
The answer above didn't work for me.
I got more info from here, and got it working with the following changes:
function setResourceId(context, events, done) {
const randomIndex = Math.round(Math.random() * (context.vars.resources.length - 1));
context.vars.resourceId = context.vars.resources[randomIndex].id;
return done();
}
module.exports = {
setResourceId: setResourceId
}

why is html5 form input saying required when optional

So I have a html5 form with input fields. Lets say the fields are first name, last name, phone, email, and address.
Now first, last, and address are required while phone and email are optional. I know that the backend has this configured properly. However on the html5 form it will not let me submit without phone or email otherwise it returns a 400 error.
If I remove the optional from the html5 form, it will let me submit it or I can put in a value=" " and will submit also. I can even tag the fields with CSS3 using :required and :optional and it will show appropriately but still won't let me submit.
Now I obviously can't just remove the optional from the html because some users may need those fields but I also don't want to send a default value of " " or "n/a" for users who don't need them. Am I just doing something wrong here or what? I don't get what is going on.
edit 2: This is a node.js api using Hapi.js with Joi validation, request, and couchdb.
edit: I know that 400 is a server error but if I post with a curl omitting the optional ones it goes through fine. It also goes through fine when I remove the optional ones from the html which is why it doesn't make sense. Here is the validation code server side for the api.
handler: function(req, res) {
request({
method: 'POST',
uri: 'https://127.0.0.1:6984/banned',
jar: cookieJar,
strictSSL: false,
json: {
firstn: req.payload.firstn,
lastn: req.payload.lastn,
licno: req.payload.licno,
phone: req.payload.phone,
email: req.payload.email,
address: req.payload.address,
description: req.payload.description
}
},
function(err, resp, body) {
if (err) { res(err) };
if (resp.statusCode === 401) {
res(resp.statusCode + ' Please log in.');
}
else if (resp.statusCode === 201) {
res(body);
}
});
},
validate: {
payload: {
firstn: Joi.string().required(),
lastn: Joi.string().required(),
licno: Joi.string().optional(),
phone: Joi.string().optional(),
email: Joi.string().optional(),
address: Joi.string().optional(),
description: Joi.string().required()
}
}
So a friend helped me figure it out. What is happening is that required or not the html form is sending with a value of "" if no data is put in. That is not " ", "null", "undefined" just "". This is not a valid value for the server so it throws the 400 error. The code that fixed it was by checking if the payload exists before validating and sending it through.

Can't Read Twitter Json

I'm a total loss. I have this function to read the Twitter Json. The Json is valid but the value is coming back as 'undefined' when I run it.
$.getJSON("http://twitter.com/users/show.json?screen_name=starbucks&callback=?" , function(data) {
var testing = (data.length);
alert(testing);
})
data is an object* not an array** so it doesn't have a length property.***
Use a debugger like Firebug, Safari/Chrome dev tools and use this code instead:
$.getJSON("http://twitter.com/users/show.json?screen_name=starbucks&callback=?" ,
function(data) {
console.log(data);
});
and you can see that the data is coming back to you perfectly.
Try this to see what I mean, preferably with a JavaScript console available.
*e.g., something that looks like {key: value, ...}; also known as a hash or an associative array
**e.g., something that looks like: [foo, bar, baz, ...]
*** unless, of course, someone was evil and constructed the object like so:
data = {
...
length: 8675309,
...
};