How to POST/PUT JSON object to an actionhero route?

1,184 views
Skip to first unread message

danie...@gmail.com

unread,
Sep 24, 2013, 8:34:33 PM9/24/13
to action...@googlegroups.com
I was wondering how to POST a json object from a web client to actionhero (simple web server type of), and use it in my action?

I'm trying to get 'userdata' to an action that has a definition like
inputs: { required: [ 'username', 'userdata' ], optional: [] }
where 'userdata' is a complex JSON object.

I saw that there is file-upload support in the form of 'Multipart/form-data'. Does actionhero threat requests with a header of 'Content-Type: application/json' in a special way? Does it ignore this kind of header?
If it does not make any difference, is there some way to 'plug-in' a custom-parser before the connection gets passed into the action?

I also thought about getting the body from the connection.rawConnection.req object and parse it inside the action, but i could not find the actual data sent in the body, nor an obvious way to get that data out from the rawConnection.

Thank You for Your help.

Evan Tahler

unread,
Sep 25, 2013, 12:45:26 AM9/25/13
to action...@googlegroups.com
This kind of thing was discussed a little bit here.

Right now, actionHero doesn't do anything special if the POST is application/json.  We currently follow pattern that github does, in that you can certainly post JSON, but it should be set to a form variable (and probably JSON.stringify'd).  "payload" is the most common param name for this, but I've also seen "body" or "data".  Here's an example:

Action

exports.action = {
  name: "json",
  description: "json",
  inputs: {
    required: ["payload"],
    optional: [],
  },
  blockedConnectionTypes: [],
  outputExample: {},
  version: 1.0,
  run: function(api, connection, next){
    try{
      var payload = JSON.parse(connection.params.payload);
      connection.response.payload = payload;
    }catch(e){
      connection.error = e;
    }
    next(connection, true);
  }
};

Curl:

> curl -X POST -d 'payload={"thing": "stuff"}' 'localhost:8080/json'
{
  "payload": {
    "thing": "stuff"
  },
  "serverInformation": {
    "serverName": "actionHero API",
    "apiVersion": "0.0.1",
    "requestDuration": 7,
    "currentTime": 1378680616429
  },
  "requestorInformation": {
    "id": "1fdb9212c86f0866cd7f3d1995f1abf916d6cd84",
    "remoteIP": "127.0.0.1",
    "receivedParams": {
      "payload": "{\"thing\": \"stuff\"}",
      "action": "json",
      "limit": 100,
      "offset": 0,
      "apiVersion": 1
    }
  }
}

I would be open to a Pull Request which takes the body of POST with application/json and munges that into a param.  Keep in mind that parsing that JSON into a param is probably something folks want to configure, along with the error responses.  Because there are many opinions/patterns for this kind of thing, actionHero has left this up to the developer to implement as needed.  Also, writing a middleware for this is very simple if you have a few actions which will have the same functionality.  

You can access the raw req and res variables of a web-type connection within an action with connection.rawConnection.req and connection.rawConnection.res

Pehr Johansson

unread,
Sep 25, 2013, 6:00:52 AM9/25/13
to Evan Tahler, action...@googlegroups.com
POSTing JSON works perfectly fine.
Try this curl:
curl -H 'content-type: application/json' -X POST -d '{"username":"superman", "userdata": { "field1": "val", "field2": [ "a1", "a1" ], "field3": { "subfield1": 1 } } }' http://localhost:8080/api/jsonfield

And the params would get parsed as:
2013-09-25 20:59:57 - info: [ action @ web ] to=127.0.0.1, action=jsonfield, params={"username":"superman","userdata":{"field1":"val","field2":["a1","a1"],"field3":{"subfield1":1}},"action":"jsonfield","limit":100,"offset":0,"apiVersion":1}, duration=1, error=null


--
You received this message because you are subscribed to the Google Groups "actionHero.js" group.
To unsubscribe from this group and stop receiving emails from it, send an email to actionhero-j...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.

Evan Tahler

unread,
Sep 28, 2013, 8:48:13 PM9/28/13
to action...@googlegroups.com, Evan Tahler
It looks like in newer versions of formidable (v1.0.12 and up), support for parsing "bodies" of POSTs with application/json was added.  actionHero uses formidable, so we gained application/json support for free! 

Normal actionHero rules still apply, so the keys in your POSTed json still need to be listed in `action.inputs` or else they won't make it to your action's run method.  Also, if you pass the same param as a query string and a POST json, the POST value wins.  Also of note, if you pass any form data along with with your post body, the body will not be parsed at all.

Evan Tahler

unread,
Sep 28, 2013, 8:49:40 PM9/28/13
to action...@googlegroups.com, Evan Tahler
For clarification, this is valid:

