1

I am wanting to test Podio webhooks locally. I am using Conveyor.cloud for tunneling and tested it successfully with their Twilio example. The problem I am having with converting the code to work with Podio is that the Twilio example used a Controller and the Podio webhook example at http://podio.github.io/podio-dotnet/webhooks/ uses IHttpHandler.

I tried implementing IHttpHandler to the controller in the code below and it's not working.

using System;
using System.Web;
using System.Web.Mvc;
using PodioAPI;

namespace WebhooksProject.Controllers
{
    public class WebController : IHttpHandler
    {
        public static string clientId = "abcd";
        public static string clientSecret = "abcd";
        public static string username = "a@b.com";
        public static string password = "abcd";

        public static Podio podio = new Podio(clientId, clientSecret);

        public void ProcessRequest(HttpContext context)
        {
            podio.AuthenticateWithPassword(username, password);

            var request = context.Request;

            switch (request["type"])
            {
                case "hook.verify":
                    podio.HookService.ValidateHookVerification(int.Parse(request["hook_id"]), request["code"]);
                    break;
                // An item was created
                case "item.create":
                    // For item events you will get "item_id", "item_revision_id" and "external_id". in post params
                    int itemIdOfCreatedItem = int.Parse(request["item_id"]);
                    // Fetch the item and do what ever you want
                    break;

                // An item was updated
                case "item.update":
                    // For item events you will get "item_id", "item_revision_id" and "external_id". in post params
                    int itemIdOfUpdatedItem = int.Parse(request["item_id"]);
                    // Fetch the item and do what ever you want
                    break;

                // An item was deleted    
                case "item.delete":
                    // For item events you will get "item_id", "item_revision_id" and "external_id". in post params
                    int deletedItemId = int.Parse(request["item_id"]);
                    break;
            }
        }

        public bool IsReusable
        {
            get{return false;}
        }
    }
}

What am I missing?

Xiolin
  • 121
  • 10
  • why implement HttpHandler? you can do it using a normal controller action – Akbar Badhusha Jun 05 '19 at 01:30
  • @AkbarBadhusha I tried to just use the normal controller action but I couldn't figure out how to access the `context`. In my original controller with the Twilio example I had an Index method: `public TwiMLResult Index(SmsRequest request) { var response = new MessagingResponse(); response.Message("Hello World"); return TwiML(response); }`This provided an SmsRequest object. How do I get the Podio object? Am I heading in the right direction? – Xiolin Jun 06 '19 at 00:45
  • why do you need the context? – Akbar Badhusha Jun 06 '19 at 01:18

2 Answers2

2

You can do as below instead of using HttpContext. I basically use requestbin to get the request then try it directly using Postman.

    [HttpPost]
    public HttpResponseMessage ProcessRequest(PodioHook hook)
    {
        var oAuth = _podio.AuthenticateWithApp(_appId, _appToken); // keep the oauth if you are reusing it.

        switch (hook.type)
        {
            case "hook.verify":
                _podio.HookService.ValidateHookVerification(hook.hook_id, hook.code);
                break;
            // An item was created
            case "item.create":
                // For item events you will get "item_id", "item_revision_id" and "external_id". in post params
                long itemIdOfCreatedItem = hook.item_id;
                // Fetch the item and do what ever you want
                break;

            // An item was updated
            case "item.update":
                // For item events you will get "item_id", "item_revision_id" and "external_id". in post params
                long itemIdOfUpdatedItem = hook.item_id;
                // Fetch the item and do what ever you want
                break;

            // An item was deleted    
            case "item.delete":
                // For item events you will get "item_id", "item_revision_id" and "external_id". in post params
                long deletedItemId = hook.item_id;
                break;
        }

        return new HttpResponseMessage(HttpStatusCode.OK);
    }

my PodioHook model will looks like below

public class PodioHook
{
    public string code { get; set; }
    public string type { get; set; }
    public long item_id { get; set; }
    public int hook_id { get; set; }
}

.NET framework will take care of the request to model conversion.

link to request bin https://requestbin.com/

Akbar Badhusha
  • 2,415
  • 18
  • 30
  • I used your code above, added the dependencies and got it to compile. But when I try to verify the webhook in Podio ProcessRequest does not fire. I tried using both https://webhooksproject.conveyor.cloud/Web/ProcessRequest and https://webhooksproject.conveyor.cloud/Web for the webhook. I am still using Conveyor. Do I need to use RequestBin or Postman to run this code? I have not used them before. I've spent the last 3 weeks trying to figure this out and can't seem to get it. Thank you for helping me. – Xiolin Jun 06 '19 at 03:49
  • i would suggest using requestbin and postman. It won't feel the same comfort as in tunneling, but it works fine. create the podio hook with public url provided by the requestbin. then get the json posted by the podio api through the requestbin. Mimic the flow using postman. Let me know if you need help on any of above – Akbar Badhusha Jun 06 '19 at 03:59
  • I don't understand. So I get a url from RequestBin. I then use that url to create a webhook in Podio. Is that right so far? If so, how then, when Podio sends a verification request, does that request go through Postman to my local machine? – Xiolin Jun 06 '19 at 21:02
  • Steps to test podio hooks manually in local 1. Get a public uri from requestbin and Create hook using that url 2. Get the json from requestbin 3. Post that json to local machine manually using postman. You need to do it manually. I'm not sure if there are any other options. but i felt this one easy. – Akbar Badhusha Jun 07 '19 at 02:17
  • 1
    I applied your PodioHook code to the controller I was using with Twilio and Conveyor and it worked. Thank you! – Xiolin Jun 08 '19 at 02:25
0

There are a couple of ways to test your webhook locally.

Unit Testing

You can unit write a unit test, then mock the context parameter in your method using a mocking library such as Moq for .NET. This is the fastest method, but best done last as you need to know the exact structure of the webhook request format in order to be able to mock it.

Integration Test

You can use Postman or a similar tool or write code to create a http request to your endpoint, using the same request format as your webhook. Again, you also need to know the request format your webhook provider is going to send you.

End to end test

This is where you trigger your provider to hit your webhook. This is the method is the most realistic compared to what will happen in production. I like to do this method first, as I can then re-use the request structure of the webhook request, once I have it working, in the Integration and Unit Tests.

You'll need your endpoint exposed at a public URL. While you could deploy your code to a public server, an easier way is to use expose.sh. You can run expose 80 for example and it will expose your local server over a public URL, like https://a2cD.expose.sh.

By running your service locally during the end to end test you'll have access to your IDE to make changes and all of your debugging tools, which means you'll be more productive and save time. There is a guide on using expose.sh to test webhooks here

Disclaimer: I built expose.sh