Get body of post request vert.x javascript verticle - javascript

Pasted below is the code of my javascript verticle which is deployed successfully. Since I couldn't find a way to debug the js verticle, I printed all the properties of the routingContext for reference. I am trying to get body of the request, however all the functions starting with getBody are returning null. I have pasted the request I am making below the code, with the log printed in the intellij terminal. Am I doing something wrong?
JS Verticle Code
var Router = require("vertx-web-js/router");
var server = vertx.createHttpServer();
var router = Router.router(vertx);
function writeHelp(obj) {
var txt = "";
for (var x in obj){
txt += x + "->" + obj[x] + "\n";
}
return txt;
}
router.post("/provider").handler(function (routingContext) {
var response = routingContext.response();
var json = routingContext.getBodyAsString();
response.putHeader("content-type", "text/plain");
//console.log("Helper\n" + writeHelp(routingContext));
//console.log("Request=" + writeHelp(routingContext.request()));
console.log("body=" + json);
response.end("Success");
});
server.requestHandler(router.accept).listen(8890);
POST Request made through ARC
Log from Intellij
Router: 257219241 accepting request POST http://localhost:8890/provider
Route matches: Route[ path:/provider pattern:null handler:io.vertx.core.Handler$$NashornJavaAdapter#69b539e failureHandler:null order:0 methods:[POST]]#32182409
Calling the handler
body=null

You have to add the BodyHandler to get parsed body:
From the official documentation:
var BodyHandler = require("vertx-web-js/body_handler");
// This body handler will be called for all routes
router.route().handler(BodyHandler.create().handle);

Related

Accessing server values in javascript file?

EDIT: Forgot a piece of code when taking stuff that was relevant
I want to work with the "jsonData" value from my server in my javascript file, but i don't know how to get the values there?
server code:
var express = require('express');
var app = express();
app.use(express.static('public'));
var Amadeus = require('amadeus');
app.set('view engine', 'ejs');
app.listen(8080);
app.get('/hotels', function(req, res){
var searchTerm = req.query.cityCode;
amadeus.shopping.hotelOffers.get({
cityCode: searchTerm
}).then(function(response){
var jsonData = JSON.parse(response.body);
var output = "";
for(var i = 0; i < jsonData.data.length; i++){
output+= "Name: " + JSON.stringify(jsonData.data[i].hotel.name) + "\t";
output+= "Rating: " + JSON.stringify(jsonData.data[i].hotel.rating) + "\t";
}
res.render('pages/onestar', {jsonData: output});
}).catch(function(error){
console.log(error.response); //=> The response object with (un)parsed data
//console.log(error.response.request); //=> The details of the request made
console.log(error.code); //=> A unique error code to identify the type of error
});
});
JavaScript attempt that i have so far:
$(document).ready(function(){
$('#searchbutton').submit(function(){
event.preventDefault();
$.get('xxxxxx', function(jsonData){
console.log(jsonData);
});
return false;
});
You need to send something back from your express server program to the web browser. There are lots of methods on the res object to do that.
Replace
var jsonData = JSON.parse(response.body);
with
res.status(200).json(JSON.parse(response.body))
You could also send back the JSON text in the response.body directly rather than parsing it first, only to tell express to stringify it again. But the req.json() function also sets the Content-Type header on the response to the web browser so it knows it's getting JSON. With respect, that's a little complex for your apparent present level of understanding. Keep it in mind for a later optimization when you get your code working.

Struggling with the wunderground api and node

So I had been stuck on this exercise in Treehouse some time ago and just moved on. I came back to it now that I understand things better and I'm still fighting with the wunderground api. I've read through the json data and documentation, updated a few things from when the class was first recorded (and the API updated since then), and still am getting errors I can't field. I've got three js files- app.js, weather.js, and api.json (which is just my api key so not shared here.)
After my corrections, I'm still getting the error "TypeError: Cannot read property 'temp_f' of undefined" which doesn't make sense as I keep reading over the JSON to check that it's pointing to the right place.
Can anyone put an end to my misery trying to fix this?
App.js:
const weather = require('./weather');
//Join multiple values passed as arguments and replace all spaces with underscores
const query = process.argv.slice(2).join("_").replace(' ', '_');
//query: 90201
//query: Cleveland_OH
//query: London_England
weather.get(query);
Weather.js
const https = require('https');
const http = require('http');
const api = require('./api.json');
// Print out temp details
function printWeather(weather) {
const message = `Current temp in ${weather.location} is ${weather.current_observation.temp_f}F`;
console.log(message);
}
// Print out error message
function get(query) {
const request = http.get(`http://api.wunderground.com/api/${api.key}/conditions/q/${query}.json`, response => {
let body = "";
// Read the data
response.on('data', chunk => {
body += chunk;
});
response.on('end', () => {
//Parse data
const weather = JSON.parse(body);
//Print the data
printWeather(weather);
});
});
}
module.exports.get = get;
//TODO: Handle any errors

FileReader API error while using jsmediatags

While using JSMediaTags, the onError event handler for the jsmediatags.open method receives an error object with properties:
type = "fileReader"
info = "Offset 0 hasn't been loaded yet"
See pseudo-code below.
The exact text of the error is not in the JSMediaTags file, leading me to believe that the error is being generated by the browser, but I am unable to find insight into what the specific problem is.
I'm running this on my local workstation, with a Windows 7 OS running IIS. I've tested in Chrome v 61, and Firefox v 55. Same error in both.
As you can see, I'm trying to first send the file object (as a file) into the jsmediatags.read function. This results in the error detailed above.
I've commented out the code where, instead of the file object, I try sending in 1.) the complete local path to the file, 2.) the result of createObjectURL on the file object, as well as 3.) the file object's name property. These last 3 do not result in either an onSuccess or onError event being fired.
<script type="text/javascript" src="tagreader/jsmediatags.js"></script>
<input type="file" id="fileinput" onchange="window.handleLocalFiles(this.files)">
<script>
var gobjFileTags = null;
function handleLocalFiles(argFiles){
if (argFiles && (argFiles.length > 0)){
testTagReader(argFiles[0]);
}
}
function testTagReader(objFile){
var objTagReader = null;
var strURL = "";
var strFileName = "";
var strLocalPath = "";
objTagReader = window.jsmediatags;
objTagReader.read(objFile, {
onSuccess: function(tag){
window.gobjFileTags = tag;
window.readFileTags();
},
onError: function(objError){
window.alert("objTagReader Error - type: " + objError.type + ", info: " + objError.info);
}
});
}
function readFileTags(){
window.alert("readFileTags called");
}

How do I make JakeJS watch work reliably with Vim?

I'm using a Jakefile to help me update Wordpress pages from the command line. I'm using Jake's watch task to re-build ever time I edit a file. When I edit a file with Vim, after the first successful build, Jake fails with following error :
WatchTask started for: default
cp home.html dist/home.html
exec wp --path=../wordpress post list --post_type=page --format=json --fields=ID,post_name { silent: true }
exec wp --path=../wordpress post update 2 dist/home.html --post_type=page
Success: Updated post 2.
jake aborted.
Error: File-task home.html has no existing file, and no action to create one.
at FileBase.isNeeded (/usr/local/lib/node_modules/jake/lib/task/file_task.js:50:17)
at TaskBase.run (/usr/local/lib/node_modules/jake/lib/task/task.js:256:26)
(See full trace by running task with --trace)
I've tried using a sleep function in the rule to delay the rebuild. I tried this because Vim, when saving a file, write the contents to a new temp file and then renames the new temp file to the original file name. I think the build fails because it's trying to build before the file is fully renamed. Using the sleep doesn't work reliably, it may work once or twice but then it fails the same way as above.
Here is my Jakefile:
var shell = require('shelljs');
var sleep = require('sleep');
shell.config.verbose = true;
const destDir = 'dist';
const wpDir = '../wordpress';
var files = new jake.FileList();
files.include('*.html');
var outputFiles = files.toArray().map(function(fileName){
return destDir + '/' + fileName;
});
var sourceFile = function(name) {
return name.substr(name.lastIndexOf('/') + 1);
}
function objectToStr(object) {
var s = '';
for(var property in object){
s += property + ': ' + object[property] + '\n';
}
return s;
}
function rmExt(name) {
return name.substr(0, name.lastIndexOf('.'));
}
directory(destDir);
task('default', [destDir].concat(outputFiles));
task('clean', function() {
jake.rmRf(destDir);
});
rule('dist/%.html', sourceFile, function() {
shell.cp(this.source, this.name);
var pages = JSON.parse(shell.exec('wp --path=' + wpDir
+ ' post list --post_type=page --format=json --fields=ID,post_name',
{ silent: true }).stdout);
var postId = null;
var l = pages.length;
for(var i = 0; i < l; i++){
if(pages[i].post_name === rmExt(this.source)){
postId = pages[i].ID;
break;
}
}
if(postId !== null){
shell.exec('wp --path=' + wpDir + ' post update ' + postId
+ ' ' + this.name + ' --post_type=page');
}else{
shell.echo('Unable to find matching post ID for file: ' + this.name);
}
shell.echo('1');
sleep.sleep(2);
shell.echo('2');
});
watchTask('watch', ['default'], function() {
this.watchFiles.include('*.html');
}
I found a reliable solution using the library node-watch. I replaced the watchTask with a normal Jake task and invoked the task I wanted to call using node-watch to watch the current working directory. The library node-watch is able filter files based on regex so the watch won't be trigger for the Vim swap file and the like. Below is the code I used:
task('watch', function() {
var defaultTask = jake.Task['default'];
defaultTask.invoke();
defaultTask.reenable(true);
watch('./', { filter: /.*.html$/ }, function(evt, name) {
defaultTask.invoke();
defaultTask.reenable(true);
});
});
Note: I also invoked the task I want to call when the watch task is first run to make sure any changes made before the watch started are built.

Server-Sent Events with Ruby Grape

I am trying to create Server-Sent events on my Ruby Grape API.
The problem is that the connection seems to be closed really fast all the time, as I get Connection closed event all the time on test webpage.
The client connects to the server as I can see the method being called, but I would like to know why is the connection not constant and why I don't receive the data I send using the Thread.
Here is my Ruby code:
$connections = []
class EventsAPI < Sinantra::Base
def connections
$connections
end
get "/" do
content_type "text/event-stream"
stream(:keep_open) { |out|
puts "New connection"
out << "data: {}\n\n"
connections << out
}
end
post "/" do
data = "data\n\n"
connections.each { |out| out << data }
puts "sent\n"
end
end
Here is my Javascript:
var source = new EventSource('http://localhost:9292/events');
source.onmessage = function(e) {
console.log("New message: ", e.data);
showMessage(e.data);
};
source.onopen = function(e) {
// Connection was opened.
};
source.onerror = function(e) {
console.log("Source Error", e)
if (e.eventPhase == EventSource.CLOSED) {
console.log("Connection was closed");
// Connection was closed.
}
};
var showMessage = function(msg) {
var out = document.getElementById('stream');
var d = document.createElement('div')
var b = document.createElement('strong')
var now = new Date;
b.innerHTML = msg;
d.innerHTML = now.getHours() + ":" + now.getMinutes() + ":" +now.getSeconds() + " ";
d.appendChild(b);
out.appendChild(d);
};
EDIT: I got it working with the GET method (I changed the Grape::API to Sinatra::Base as Grape does not implement stream). I now receive data, but the connection is not kept alive and when I use the post method the data never reaches the browser.
Thank you in advance for your answers.
The JS code looks correct. My guess is that you should not start a new thread for your infinite loop. What will be happening is that the main thread will carry on executing, reach the end of its block, and close the http request. Your detached thread is then left writing to a non-existent out stream.
UPDATE in response to your EDIT: POST is not supported in SSE. Data can only be passed to an SSE process by using GET data or cookies.

Categories