Construct form-data with duplicate keys in Nodejs client post request body - node.js

I am trying to make a post request which body consists of form-data. But the API rest spec, says the form data should look like this :
names[]= company name 1&names[]=company name 2
I tried
form: {'names[]': "google" ,'names[]': "kraft", 'fields[]': "Country",
'fields[]':"ISIN"}
But the server receives only the first names[] and fields[]. The second ones are cut.
Server: Post data: {"names"=>["kraft"], "fields"=>["ISIN"]}
Then I tried to add array as value:
form: {'names[]': ["google", "kraft"], 'fields[]': ["Country","ISIN"] }
Server: Post data: {"names"=>[{"0"=>"google", "1"=>"kraft"}], "fields"=>[{"0"=>"Country", "1"=>"ISIN"}]}
Looking at the server request, I see that it accepts body in this format:
BODY: names[]=google&names[]=kraft&fields[]=ISIN&fields[]=Country
But I cant construct such form in my node-client side.
I am using this library: https://www.npmjs.com/package/request
********* EDIT ********
This one actually woked:
form: "names[]=google&names[]=kraft&fields[]=Country&fields[]=ISIN"
Now the question is how to form this string using https://github.com/form-data/form-data
No append doesn't work I tried.

It's recommended for keys to be unique and not have brackets in their naming. In your case, names[] and fields[] repeat themselves
const form = {
form: {
names: ['google', 'kraft'],
fields: ['Country', 'ISIN']
}
};
request.post('http://yourwebsite.com', form);
EDIT
names[]=google&names[]=kraft&fields[]=ISIN&fields[]=Country
May be valid, but depending on framework/language, only one entry will be taken into consideration (first or last). So it is equivalent to
names[]=google&fields[]=ISIN // considering first are chosen
Also as you can see
Server: Post data: {"names"=>["kraft"], "fields"=>["ISIN"]}
The brackets were filtered out, so this will be again the same thing
names=google&fields=ISIN // considering first are chosen

Related

Persist data sent to a Pug template via render

I'm trying to find out how I can persist the data I pass to my Pug template from the Express render method.
I pass in some JSON data to the res.render() method in Express that renders my view with Pug. On the Pug template, I use that data immediately to populate one of my select elements with drop down values from the JSON data.
What I want to then do is store this data that was passed so I can use it in an event handler function I create for another field.
Basically, I'm passing a table name and the field names for the table, but for each table I have in the JSON data.
So the shape is like [{ tableName: "table name here", fieldNames: ['field1', 'field2', ...] }, ... ]
I have a select field for "choose a table name" and when the user picks a table name, I then want to get the fieldNames for a second select field that allows them to choose a field name to use. So I have an event handler setup on the "choose a table name" field that runs a little event handler I have setup in the pug template. Only problem is the event handler does not have access to the data that was passed to the Pug template originally.
I'm trying to google this but having no luck finding anything, so does anyone know how I can persist data sent via the res.render() method in a pug template for using after the page has been rendered inside an event handler or other functions?
Thank you!
Always be clear what is done at the server (pug) and what is done in client Javascript (browser).
While data passed to pug scripts are meant to be consumed at the server, it is possible to inject, for want of a better word, server data into client side Javascript variables.
The following creates two dropdown lists on the same page using the exact same data passed by Express. One is generated at the server, while the second is created entirely by Javascript running in the browser.
Express code:
app.get("/testdata", (req, res) => {
res.render("testdata", { data: [ 1, 2, 3, 4, 5]});
});
testdata.pug:
html
head
body
p Dropdown list generated at the server:
p
select
each n in data
option(value=n)=n
br
p Dropdown list generated in browser Javascript:
p
select#dropdown
script.
document.body.onload = () => {
const dropdown = document.getElementById("dropdown");
let data = JSON.parse(`!{JSON.stringify(data)}`); // line 18
data.forEach(d => {
const item = document.createElement("option");
item.innerText = d;
dropdown.appendChild(item);
})
}
I have used the same variable name in totally different contexts pointing to different entities. Be careful not to trip. For example, look at line 18:
let data = JSON.parse(`!{JSON.stringify(data)}`); // line 18
The first instance of data is a Javascript variable in the browser.
The second instance of data is a server object passed to the pug script in the render method. Basically any !{expression} instances found in a pug file are evaluated¹ when the view is rendered.
¹ I think the expression is evaluated and its toString method called. If I know it is an array, I could have used:
let data = [!{data}]; // line 18

Add additional links response to knowledge base in DialogFlow

