JSONSerialization makes incorrect JSON object. Swift - node.js

I'm creating an iOS app that connects to a NodeJS server. The get method works fine but the POST method has problems.
var urlRequest = URLRequest(url: "http://localhost:3000/register")
urlRequest.httpMethod = "POST"
let info: [String:Any] = ["username": "username", "password":"username", "email":"username#username.com"]
do {
let jsonInfo = try
JSONSerialization.data(withJSONObject: info, options[])
urlRequest.httpBody = jsonInfo
} catch {
print("ERROR")
return
}
The request gets sent but something goes wrong with JSONSerialization because this is the JSON data that the server gets:
{'{"email":"username#username.com","username":"username","password":"username"}': '' }
This is what I'm going for:
{"email":"username#username.com","username":"username","password":"username"}
This is part of the server code:
const express = require('express');
const bodyParser = require('body-parser');
var app = express();
var allowMethods = function(req, res, next) {
res.header('Access-Control-Allow-Methods', 'GET, POST, PATCH, PUT, DELETE');
next();
}
http.createServer(app).listen(3001);
console.log("Server started");
app.use(bodyParser.urlencoded({extended: true}));
app.use(allowMethods);
const _ = require('lodash');
let b = _.pick(req.body, ['username', 'password', 'email']);
Any ideas on what I'm doing wrong? I'd like to avoid using alamofire if possible. I've tried changing the format of the dictionary but always turns out as:
{ 'the whole dictionary is the key': ''}
I've also tried using pretty print and this was the result:
{ '{\n "email" : "username#username.com",\n "username" : "username",\n "password" : "username"\n}': '' }
Any help is appreciated. Thank you!
EDIT:
I tried Mike Taverne's suggestions.
I changed the server code to use this instead:
app.use(bodyParser.json());
But I receive an empty body from the simulator.
I also added these to the swift code:
urlRequest.addValue("application/json", forHTTPHeaderField: "Content-Type")
urlRequest.addValue("application/json", forHTTPHeaderField: "Accept")
But the server also receives an empty body and by empty body I mean the data I'm trying to send is received as empty by the server. When I check the httpBody the data is there but for some reason the server doesn't receive it.

I believe your Swift code is fine. When I did this in a playground:
print(String(data: urlRequest.httpBody!, encoding: String.Encoding.utf8)!)
It printed:
{"username":"username","password":"username","email":"username#username.com"}
I'm not an expert on body-parser, but I think that instead of this:
bodyParser.urlencoded({extended: true})
You should be using this:
bodyParser.json([options]) //not sure which options exactly you need
You may need to set Content-Type: application/json header as well. Refer to the body-parser documentation for more info.

I solved it by changing the data itself. Instead of forcing it to pass JSON I passed it as a string encoded using UTF8
let dataString = "username=username&password=username&email=username#username.com"
urlRequest.httpBody = dataString.data(using: .utf8)
I got the answer by using the method in this post:
HTTP Request in Swift with POST method

Related

Cannot get query param in nodejs

I have this proxy-middleware application. It is not including express.js.
Server.js contains this:
const app = require('connect')(),
http = require('http'),
While the middlewares a set of rules, for example:
const httpProxy = require('http-proxy'),
HttpProxyRules = require('http-proxy-rules'),
const proxyRules = new HttpProxyRules({
rules: {
'/api/v1/stuff/([0-9]+)/documents/': 'http://0.0.0.0:3000/$1',
},
default: 'http://localhost:4443'
});
So all the other microservices are being intercepted by this proxy.
There is an "app.use" where a few checks are made.
Here I can see the request-object. Im interested in reading the query parameter attached to the url.
So when I have this:
http://localhost:8081/api/v1.1/stuff/63/documents/file.pdf?token=mytoken
Printing this:
console.log('GATEWAY',req.originalUrl);
Will output this:
http://localhost:8081/api/v1.1/stuff/63/documents/file.pdf?token=mytoken
However, how can I access the query parameter? As Im not using express, doing "req.query" gives undefined.
I have tried a bunch of solutions: "querystring", "url" etc. But they give very strange result and it is not easy to get the field itself. I can never do something like:
req.query
I had a look at connect documentation but there is nothing about getting the request query parameters.
What should I use?
Please check if you used the followings:
If not, please add them:
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
And try to get req.params

