How to process the payload send to an API [duplicate] - json

This question already has answers here:
Unable to get raw POST data when using Classic ASP VBScript
(2 answers)
Closed last year.
Before reading on: This is NOT a question about how to access a REST API. I am NOT asking about communicating with the endpoint, sending it a payload, and parsing the received JSON.
Rather, I AM asking about how to set up that endpoint in vbScript. The endpoint itself, not the code that's going to be sending it messages. My post is asking how to receive the JSON payload. I'm editing the question because people just don't really read a post sometimes, and because of that I'm being told I need to defend my post as NOT being the same as some other post which IS NOT THE SAME. Duh. If people aren't going to read, then how do I explain to them?
Anyway, since I made the original post, somebody ACTUALLY did address my question. It is #user692942 below, who wrote (confirming my suspicion) that if I wanted to do this in vbScript, I was going to have to use Request.BinaryRead, and then posted an actual relevant link (which I had missed in my searching) that talked about some of the ways you could use Request.BinaryRead. But for those who want to read my original post:
In vbScript I am trying to write a REST API that is passed a JSON payload (which it then parses, then it does whatever it needs to do, then responds with a resulting JSON string). I've got the output part working, but I realized that I made a fundamental mistake with the input side. I wrote it expecting to receive standard POSTed fields, NOT a JSON string. When I google this problem, all I can find is how to parse the returned JSON from an endpoint, NOT how to create the endpoint api itself, and how it must be written to properly grab the payload.
Thus, I begin the api code with two simple requests:
email = Request.Form("email")
password = Request.Form("userpassword")
Obviously that's wrong, since I'm not receiving fielded data, but instead trying to grab a JSON payload. How do I write this to input the payload properly. (I know how to do the JSON parse, but I can't get the JSON string!) I realize this borders on a dumb question, but could someone please tell me what obvious thing it is that I am missing? Thanks.

There is a big distinction between a REST API and a piece of software that merely "CALLS" the REST API. The following is a way to create the REST API itself, using only vbScript. This API can reside at a url ending with myrestapi.asp. When some other progrem calls your "end point" and sends a GET or POST request, you could perform any number of interesting tasks on your server, notably interacting with your MSSQL database, before returning whatever it was to be returned, as a JSON string. (THEN, it would be up to your interlocutor to figure out your answer by parsing that JSON. -- But I stress, THAT task is NOT the focus of this post.)
The following relies on the totally free ASPJSON parser (with Response.LCID = 1033).
It also briefly shows the use of Window's command-line curl to run tests.
One of the problems with vbScript is that it is so old, people assume "api-related" problems must mean you're using vbScript to send a command to an end point and get something back in JSON, and a lot of folks ask about and talk about how to do that.
But it's also possible (as I've recently discovered) to create the endpoints THEMSELVES. The difference is that when you are only ACCESSING an API, you are always dealing with structured data. When you ARE the API, if the data coming in is a JSON string, it is UNstructured. It is not a part of a name-value pair.
But it is very possible, with only a little work, to build such a piece of software using only vbScript. The api reads its Request object, bringing in the raw binary data in a format that can be easily converted to a standard vbscript string. At that point, the JSON parser is called, the result of which is the JSON fields, attached to a vbScript object. The retrieval syntax is very concise. Here's a very simple example login with email and password.
Dim tb,br,i,s,jsonObj,incomingParams,email,password,status
tb = Request.TotalBytes
br = Request.BinaryRead(tb)
s = ""
For i = 1 To tb
s = s & Chr(AscB(MidB(br, i, 1)))
Next
' s now contains JSON input
Set jsonObj = New JSONobject ' see note above
Set incomingParams = jsonObj.parse(s)
email = incomingParams("useremail")
password = incomingParams("userpassword")
status = checkEmail email,password ' pre-canned verification function
If status = "good" Then
key = getKey ' precanned routine to get random unique key
jout = "{""loginstatus"":""" & status & """,""loginkey"":""" & key & """}"
Else
key = 0
jout = "{""loginstatus"":""1""}"
End If
Response.ContentType = "application/json"
Response.Write(jout)
And that's it. To try this out, open a Windows cmd window and type:
curl -d "{\useremail\":\"memberemail#gmail.com\",\]"userpassword\":\"rawpassword\"}" -H Content-Type: application/json" https://www.myserver.com/myrestapi.asp
Hit Enter and if you have used an accepted email/password and if you typed the appropriate location for your API endpoint that you're testing, you should see two JSON fields in return, loginstatus, with a 0 (good status) and loginkey with a random sequence, your key.
So now you have your own REST API (of sorts) which CAN be expanded to support a full range of GETs and POSTs. I realize there are a lot of things classic ASP is lacking and that it is often possible to use a more modern language when programming in vbScript. Nevertheless, it's also possible to pull something off in vbScript.

Related

How to process Vue/Axios Json payload posted data on Yii2

It took me a while to understand this, being that it was a little obvious. I will answer myself, so other can benefit of the answer and ofcourse to see if there's a better way to do this. The problem was based on Axios/Yii2 but I guess this will apply equally to other frontend libraries/frameworks sending data to Yii2.
I needed to post data from a small form made on Vuejs, sending the request Axios to a Action/Controller on Yii2, so data is sent on a simple POST request and the post is getting to the controller, but I was not able to receive the data on the action, $_POST | $post arrives empty (checked using xdebug).
As much as I remember, this had something to do with security. But I already tried by disabling public $enableCsrfValidation, so that was not the problem.
public $enableCsrfValidation = false;
But no matter what, data was not being added to the request/post data inside Yii2.
The following Image, explains the problem you will find there:
The Axisos method that sends the post with test data.
The Yii2 Action stpoed at the place, I should be able to see data.
The capture of the xdebug variables and data for the request.
The capture of Chrome where you can check the payload is sent.
The answer is as I said "kind of obvious", but I could not see that, and I am sure some other devs will probably fall on this.
After searching like crazy and asking everyone, I tried sending the request by using Postman app, yup the best thing I know to test apis.
Dont forgue to add the xdebug cookie to be able to debug your PHP Endpoint.
There I found the first clue «the obvious part», I was not sending data as a form-data, Axios and other libraries, send the data as a raw (application/json) payload.
This means that Yii2 will no be able to find the data inside the post request, yes its there but Yii2 magic will not work, neither you will find this data inside $GLOBALS or in $_POST.
So reading the Yii2 documentation I found that inside request I can use a function that will help me recovering the Raw data, so to do this use the following line:
$raw_data = Yii::$app->request->getRawBody();
Now, that data gets to you as a simple, raw json string, so use the power of PHP to parse it to an object.
$object= json_decode($raw_data );
And finally use the data inside by calling the properties you look for, sent on the pay load:
Json Payload:
{
"msg":"This is my payload",
"id":"11"
}
To use it:
echo $object->{'msg'}; // prints: This is my payload
So that's the way to handle that, now I would like some other points of view to see if there's a better way or cleaner way to do this. Hope it helps.

Does using multipart/form-data Content Type for a RESTful POST api a good practice?

I have a situation where I have to write a api to create a resource and amongst datafields that I need to accept is a string that is basically contents of a html file. As I see it I have a choice between structuring the entire thing as a json object where this field is a string field with urlencoded html string , and having the Content Type as multipart/form-data where each of the fields and the html string (UTF-8 encoded) is a part in the message.
Not using json is something I am not comfortable with as I feel violating the REST standards in not structuring the content of the entity I am about to create thus there is a loss of information for the consumers as they can't tell immediately looking at my api definition about what data to feed to it. But practically multipart/form-data handles stuff like html file content better and more efficient as I will not have to urlencode it and can control the char-encoding also.
What will be a better approach in current context and upholding RESTful principles ? Also are there other trade-offs i should be aware of ? what about parsing a json with a huge string field (~ 200 Kb)embedded?
EDIT :- I was reading some similar questions on SO and one approach that stood out was the 2-step approach of making a first call with metadata to create the entity and then upload the file as an UPDATE process to the created entity wherein we use multipart/form-data. In that context, I guess , what I am asking is how sound is an approach where I send both metadata and the file in a single api call as multipart data , where each metadata field is actually a part in the multipart message as is the file.
The canonical way to upload files to REST API is using the multipart/form-data. As W3 recommendation guide says:
The content type "multipart/form-data" should be used for submitting
forms that contain files, non-ASCII data, and binary data.
Multipart/form-data has advantages over base64 to represent binary data. Is sticked to REST/Http philosophy, and simplify the develop of API clients.
Returning values from Forms: multipart/form-data
W3 Recommendation guide
The good practice is to use multipart/form-data whenever files are uploaded to the server along with database fields. Do not send a base64 JSON string as the request to your Rest API as it might corrupt the file or degrade the performance of your application.
As far as documenting multipart/form-data Rest API for your consumers is concerned you have to force your API consumers to use the same form fields which you have predefined in your web service.
Returning Values from Forms: multipart/form-data
I started using FormData objects everywhere on the client-side, in lieu of regular form input fields, for dynamic REST posts. FormData is presented in a positive light in various tutorials, so I went with it.
However, down the line, this caused me problems when decoding the form data into my Go structs. FormData objects are sent as "multipart/form-data" (regardless of files being sent) and I believe my decoder in Go didn't convert the raw data back to string form. Eventually my SQL queries were throwing panics, as hex data was being sent in where strings should have been.
So with some adjustment, I could use FormData however I've decided to revert to the simple universal recommendation: Use "multipart/form-data" only for special cases like when sending files. Otherwise, just use regular "application/x-www-form-urlencoded".

Pentaho HTTP Post using JSON

I'm brand new to Pentaho and I'm trying to do the following workflow:
read a bunch of lines out of a DB
do some transformations
POST them to a REST web service in JSON
I've got the first two figured out using an input step and the Json Output step.
However I have two problems doing the final step:
1) I can't get the JSON formatted how I want. It insists on doing {""=[{...}]} when I just want {...}. This isn't a big deal - I can work around this since I have control over the web service and I could relax the input requirements a bit. (Note: this page http://wiki.pentaho.com/display/EAI/JSON+output gives an example for the output I want by setting no. rows in a block=1 and an empty JSON block name, but it doesn't work as advertised.)
2) This is the critical one. I can't get the data to POST as JSON. It posts as key=value, where the key is the name I specify in the HTTP Post field name (on the 'Fields' tab) and the value is the encoded JSON. I just want to post the JSON as the request body. I've tried googling on this but can't find anyone else doing it, leading me to believe that I'm just approaching this wrong. Any pointers in the right direction?
Edit: I'm comfortable scripting (in Javascript or another language) but when I tried to use XmlHttpRequest in a custom javascript snippet I got an error that XmlHttpRequest is not defined.
Thanks!
This was trivial...just needed to use the REST Client (http://wiki.pentaho.com/display/EAI/Rest+Client) instead of the HTTP Post task. Somehow all my googling didn't discover that, so I'll leave this answer here in case someone else has the same problem as me.
You need to parse the JSON using a Modified JavaScript step. e.g. if the Output Value from the JSON Output is called result and its contents are {"data"=[{...}]}, you should call var plainJSON = JSON.stringify(JSON.parse(result).data[0]) to get the JSON.
In the HTTP Post step, the Request entity field should be plainJSON. Also, don't forget to add a header for Content-Type as application/json (you might have to add that as a constant)

Why use a JSON object to pass data with POST versus a Query String in Perl?

I'm looking to run a script using Stripe.pm, basically looking to do credit card processing. The credit card number is not being passed at all. All the examples I see use a JSON object passed in a POST call but I have a lot of experience using Query Strings i.e.
http://www.example.com/cgi-bin/processingscript.pl?param1=XXXX&param2=YYYYY&param3=ZZZZZ
Is this a security risk? What is the advantage or disadvantage of posting using JSON versus a query string like I'm used to using?
From a purely technical point of view, there is no difference between POST and GET if you pass a reasonably short parameter. You can also just pass JSON as a GET parameter no problem:
GET foo.pl?json={'foo':'bar'}
It would make sense to url-encode the data in this case. You can also send the same request using POST.
If you do not want to use query params at all, you need POST and put your JSON into the request body. Depending on which option you choose, there are differences in how to deal with it in Perl. Let's say you are using the CGI module... Perl makes no difference between POST and GET params.
For the query string GET or POST, you need to do:
use CGI;
my $cgi = CGI->new;
my $json = $cgi->param('json');
If you put the payload directly into the request body, you will instead need to do:
use CGI;
my $cgi = CGI->new;
$cgi->param('POSTDATA');
This is documented in CGI under "handling non url-encoded ...".
For JSON, there is also of course the time it takes to parse it, but that should be negligible.
The advantage JSON has over query strings without JSON inside them is, that you can encode arbitrary complex data structures inside JSON, while plain-text query strings are just one level deep.
From a security point of view, pretty much everything has been said. I'll recap my own ideas:
use SSL
do not put sensitive stuff into log files
if you are dealing with CC data (even if it is not the number itself), take extra care; read up on PCI DSS and encrypt stuff during transmission
NEVER store a cvc!
if you want to learn more about that topic, there is a Stack Exchange site called Information Security.
Security
- making sure no one other than user/server know the data GET/POST has no influence. Use SSL to ensure this.
- Stopping the user passing "interesting" arguments to your script. POST has a certain amount of security-through-obscurity in that most users won't see the parameters, but it's no real security. You should check the parameters in your application to cover that.
Generally POST with a nice data package (e.g. JSON) makes for a much more flexible and maintainable application interface, and has the advantage that you don't need to worry about encoding and length of parameters the same way you do when using GET.
POST:
Generally safer for important data
Parameters not shown in url
You can pass longer Strings-Structures (e.g. JSON) than by using GET that has length limit on the parameters you send

How to change content of Post Body in JMeter HTTP Request

Please forgive my ignorance as I'm a jmeter noob. My webservice accepts JSON objects so I was able to write a rudimentary test where I create an HTTP Request with a JSON object in the "Post Body" portion of the http request.
Anyway, what I want to do is have the HTTP Request choose a different JSON object from a csv file or some other input mechanism so that I can randomize the types of queries that are being run during the load test. Is there a way to do this? The closest is probably using variables (section 4.11 in the user manual) but I have a feeling that's not how variables are used.
A second way I've theorized (although I haven't tried yet since I think the method above is easier) is to create a HTTP Request Default obj with a bunch of HTTP Requests with different JSON objects in them and then use a Random Controller to randomly go thru my multiple HTTP Requests on each pass.
If there's a third way, I'm all ears to learn how to use this tool. I'll continue to read and possibly experiment with plan B above. Thanks in advance for any help you can give me.
UPDATE: So I tried the second way and it seems to work. I had 3 different HTTP requests and the number of times each request gets hit varies from run to run. I still invite answers from the community since I'd like to see what the pros do for issues similar to mine.
You have partially answered your question yourself, by saying "csv file or". Here are the specifics.
You will have to use CSV data set config in your test plan to read data from CSV. In your post body, use the variables read from CSV.
Here is a screen cast showing how to use csv data set config.