Message Boards
Best approach for handling a webhook
Best approach for handling a webhook
Regular Member Posts: 225 Join Date: 4/7/11 Recent PostsI 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?
RE: Best approach for handling a webhook (Answer)
Regular Member Posts: 225 Join Date: 4/7/11 Recent PostsOK. 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.
RE: RE: Best approach for handling a webhook
Expert Posts: 326 Join Date: 12/20/10 Recent Postshi 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.
RE: Best approach for handling a webhook
Regular Member Posts: 225 Join Date: 4/7/11 Recent PostsNot 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
RE: RE: Best approach for handling a webhook
Expert Posts: 326 Join Date: 12/20/10 Recent Postshi 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;
}
}
}
%>
RE: Best approach for handling a webhook
Regular Member Posts: 225 Join Date: 4/7/11 Recent PostsI 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
RE: RE: Best approach for handling a webhook
Expert Posts: 326 Join Date: 12/20/10 Recent PostsHi 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
RE: RE: Best approach for handling a webhook
Expert Posts: 326 Join Date: 12/20/10 Recent Postshi
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