Node.JS GET / Parameters

For exemple this is my server with a simple API :
var express = require('express');
var rzServer = express();
rzServer.use(bodyParser.urlencoded({extended:true}));
rzServer.use(bodyParser.json());
app.get('/url', function(req, res) {
console.log(req.query.data); // String
console.log(JSON.parse(req.query.date)); // Object
});
req.query.data is interpreted as a string but it's a JSON Object.
Is it possible with the body-parser package to parse the querystring ?
Thanks.
body-parser is a middleware to parse body (it's its name). If you want to parse the query string, so you need another middleware for that.
Another thing : GET requests normally don't take any JSON parameters (no body). If you need to send a true JSON, perhaps you're not using the good HTTP method. Try to use a POST request, or create a true query string (http://expressjs.com/fr/api.html#req.query).

node express body-parser for application/logplex-1

I am using node express to process POST requests of heroku logging data with body data that is in the application/logplex-1 format (apparently syslog formatted).
In particular, I am using the body-parser module as middleware to parse the POST body.
It works OK to specify app.use(bodyParser.text({ type: 'application/logplex-1' })) to force body-parser to parse the body as text, but the text is just a big block of space-separated information without much structure other than that. Therefore I need to parse the body data further to find and extract what I want.
This is OK, but I'm wondering if there is, perhaps, a better way of parsing the logplex-1 body more directly into something more structured and easier to work with, like JSON. I'm not familiar with logplex-1 or the syslog format, and whether it does indeed have anything more useful structure/metadata in it than is apparent from the text block I'm currently getting.
Any ideas?
I have no experience with logplex or Heroku, but this seems to be working:
var syslogParser = require('glossy').Parse;
var express = require('express');
var app = express();
var server = app.listen(3012);
// Express allows arrays-of-middleware to act as a "single" middleware.
var logplexMiddleware = [
// First, read the message body into `req.body`, making sure it only
// accepts logplex "documents".
require('body-parser').text({ type: 'application/logplex-1' }),
// Next, split `req.body` into separate lines and parse each one using
// the `glossy` syslog parser.
function(req, res, next) {
req.body = (req.body || '').split(/\r*\n/).filter(function(line) {
// Make sure we only parse lines that aren't empty.
return line.length !== 0;
}).map(function(line) {
// glossy doesn't like octet counts to be prepended to the log lines,
// so remove those.
return syslogParser.parse(line.replace(/^\d+\s+/, ''));
});
next();
}
];
// Example endpoint:
app.post('/', logplexMiddleware, function(req, res) {
console.log(req.body);
return res.sendStatus(200);
});
It uses glossy to parse the syslog messages into Javascript objects.
If the amount of data being posted is considerable (>hundreds of K's), it might be better to implement a streaming solution as the code above will first read the entire message body into memory.

Using node-validator to validate multiple properties at once

I'm building a Node.js proxy with the intent of handling a single POST request and redirecting the payload to two separate endpoints.
Let's say my JSON payload is:
{
"owner":"0ce856fa-f17f-11e2-9062-9b7910849bf4",
"comment":"My super cool comment!",
"photo":"0928536a-53c4-11e3-ba86-4b026f27c637"
}
I need to validate this payload on the proxy endpoint before I send it off; each of these three properties must exist, and both owner and photo must match the regex below. If they don't pass validation, I need to handle the error(s) and return a message back to the user with an appropriate error code.
I've set up a basic Node.js instance with Express and Validator like so in order to accomplish this:
var url = require('url');
var request = require('request');
var express = require('express');
var check = require('validator').check,
sanitize = require('validator').sanitize;
var app = express();
app.use(express.json());
app.use(express.urlencoded());
app.all('*', function(req, res){
if (req.method == "POST")
{
try {
check(req.body.owner, {
is: "<owner> property of type [uuid] is required"
}).is(/\w{8}(?:-\w{4}){3}-\w{12}?/);
} catch (e) {
console.log(e);
res.json({"result":"failed","message":"Your payload didn't pass validation"});
}
}
});
app.listen(9000, function() {
console.log("Server initialized on port 9000");
});
The problem: this is all fine and dandy and works great for a single validation (in this case owner), but e on catch doesn't contain any details about the property that failed validation -- if I set up multiple checks, I'd have no idea which one failed or why.
How can I set up a series of checks and retrieve the custom message I've configured? It talks about using req.onValidationError in the Validator readme, but that looks to be front-end validation, I'm not clear how (if possible) to integrate that up with the server-side code.
try express-validator which provides errors handling like:
var errors = req.validationErrors();
Update, using express-validator:
Per #shawnzhu's suggestion, I implemented express-validator instead; it took a bit of tweaking to get it working with express+connect 3.0, but given it's handling of node-validator errors, it looks like the best way to go (validating headers notwithstanding).
var express = require('express'),
expressValidator = require('express-validator');
var app = express();
app.use(express.json());
app.use(express.urlencoded());
app.use(expressValidator());
req.checkBody("owner", "<owner> property of type [uuid] is required; " + req.body.owner + " is invalid.").is(uuidRegex);
req.checkBody("photo", "<photo> property of type [uuid] is required; " + req.body.owner + " is invalid.").is(uuidRegex);
req.checkBody("comment", "<comment> property can't be empty").notNull().notEmpty();
req.sanitize("comment").trim();
var errors = req.validationErrors();
if (errors)
{
res.json({"result":"failed","errors":errors});
return;
}
To get it working just with node-validator:
It was the inline message validation that was causing problems:
try {
check(req.body.owner, "<owner> property of type [uuid] is required").is(/\w{8}(?:-\w{4}){3}-\w{12}?/);
check(req.body.photo, "<photo> property of type [uuid] is required").is(/\w{8}(?:-\w{4}){3}-\w{12}?/);
check(req.body.comment, "<comment> property can't be empty").notNull().notEmpty();
} catch (e) {
res.json({"result":"failed","message":e.message});
}
This does the job, and validates each property based on the criteria.

How can I gunzip POST request data in express?

I am trying to build a server that can accept gzipped POST data with express. I think I could just write my own middleware to pipe the request stream to a zlib.createGunzip() stream. The question is, how can I achieve that, afterwards, the express.bodyParser() middleware is still able to parse my gunzipped POST data?
I tried to replace the original request stream methods by the ones of the zlib stream, but that just made the bodyParser return a "Bad Request" Error:
var express = require('express');
var app = express();
function gUnzip(req, res, next) {
var newReq;
if (req.headers['content-encoding'] === 'gzip') {
console.log("received gzipped body");
newReq = req.pipe(zlib.createGunzip());
Object.getOwnPropertyNames(newReq).forEach(function (p) {
req[p] = newReq[p];
});
}
next();
}
app.use(gUnzip);
app.use(express.bodyParser());
app.listen(8080);
Is there a way to make this work without rewriting the bodyParser() middleware within my own middleware?
EDIT:
This is the same question: Unzip POST body with node + express. But in the answer he just does in his own middleware what the express.bodyParser() should do, which is what I want to avoid. I am looking for a way to simply unzip the request data from the stream and then pass it to the bodyParser(), which expects a stream itself, as can be seen at http://www.senchalabs.org/connect/json.html.
compressed request bodies are generally not used because you can't negotiate content encodings between the client and server easily (there's another stackoverflow question about that i believe). most servers don't support compressed request bodies, and the only time you really need it is for APIs where the client will send large bodies.
body-parser, specifically raw-body, does not support it because the use-case is so minimal, though i've though about adding it. for now, you'll have to create your body-parser. fortunately, that's easy since you can just fork body-parser and leverage raw-body. the main code you'll add around https://github.com/expressjs/body-parser/blob/master/index.js#L80:
var zlib = require('zlib')
var stream
switch (req.headers['content-encoding'] || 'identity') {
case 'gzip':
stream = req.pipe(zlib.createGunzip())
break
case 'deflate':
stream = req.pipe(zlib.createInflate())
break
case 'identity':
break
default:
var err = new Error('encoding not supported')
err.status = 415
next(err)
return
}
getBody(stream || req, {
limit: '1mb',
// only check content-length if body is not encoded
length: !stream && req.headers['content-length'],
encoding: 'utf8'
}, function (err, buf) {
})
Have you tried using the built in compress middleware. It's documented in the expressjs reference documentation
app.use(express.compress());
Maybe you can find something useful here instead: Unzip POST body with node + express

Resources