With knowledge bases in DialogFlow you can have a basic FAQ upload. First column is the question and second is the answer. Often we need to have the answer provide an additional link. e.g., "The answer to your question is no, pineapple does not go on pizza". More info
What I want to provide is the answer followed by a rich response link. Since you cannot have a 3rd column in the spreadsheet to add a link, how can I do this cleanly? Sure, I can just have the link as part of the answer text, but that's not as pretty.
I was able to duplicate the question and then provide a link as the second answer (i.e., $Knowledge.Answer(2)) but then some answers don't have links and I can't make this conditional.
I assume I can do this in Fulfilment but I'm not sure of the actual code that can return the answer ($Knowledge.Answer(1)) and then conditionally add a rich response with a link.
I finally worked it out.
First, I used some delimiter in my answer (here just 'Z$Z').
For example, in the csv file I put the following in a second column:
The answer to your question is no, pineapple does not go on pizza$Z$More Info$Z$https://www.mashed.com/183299/the-most-controversial-pizza-toppings-explained/
This way when I get to the fulfillment I can just parse the answer.
Here's a cut of the code:
exports.dialogflowFirebaseFulfillment = functions.https.onRequest((request, response) => {
const agent = new WebhookClient({ request, response });
console.log('Dialogflow Request headers: ' + JSON.stringify(request.headers));
console.log('Dialogflow Request body: ' + JSON.stringify(request.body));
// save off the answer to parse
let answer = JSON.stringify(request.body.queryResult.fulfillmentText);
function faqHandler(agent) {
let answerAlt = answer.slice(1,-1); // remove first and last double quote
let answerParse = answerAlt.split("Z$Z"); // parse the answer
if( answerParse.length == 1) {
// no links
agent.add(answerParse[0].toString());
} else {
// display the content with the text and links
// you can use different ways here to display but you have access to
// the answer, title, and url as follows
// answerParse[0].toString(), answerParse[1].toString(), answerParse[1].toString()
}
}
...
intentMap.set('Knowledge.KnowledgeBase.ID_OF_KNOWLEDGEBASE',faqHandler);

How to send a Post query using Excel Power Query

I am trying to retrieve data from the Betfair API and have to send some extra info as headers and Json data. Details below:
Url:
https://api.betfair.com/exchange/account/json-rpc/v1
Headers:
{ 'X-Application' :'exampleappid', 'X-Authentication' :'examplesessionkey','Content-Type':'application/json' }
formdata:
{"jsonrpc": "2.0","method": "AccountAPING/v1.0/getAccountStatement", "params": {"itemDateRange":{},"includeItem":"ALL"}, "id": 1}
Currently in excel I go to the Data tab then click on New Query>From Other Sources>From Web>Advanced then I type in the url and the headers in the respective fields. Where do I put in the other form data, or its just not possible?
Edit:
I have created the following query in the query editor :
let
formdata = "{""jsonrpc"": ""2.0"",""method"": ""AccountAPING/v1.0/getAccountStatement"", ""params"": {""itemDateRange"":{},""includeItem"":""ALL""}, ""id"": 1}" ,
Source = Web.Contents("https://api.betfair.com/exchange/account/json-rpc/v1",[Headers= [#"X-Application"="appkey", #"X-Authentication"="sessionkey", #"Content-Type"="application/json"],
Content=Text.ToBinary(formdata)])
in
Source
and I get the following error DataSource.Error: The server committed a protocol violation. Section=ResponseHeader Detail=Header name is invalid
Details:
https://api.betfair.com/exchange/account/json-rpc/v1
Unfortunately I don't think there is a field in the UI for web connections to set the formdata, but it can be done by manually setting up the connection. I think what you have without the formdata would look like this in the M code
Web.Contents(
"https://api.betfair.com/exchange/account/json-rpc/v1",
[Headers=[#"X-Application"="exampleappid", #"X-Authenticaion"="examplesessionkey", #"Content-Type"="application/json"]]
)
There is a "Content" field that can be added after the Headers. In most examples I've seen (and I recall doing this myself once though I don't remember what for), you setup a string for the form data and use Text.ToBinary before passing it into the Content field. So a full query would look something like this:
let
formdata = "{""jsonrpc"": ""2.0"",""method"": ""AccountAPING/v1.0/getAccountStatement"", ""params"": {""itemDateRange"":{},""includeItem"":""ALL""}, ""id"": 1}" ,
Source =
Web.Contents(
"https://api.betfair.com/exchange/account/json-rpc/v1",
[
Headers=[#"X-Application"="exampleappid", #"X-Authenticaion"="examplesessionkey", #"Content-Type"="application/json"],
Content = Text.ToBinary(formdata)
]
)
in
Source

Can Cloudant list/show functions return objects and arrays(any JSON)?

As per the API documentation for Cloudant: Show function can be used to render a document in a different format or extract only some information from a larger document. Same is the case for a list function, the only difference is that it applies on a set of documents. I created a design document with a show function as follows:
{ "shows": { "showDemo":"function(doc,req){return {'body': doc, 'headers':{'Content-Type':'application/json'}}}" } }
When I use this function, _design/showFunc/_show/showDemo/doc1, I get the following error:
{ "error": "unknown_error", "reason": "badarg", "ref": 1793182837 }
I have observed the same error when the show function returns an array. However, no error is given when HTML,Text, XML is returned. Can we say that list/show functions can only return data in a format other than JSON? This example shows the "Accept" header for req object request Object.
What's happening here is that the show function needs to return a response object. From the docs (see http://docs.couchdb.org/en/2.1.0/json-structure.html#response-object) the body field needs to be a string, so you can return whatever you like but it needs to be stringified or otherwise turned into a format that can be sent as HTTP.
If you want to send JSON then doing JSON.Stringify(doc) as the value for body should do what you expect.

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