Message Boards

Best approach for handling a webhook

thumbnail
Pete Helgren, modified 2 Years ago.

Best approach for handling a webhook

Regular Member Posts: 225 Join Date: 4/7/11 Recent Posts

I am working with a Zoom webhook that triggers when a voicemail is left by a caller.  I created a table to store the webhook details for each call and used the service builder to create the DB IO.  I was *hoping* that I could just expose the SB API in such a way that I wouldn't need much additional plumbing to make it work but I can't figure out how to handle receiving the webhook api call and the json payload.

The Zoom documentation provides this example payload:

{
  "event": "phone.voicemail_received",
  "event_ts": 1626759486127,
  "payload": {
    "account_id": "2AB-cdEFGhijkLnop3qRs",
    "object": {
      "id": "0388975092074598b47330a6a87e9a7b",
      "date_time": "2021-07-20T05:38:04Z",
      "download_url": "example.com",
      "duration": 30,
      "caller_number": "15550100",
      "caller_number_type": 1,
      "caller_name": "Dana",
      "callee_user_id": "user",
      "callee_number": "15550101",
      "callee_number_type": 1,
      "callee_name": "Alex",
      "callee_extension_type": "string",
      "callee_id": "user"
    }
  }
}

 

The SB method I exposed will work with that payload.  But when I use Postman to test I have to add a a bit more to the body

The URL :  http://localhost:9080/api/jsonws/invoke

And this added to the body:
{"/myapp.vmrecord/add-voice-mail-record":  then the payload and then close with a }

So the whole body becomes:
 

{"/myapp.vmrecord/add-voice-mail-record":
{
        "event": "phone.voicemail_received",
        "event_ts": 1626759486127,
        "payload": {
            "account_id": "2AB-cdEFGhijkLnop3qRs",
            "object": {
                "id": "0388975092074598b47330a6a87e9a7b",
                "date_time": "2021-07-20T05:38:04Z",
                "download_url": "example.com",
                "duration": 30,
                "caller_number": "15550100",
                "caller_number_type": 1,
                "caller_name": "Dana",
                "callee_user_id": "user",
                "callee_number": "15550101",
                "callee_number_type": 1,
                "callee_name": "Alex",
                "callee_extension_type": "string",
                "callee_id": "user"
            }
        }
    }
}


So the question is:  Can i invoke the SB API (method) and pass the payload without adding the "/myapp.vmrecord/add-voice-mail-record": to the body (which I cannot do because Zoom is the one who sends the body in the webhook call as a POST)

I tried http://localhost:9080/api/jsonws/invoke/myapp.vmrecord/add-voice-mail-record/json  but it doesn't recognize the signature.

So the question is:  What is the best appraoch when you want a webhook to return json data and LR to consune it?  The SB part is sorted, the question is, do I need to frontend with with a portlet or other application to be able to consume it?

 

thumbnail
Pete Helgren, modified 2 Years ago.

RE: Best approach for handling a webhook (Answer)

Regular Member Posts: 225 Join Date: 4/7/11 Recent Posts

OK.  Hearing no suggestions, I went ahead and created a front end servlet to listen for the webhook calls and then called the SB methods to update the DB with the webhook content.  The only "tricky" part is that the webhook only passes a json object in the body.  So the solution at the servlet end was to do this:
 

	public void doPost(HttpServletRequest request, HttpServletResponse response)
	  {
		
		// grab the whole body
		
		try {
			BufferedReader br = request.getReader();
			
			String json = br.lines().collect(Collectors.joining());
			
			 VMRecordLocalServiceUtil. addVoiceMailRecord(json);
			 
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	 }

The SB method took the json onject as a string, converted it to a JSON object, and then created a DB object, added the properties and added the record to the DB.  Don't know if it is the easiet approach to handling a webhook that passes a json object but this works and is simple.

Scarletake Bwi, modified 2 Years ago.

RE: RE: Best approach for handling a webhook

Expert Posts: 326 Join Date: 12/20/10 Recent Posts

hi Pete

can you share how your SB method work with that payload.

i use Chatwoot, webhook of Chatwoot will send a POST request with the payload to the configured URL.

but i do not know how to get payload infomation from SB method(exposed REST).

now i do is very like yours, but i use dynamic web project and jsp to do it.

thank you in advance.

thumbnail
Pete Helgren, modified 2 Years ago.

RE: Best approach for handling a webhook

Regular Member Posts: 225 Join Date: 4/7/11 Recent Posts

Not much magic to it.  The json passed into the addVoiceMailRecord S/B metthod  is then rendered into an object using the import org.json.JSONObject;  So I have:


        JSONObject vmrecord = new JSONObject(json);


that renders the string into an object and at that point it is just parsing the json obejct to get what I need and then use other S/B methods to create the database object and populate it with the properties from the json object
 

SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.ENGLISH);
			
	VMRecord vmr = createVMRecord(id);
				
		try {
			vmr.setDate_time(formatter.parse(date_time));
			vmr.setGeneric_payload_account_id(generic_payload_account_id);
			vmr.setDownload_url(download_url);
			vmr.setDuration(duration);
			vmr.setCaller_number(caller_number);
			vmr.setCaller_number_type(caller_number_type);
			vmr.setCaller_name(caller_name);
			vmr.setCallee_user_id(callee_user_id);
			vmr.setCallee_number(callee_number);
			vmr.setCallee_number_type(callee_number_type);
			vmr.setCallee_name(callee_name);
			vmr.setCallee_extension_type(callee_extension_type);
			vmr.setCallee_id(callee_id);
			
			addVMRecord(vmr);
				
		} catch (Exception e) {
			// TODO Auto-generated catch block
				e.printStackTrace();
		}
			


