vibed: How can I handle POST request? - post

Could anybody help me to handle POST request, I read docs, but it's not clear to me, how to handle POST request, that I send from page, to vibed server.
I wrote next code:
import vibe.d;
import std.stdio;
void main()
{
auto router = new URLRouter;
router.any("*", &accControl);
router.any("/my", &action);
auto settings = new HTTPServerSettings;
settings.port = 8080;
settings.bindAddresses = ["::", "127.0.0.1"];
listenHTTP(settings, router);
runEventLoop();
}
void accControl(HTTPServerRequest req, HTTPServerResponse res)
{
res.headers["Access-Control-Allow-Origin"] = "*";
}
void action(HTTPServerRequest req, HTTPServerResponse res)
{
// how get string from POST request here. And how get JSON object, if server send it.
}
but what method I should use for req? As I understand expect POST body there is sending a lot of other data.
The POST request is sending with JQuery:
$.post("http://127.0.0.1:8080", "\"answers_result\":777");
So I need to get this JSON and send with vibed it's to DB. But problem that I can't understand how to handle it.

In main:
auto router = new URLRouter;
router.post("/url_to_match", &action);
listenHTTP(settings, router);
Action:
void action(HTTPServerRequest req, HTTPServerResponse res)
{
auto answers_result = req.json["answers_result"].to!int;
// ...
}
Or you can use registerRestInterface.

Here is an example code to show how to read POST params from vibe.d:
Main Function:
shared static this()
{
auto router = new URLRouter;
router.post("/url_to_match", &action);
auto settings = new HTTPServerSettings;
settings.port = 3000;
listenHTTP(settings, router);
}
Action:
void action(HTTPServerRequest req, HTTPServerResponse res)
{
// Read first POST parameter named "first_name"
auto firstName = req.form["first_name"];
// Read second POST parameter named "last_name"
auto lastName = req.form["last_name"];
// Prepare output to be sent to client.
auto name = "Hello %s, %s".format(lastName, firstName);
// Send data back to client
res.writeBody(name);
}
Build the program and run it, to try it out on your local machine you may execute the following simple curl request:
curl --data "first_name=kareem&last_name=smith" "http://localhost:3000/url_to_match"
HTH

Related

Solve issue POSTING to webhook for IFTTT from Arduino MKR1010

I am aiming to make a post request to trigger a IFTTT webhook action. I am using the MKR1010 board. I am able to connect to the network and turn the connected LED on and off using the cloud integration.
The code is as follows, but doesn't trigger the web hook. I can manually paste the web address in a browser and this does trigger the web hook. When the code is posted it returns a 400 bad request error.
The key has been replaced in the below code with a dummy value.
Does anybody know why this is not triggering the web hook? / Can you explain why the post request is being rejected by the server? I don't even really need to read the response from the server as long as it is sent.
Thank you
// ArduinoHttpClient - Version: Latest
#include <ArduinoHttpClient.h>
#include "thingProperties.h"
#define LED_PIN 13
#define BTN1 6
char serverAddress[] = "maker.ifttt.com"; // server address
int port = 443;
WiFiClient wifi;
HttpClient client = HttpClient(wifi, serverAddress, port);
// variables will change:
int btnState = 0; // variable for reading the pushbutton status
int btnPrevState = 0;
void setup() {
// Initialize serial and wait for port to open:
Serial.begin(9600);
// This delay gives the chance to wait for a Serial Monitor without blocking if none is found
delay(1500);
// Defined in thingProperties.h
initProperties();
// Connect to Arduino IoT Cloud
ArduinoCloud.begin(ArduinoIoTPreferredConnection);
/*
The following function allows you to obtain more information
related to the state of network and IoT Cloud connection and errors
the higher number the more granular information you’ll get.
The default is 0 (only errors).
Maximum is 4
*/
setDebugMessageLevel(2);
ArduinoCloud.printDebugInfo();
// setup the board devices
pinMode(LED_PIN, OUTPUT);
pinMode(BTN1, INPUT);
}
void loop() {
ArduinoCloud.update();
// Your code here
// read the state of the pushbutton value:
btnState = digitalRead(BTN1);
if (btnPrevState == 0 && btnState == 1) {
led2 = !led2;
postrequest();
}
digitalWrite(LED_PIN, led2);
btnPrevState = btnState;
}
void onLed1Change() {
// Do something
digitalWrite(LED_PIN, led1);
//Serial.print("The light is ");
if (led1) {
Serial.println("The light is ON");
} else {
// Serial.println("OFF");
}
}
void onLed2Change() {
// Do something
digitalWrite(LED_PIN, led2);
}
void postrequest() {
// String("POST /trigger/btn1press/with/key/mykeyhere")
Serial.println("making POST request");
String contentType = "/trigger/btn1press/with/key";
String postData = "mykeyhere";
client.post("/", contentType, postData);
// read the status code and body of the response
int statusCode = client.responseStatusCode();
String response = client.responseBody();
Serial.print("Status code: ");
Serial.println(statusCode);
Serial.print("Response: ");
Serial.println(response);
Serial.println("Wait five seconds");
delay(5000);
}
Why do you want to make a POST request and send the key in the POST body? The browser sends a GET request. It would be
client.get("/trigger/btn1press/with/key/mykeyhere");
In HttpClient post() the first parameter is 'path', the second parameter is contentType (for example "text/plain") and the third parameter is the body of the HTTP POST request.
So your post should look like
client.post("/trigger/btn1press/with/key/mykeyhere", contentType, postData);