exports.action = {
  name: "params",
  description: "params",
  inputs: {
    required: [],
    optional: ["thing"],
  },
  blockedConnectionTypes: [],
  outputExample: {},
  version: 1.0,
  run: function(api, connection, next){
    connection.response.params = connection.params;
    console.log(connection.params);
    next(connection, true);
  }
};

curl -X POST -H "Content-Type: application/json" -d '{"thing": "fromBody"}' "http://localhost:8080/params"

`connection.params.thing` will equal "fromBody" in this case.

acheb...@gmail.com

unread,
Feb 10, 2014, 2:26:34 AM2/10/14
to action...@googlegroups.com

Hi Evan,
I have tried the code above but i dont see the "connection.params.thing" being populated with "FromBody". Am i missing something?
Thanks
Azeet

Evan Tahler

unread,
Feb 10, 2014, 9:00:14 PM2/10/14
to action...@googlegroups.com, acheb...@gmail.com
Looks ok to me... In the newest version of actionhero.  Be sure to name your action 'params.js'.  You may need to curl:
curl -X POST -H "Content-Type: application/json" -d '{"thing": "fromBody"}' "http://localhost:8080/api/params"

acheb...@gmail.com

unread,
Feb 10, 2014, 9:20:04 PM2/10/14
to action...@googlegroups.com, acheb...@gmail.com
Evan,
I dont know what am i doing wrong.here is the action i have

exports.action = {
name: "params.js",
description: "params",
authenticated:false,
inputs: {
required: [],
optional: ["thing"],
},
blockedConnectionTypes: [],
outputExample: {},
version: 1.0,
run: function(api, connection, next){
// console.dir(connection.rawConnection);
connection.response.params = connection.params;
console.log(connection.params);
console.log("hello:",connection.params.thing);
next(connection, true);
}
};

and when i curl
curl -X POST -H "Content-Type: application/json" -d '{"thing": "fromBody"}' "http://localhost:8080/api/params"
this is the response i am getting
{
"params": {
"action": "params",
"limit": 100,
"offset": 0,
"apiVersion": 1
},
"serverInformation": {
"serverName": "Brainstorm API Server",
"apiVersion": "0.0.1",
"requestDuration": 3,
"currentTime": 1392085067560
},
"requesterInformation": {
"id": "65794f846721902e2440eaf2eced26ceffe71f2f",
"remoteIP": "127.0.0.1",
"receivedParams": {
"action": "params",
"limit": 100,
"offset": 0,
"apiVersion": 1
}
}
}

Appriciate any help.
Thanks
Azeet

Evan Tahler

unread,
Feb 10, 2014, 9:55:22 PM2/10/14
to acheb...@gmail.com, action...@googlegroups.com
other than the fact that it should be `name: "params",` that all looks correct.  Which OS, actionhero and node version do you have?



Thanks
Azeet

azeet.c...@gmail.com

unread,
Feb 10, 2014, 10:40:14 PM2/10/14
to action...@googlegroups.com, acheb...@gmail.com
I have changed the name to "params" but still it didnt work:(
I am on Windows 8 with node v0.10.21 and latest actionhero.
Any issue with windows?

azeet.c...@gmail.com

unread,
Feb 11, 2014, 12:07:39 AM2/11/14
to action...@googlegroups.com, acheb...@gmail.com, azeet.c...@gmail.com
OK Evan,
I got it finally.I need to set the config entry "disableParamScrubbing" to true.
Thanks for your help.
Azeet

azeet.c...@gmail.com

unread,
Feb 11, 2014, 1:03:38 AM2/11/14
to action...@googlegroups.com, acheb...@gmail.com, azeet.c...@gmail.com
But i am seeing a new problem now.actionhero is no longer generating the api documentation for me when i access http://localhost:8080/public .i am getting an error in actionheroClient.js saying "Error: {no action} is not a known action or that is not a valid apiVersion."
Any other setting i missed?
Thanks
Azeet

Evan Tahler

unread,
Feb 11, 2014, 9:45:35 PM2/11/14
to azeet.c...@gmail.com, action...@googlegroups.com, acheb...@gmail.com
You shouldn't have to disable param scrubbing.  The param you are sending is in the list, and it works OK.  Disabling param scrubbing doesn't stop the documentation from being sent at the api root (I even checked on windows 8).  Unfortunately, I can't see what you are doing wrong.



Screen Shot 2014-02-11 at 6.44.18 PM.png

azeet.c...@gmail.com

unread,
Feb 12, 2014, 12:17:42 AM2/12/14
to action...@googlegroups.com, azeet.c...@gmail.com, acheb...@gmail.com
Hmm even i am confused.but thanks a lot for trying to help me out.

Azeet
Reply all
Reply to author
Forward
0 new messages