Thats about it

Scarletake Bwi, modified 2 Years ago.

RE: RE: Best approach for handling a webhook

Expert Posts: 326 Join Date: 12/20/10 Recent Posts

hi Pete

thank you so mush for reply, i think i did not explain well.

Chatwoot will send a POST request with the payload to the configured URL, and i plan use a rest generated by SB to got it.

but i do not know how to get request's body(payload).

the steps are

1. i create a service-builder module, it will have two modules, -api and -service

2. i create a entity, set remote-service  as true

3. in my ServiceImpl, i add a method with notation @AccessControlled(guestAccessEnabled = true)

4. and i build service, generate wsdl....etc.

yes, it will be called, but i do not now how to get request and it's parameter

 

for now, i create a dynamic web project, and put the WAR to webapp, use jsp to do it

<%@ page import="java.io.*"%>

<%

	String payloadBody = null;
	StringBuilder stringBuilder = new StringBuilder();
	BufferedReader bufferedReader = null;

	try {
		InputStream inputStream = request.getInputStream();
		if (inputStream != null) {
			bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
			char[] charBuffer = new char[128];
			int bytesRead = -1;
			while ((bytesRead = bufferedReader.read(charBuffer)) > 0) {
				stringBuilder.append(charBuffer, 0, bytesRead);
			}
		} else {
			stringBuilder.append("");
		}
	} catch (IOException ex) {
		throw ex;
	} finally {
		if (bufferedReader != null) {
			try {
				bufferedReader.close();
			} catch (IOException ex) {
				throw ex;
			}
		}
	}
%>

 

thumbnail
Pete Helgren, modified 2 Years ago.

RE: Best approach for handling a webhook

Regular Member Posts: 225 Join Date: 4/7/11 Recent Posts

I may not be fully understanding either.  The only way I was able to handle the JSON that the api calback passed was to create a servlet that received the callback, grabbed the json payload from the request and then passed it to the S/B api.  So, yes, I had an SB project that handled the "backend".  But I also created a second project, a servlet, that actually handled the "frontend", the callback,  and then passed the payload to the SB.  The service builder itself doesn't recieve the callback, the servlet does and then the servlet calls the SB API to handle the backend.

​​​​​​​I hope that makes it a little clearer.  I could never get just the service builder to handle everything.

Pete

 

Scarletake Bwi, modified 2 Years ago.

RE: RE: Best approach for handling a webhook

Expert Posts: 326 Join Date: 12/20/10 Recent Posts

Hi Pete

thank you, very much.

yeah, but my goal is to develop, receive, process, and send back all by liferay.
if there have any new news, I will share with you

 

have a nice day

Scarletake Bwi, modified 2 Years ago.

RE: RE: Best approach for handling a webhook

Expert Posts: 326 Join Date: 12/20/10 Recent Posts

hi

I create a mvc-module, and relate the service-builder api.

and create a site and page(public), pull the mvc-module in the page.

i use view.jsp to do receiving job, 

by this way, i do not need to generate a new WAR and i can modify it just like other module.

This is the best way I think so far