How to mock HttpClientResponse to return a String

I am trying to write a test after refactoring to dart:io.HttpClient following https://flutter.io/networking/
Everything seems to work well up until
var responseBody = await response.transform(utf8.decoder).join();
The following test throws a NoSuchMethodError: The method 'join' was called on null.
MockHttpClient http = new MockHttpClient();
MockHttpClientRequest request = new MockHttpClientRequest();
MockHttpHeaders headers = new MockHttpHeaders();
MockHttpClientResponse response = new MockHttpClientResponse();
MockStream stream = new MockStream();
when(http.getUrl(Uri.parse('http://www.example.com/')))
.thenReturn(new Future.value(request));
when(request.headers)
.thenReturn(headers);
when(request.close())
.thenReturn(new Future.value(response));
when(response.transform(utf8.decoder))
.thenReturn(stream);
when(stream.join())
.thenReturn(new Future.value('{"error": {"message": "Some error"}}'));
I did see How to mock server response - client on server side, but that uses the http package, not dart:io.
I also tried https://github.com/flutter/flutter/blob/master/dev/manual_tests/test/mock_image_http.dart but that also returns a null.
Much thanks in advance!
The problem is that when you mock stream you actually need to implement a ton of different methods to get it to work properly. It is better to use a real Stream if you can like in the example in the flutter repo. To make sure your body is correctly set, use the utf8 encoder.
final MockHttpClientResponse response = new MockHttpClientResponse();
// encode the response body as bytes.
final List<int> body = utf8.encode('{"foo":2}');
when(response.listen(typed(any))).thenAnswer((Invocation invocation) {
final void Function(List<int>) onData = invocation.positionalArguments[0];
final void Function() onDone = invocation.namedArguments[#onDone];
final void Function(Object, [StackTrace]) onError = invocation.namedArguments[#onError];
final bool cancelOnError = invocation.namedArguments[#cancelOnError];
return new Stream<List<int>>.fromIterable(<List<int>>[body]).listen(onData, onDone: onDone, onError: onError, cancelOnError: cancelOnError);
});

angular2 http.post method throws typeerror{} exception

I tried to change the existing angularjs library to angular2 for my need. http.post method in the below code throws TypeError {} as exception. Someone please help as i am stuck on this.
login() {
return new Promise((resolve, reject) => {
if(typeof jsSHA !== "undefined") {
var signatureObj = (new OauthUtility()).createSignature("POST", this.magentoOptions.baseUrl+"/oauth/initiate", this.oauthObject, {oauth_callback: "http://localhost/callback"}, this.magentoOptions.clientSecret, null);
let headersInitiate = new Headers();
headersInitiate.append('Authorization',signatureObj.authorization_header);
headersInitiate.append('Content-Type','application/x-www-form-urlencoded');
let url = this.magentoOptions.baseUrl + "/oauth/initiate";
let callback = "oauth_callback=http://localhost/callback";
try{
this.http.post(url, callback,{headers: headersInitiate})
.subscribe(
(result) => {
console.log("i am inside");
var rParameters = (result).split("&");
.....
}
catch(Exception){
console.log(Exception)
}
You should try something like that:
var signatureObj = (new OauthUtility()).createSignature("POST",
this.magentoOptions.baseUrl+"/oauth/initiate", this.oauthObject,
{oauth_callback: "http://localhost/callback"},
this.magentoOptions.clientSecret, null); let headersInitiate = new Headers();
headersInitiate.append('Authorization',
signatureObj.authorization_header);
headersInitiate.append('Content-Type',
'application/x-www-form-urlencoded');
let url = this.magentoOptions.baseUrl + "/oauth/initiate";
let payload = ' ... ';
this.http.post(url, payload,{headers: headersInitiate})
.subscribe(
(result) => {
console.log("i am inside");
var rParameters = (result).split("&");
(...)
});
Here are the comments I would have on your code:
The second parameter of the post method should be a string corresponding to the payload not a callback. I see from your headers that you want to send url-encoded form, so you need to create it by your own
The try catch isn't necessary since executing an HTTP is asynchronous and errors can be "catched" within the second parameter (another callback) of the subscribe method.
You don't need at all a promise. For HTTP, Angular2 uses observables under the hood. They target asynchronous processing as well.
After fixing all of this, I think that you won't have error anymore...
Hope it helps you,
Thierry
I found to stuck even after proceeding with the above all steps. The complete solution is as follows.
Remove try catch block and promise as suggested by Thierry.
Use dependency injection of http inside the constructor as follows to define http.
import {Http,HTTP_PROVIDERS,Headers} from 'angular2/http';
import {Injector} from "angular2/core";
constructor() {
var injector = Injector.resolveAndCreate([HTTP_PROVIDERS]);
this.http = injector.get(Http);
}

Handle POST data using Dart Route after already listening to stream

I am using route to handle http requests to my server. This is my current route code:
HttpServer.bind("127.0.0.1", 8080).then((server) {
new Router(server)
..filter(new RegExp(r'/.*'), addCorsHeaders)
..filter(new RegExp(r'/admin/.*'), authenticate)
..serve(userGetURL, method: 'GET').listen(userGetHandler)
..serve(userPostURL, method: 'POST').listen(userPostHandler);
});
I am trying to get JSON data that I am POSTing to a URL. The data will be used to get an entity from the database and return it as JSON to the caller. I am basically trying to create a server application that will handle all the data and a client application that will display it.
I cannot figure out how to get the data from a POST. Everything I have tried requires that I listen to the stream, but it is already being listened to. This is how I have been trying to get the POST data:
userPostHandler(HttpRequest req) {
req.listen((List<int> buffer) {
// Return the data back to the client.
res.write(new String.fromCharCodes(buffer));
res.close();
}
}
The problem is I get a Bad state: Stream has already been listened to. error.
EDIT: The filters
Future<bool> authenticate(HttpRequest req) {
if (req.method == 'POST') {
// Post data is not null
// Authenticate user
String userName = '';
String password = '';
User user = new User();
user.DBConnect().then((User user) {
return new Future.value(user.ValidateUser(userName, password));
});
}
}
Future<bool> addCorsHeaders(HttpRequest req) {
print('${req.method}: ${req.uri.path}');
req.response.headers.add('Access-Control-Allow-Origin', '*, ');
req.response.headers.add('Access-Control-Allow-Methods', 'POST, OPTIONS, GET');
req.response.headers.add('Access-Control-Allow-Headers',
'Origin, X-Requested-With, Content-Type, Accept');
return new Future.value(true);
}
I have never used the Route package but I wonder why you want to listen inside the Handler. Can't you just access the properties you want to process?
Otherwise you could try
req.asBroadcastStream().listen(...)
A BroadcastStream supports multiple listeners.
More information in this article Use Streams for Data
Using the following code I was able to get a POST working:
void main() {
HttpServer.bind("127.0.0.1", 8080).then((server) {
new Router(server)
..filter(new RegExp(r'/.*'), addCorsHeaders)
..filter(new RegExp(r'/admin/.*'), authenticate)
..serve(userGetURL, method: 'GET').listen(userGetHandler)
..serve(userPostURL, method: 'POST').listen(userPostHandler);
});
}
Future userPostHandler(HttpRequest req) {
bool headerSent = false;
// Start listening before writing to the response.
req.listen((List<int> buffer) {
if (!headerSent) {
req.response.write("User POST");
headerSent = true;
}
req.response.write(new String.fromCharCodes(buffer));
},
// Use onDone to close the response.
onDone: () => req.response.close()
);
}
Here is what I figured out. Any write to the response automatically drains the body and thus destroy the POST data. As mentioned here. Also, listening to the response is done asynchronously and thus must be completed before close() is called.

Backbone.js: POST request with empty value

I am trying to make a POST request.
Here my code:
var myModel = new MydModel({
content: "ciao"
});
console.log(myModel.get("content")); // "ciao"
myModel.save();
If I look to the network activity it looks like this:
The response part {id:0, content:"", ……}
In the header part: Request Payload {"content":"ciao"}
Here my model:
define([], function () {
var MyModel = Backbone.Model.extend({
url: function url ()
{
return "http://localhost/users";
}
});
return MyModel;
});
Is it my problem or is it in the server part?
send/receive vs request/response
a server receives requests and sends responses
a client sends requests and receives responses
in short
if {id:0, content:"", ……} (the response) is wrong, it's your server
if {"content":"asdasdsa"} (the request) is wrong, it's your client
There is little problem with receiving JSON-payload that "Backbone-client" sends to your Apache-server.
All you need to do is to manually parse JSON-payload from input on the server side ("php://input", for PHP), like this:
if($_SERVER['REQUEST_METHOD'] == 'PUT' || $_SERVER['REQUEST_METHOD'] == 'POST') {
$postStr = file_get_contents("php://input");
//json_decode throws error or returns null if input is invalid json
try {
$json = json_decode($postStr, true);
if(empty($json)) {
throw new Exception("Not valid json");
}
//must not be json, try query str instead
} catch(Errfor $e) {
$postVars = parse_str($postStr);
foreach($postVars as $key=>$data) {
$_POST[$key] = $data;
}
}
}
Full explanation you can find here:
http://colinbookman.com/2014/04/08/php-puts-posts-and-backbone-js/

Resources