Responding to a webhook event with raw data - krl

I'd like to write a ruleset that can respond to webhook events with raw data. The event might come in from a URL like the following:
http://cs.kobj.net/blue/event/rest/echo/a163x85/?a163x85:kynetx_app_version=dev&body=hi%20there
I can use the send_directive() action, but that returns a lot of JSON that I don't necessarily want:
// KNS Fri Apr 8 19:40:40 2011
{"directives":[{"options":{"body":"hi there"},"name":"echo","meta":{"rule_name":"echo","txn_id":"154CEDCC-6218-11E0-9E71-726A5E50CE3F","rid":"a163x85"}}]}
Is there a way to respond with just raw data, rather than with a whole directive structure?

The answer is to use the Webhook Endpoint to interact with KNS, not directly signal an event.
You would signal your event like so:
http://webhooks.kynetxapps.net/h/a163x85.dev/echo?body=hi%20there
And a rule like so:
rule x {
select when webhook echo
pre {
body = event:param("body");
response = { 'thebody': body };
rjson = response.encode();
}
send_directive("json") with body = rjson;
}
For a response like:
{"thebody":"hi there"}
Note the .dev in the URL for indicating the dev version of the app, echo as the event name, and the event domain of webhook.
The endpoint will even serve it with the proper mime/type for json.
Also note you can return html, xml, js, plain text, and even a redirect. Check the Webhook Endpoint Docs for more details.

Related

PayPal Checkout Buttons - client/server communication

I am integrating the smart checkout of Paypal. I do not understand what the javascript portion expects back from the server. This is what I have got in JS
...
...
createOrder: function(data, actions) {
return fetch('/paypal/sandbox/createOrder', {
method: 'post',
headers: {
'content-type': 'application/json'
}
}).then(function(res) {
return res.json();
}).then(function(data) {
return data.orderID;
});
},
...
...
And this is what the server side does when /paypal/sandbox/createOrder' is called …
$request = new OrdersCreateRequest();
$request->prefer('return=representation');
$request->body = $this->buildRequestBody();
$response = $this->PayPalClient->execute($request);
What I can not find anywhere: What am I supposed to do with the response? I tried to echo it plain, echo it as JSON, but I always get errors like "Expected order id"
What do I need to respond to the client request?
The structure of the communication between your createOrder frontend JS and your backend server route (which in turn calls the PayPal API) is something you define. It can be is simple or as complex as you need it to be. You can send as many parameters back and forth as you want. You can use JSON, XML, Morse code, RFC 1149, or whatever you want for this transmission between your client and server.
The only required bit of information is the Order ID, which your server-side code in turn gets from the PayPal API v2/checkout/orders call (as id in the response), and which your createOrder function must then propagate back to its caller once obtained, which in the sample code happens here:
...
return data.orderID;
One very simple implementation would be to echo the whole v2/checkout/orders API response , not just id, and change the above client-side code to be return data.id so it reads that key name

REST: Is it considered restful if API sends back two type of response?

We have stock website and we help buyers connect with the sellers. We are creating API to let buyers push their contact details and get back the seller details. This is transaction and get logged in our database. We have created following API:
The request is POST, the URL looks like:
/api/leads
The request body looks like:
{
"buyermobile": "9999999999",
"stockid": "123"
}
The response looks like:
{
"sellermobile" : "8888888888",
"selleraddress": "123 avenue park"
}
We have a new requirement, i.e. we need to send back PDF URL (instead of "sellermobile" & "selleraddress"). This PDF URL would contain the seller details in case it comes from one of our client.
We have modified the same API, now the request body looks like:
{
"buyermobile": "9999999999",
"stockid": "123",
"ispdf": true
}
The response looks like:
{
"sellerdetailspdf" : "https://example.com/sellerdetails-1.pdf",
}
Is it RESTFUL to do this? OR we should create separate API for getting response as PDF?
I wouldn't approach it this way. What happens when you need to add XLS? Do you add "isxls" to the request too?
Things I'd consider:
Use a mime type for content negotiation. Post the same request, and specify in the Accept header what you expect back - JSON, PDF, etc. You're then actually getting the report instead of a link to the report, which may or may not be better.
- or -
Include a link in the typical lead response.
{
"sellermobile" : "8888888888",
"selleraddress": "123 avenue park",
"_links": {
"seller-details-pdf": "https://example.com/sellerdetails-1.pdf"
}
}
- or -
Support a query parameter that specifies the type in the response.
- or -
Have a single property that specifies the type in the response, rather than a boolean. Much cleaner to extend when you add new response types.
The first two options have the bonus that you don't require clients to handle multiple response types to a single request. That's not forbidden by any spec, but it's annoying for clients. Try not to annoy the people who you want to pay you. :)
Again the implementation looks good to me, however you could potentially look at breaking the return of the PDF URL to another endpoint maybe something like api/lead/pdf that way your request body is the same for api/lead and all subsequent endpoints under /lead. Allowing your routes and other code to handle small portioned tasks instead of having a route that handles multiple flags and multiple code routes.
That looks good to me - the same type of input should give the same type of response but in your case you have two different types of input - one with the "ispdf" flag and one without. So it's consistent to responds with two different types of response, one with the PDF link and one without.
That's still something you'll want to document but basically it's a correct implementation.

CakePHP: Distinguish between regular http and REST calls

I want the same Controller routines to serve both regular web-based page loads as well as REST calls. I have REST handling set-up in my routes.php:
// Setup REST Handling
Router::mapResources( '<ControllerName>' );
Router::parseExtensions();
Let's take for example, the add() method - how do I distinguish inside this method how the call is being made?
To elaborate on the issue:
public function add() {
$status = array();
if( $this->request->is( 'post' ) ) {
// Read POST body
$entityBody = file_get_contents( 'php://input' );
}
}
As you can see in the above code, I'm detecting POST requests and will deal with the request accordingly. What I need to figure is whether the post data is coming from a REST call of from a web-form. If the data comes from a web-form, it'll be in the request->data array whereas for a REST call, it'll be in XML form.
I'll deal with the data accordingly and dish out an appropriate response.
Thanks.
Use the CakeRequest object, see the documentation, works the same as with post.
$this->request->is('put');
is('get') Check to see if the current request is a GET.
is('put') Check to see if the current request is a PUT.
is('post') Check to see if the current request is a POST.
is('delete') Check to see if the current request is a DELETE.

Mojolicious websocket request query string

I'm experiencing unexpected behaviour while trying to access query string parameters in a mojolicious websocket request. Say my request looks like this:
ws://127.0.0.1:3000/websock_action?item_id=1234
Then in my mojo controller code I try and get the value of item_id in any of the following ways:
#in mojo controller
my $item_id = $self->param('item_id');
my $item_id = scalar $self->param('item_id');
my $item_id = scalar $self->tx->req->url->query->param('item_id');
The issue is that the item_id I get is often from a previous request, whichever of these techniques I use. My app is currently being served with hypnotoad.
Are query string parameters supported on websocket requests in mojolicious? Is there a more reliable way to access them? Essentially I'd like to know if I'm trying to something that isn't supported, so I can know whether the problem is something specific to my app.
Thanks in advance for any help
I suspect that what is happening, is that the parameters are passed in the html request, which is then upgraded to a websocket request at which point they are no longer available.
As Daren said, pass the data in the Web-Socket data. Something like...
var ws = $.websocket("ws://127.0.0.1:3000/websock_action", {
events: { message: function(e) {}
});
ws.send('message', 1234);

Sending Batch Request to Facebook Open Graph Beta

I am trying to submit a batch request to add objects via Open Graph Beta to a user's Timeline but no matter what I do I get this:
The action you're trying to publish is invalid because it does not specify any reference objects. At least one of the following properties must be specified: egg.
I am specifying an egg property though. My requests look like this:
https://graph.facebook.com/?batch=[{'method':'POST','relative_url':'/me/my_namespace:find','egg':'http%3A%2F%2Fwww.mydomain.com%2Fmy_namespace%2Fog%2Fegg.php%3Ftypeid%3D-966','start_time':'1317439270','end_time':'1317439270'}]&access_token=<<snipped>>&method=post
I am sending egg as a url-encoded reference string to a URL that contains my open graph data -- the URL does work if I send it not as a batch but since when setting up a user's Timeline I will in some cases have to post up to 1000 actions I am trying to speed things up by batching them.
I was able to successfully delete via a batch request.
Instead of sending the 'egg' as a param of the batch object, you need to format this like a query string and send it in the body param.
Also, relative_url should not begin with a '/'
Try posting this instead...
https://graph.facebook.com/batch?access_token=TOKEN&method=post&batch=
[
{
"method": "post",
"relative_uri": "me/your_namespace:find",
"body": "egg=http%3A%2F%2Fwww.mydomain.com%2Fmy_namespace%2Fog%2Fegg.php%3Ftypeid%3D-966&start_time= 1317439270&end_time= 1317439270
}
]
I've tested this and it works.
When Posting data to the batch API, the data must be formatted like a querysting and sent in the 'body' param as a string.