Overview

Webhooks can be inserted between sections of a form to call an external service and perform workflow actions on the form based on the result of service call.

Defining a service section

To declare a service section do the following in a form tag.

Any service section related attributes will be scrubbed from the HTML sent to a user's browser even if the service section is set to be visible to users. Users will not be able to discover your web service URLs or HTTP basic auth credentials this way.

 

An example service section declaration can be seen below.  In this particular case the service section is visible from another section, named "Student". The service section could include some visible data fields, which could receive data from the service section call, possibly informing the submitter about how the call to the service went.

<form id="Eligibility_Check" class="form-section visiblefrom-Student formcycle-service-section" formcycle-service-action="https://webapps6-test.weinberg.northwestern.edu/forms-testservices/approve.php" formcycle-service-method="post" formcycle-service-user="test-user" formcycle-service-password="test-pass">
	<!-- Include some fields here if desired -->
</form>

 

 

Data sent by service sections

The JSON data payload POSTed to a web service by a service section includes information about all of the sections related to the form submission, limited to ones visible to the service section.  Also included is information about the related section templates, form version, and form template.  Any users or groups assigned any of the sections are also included.  Below is an example of the data submitted with a service call from Online Forms.  Note that the section names of "Part1-of-form" and "Part2" just happen to be the section names used in the example form, these can be anything you define in your form.

 

{
   "FormVersion":{
      "id":"266",
      "active":true,
      "form_template_id":"162"
   },
   "FormTemplate":{
      "id":"162",
      "name":"Service Section Testing Form",
      "group_id":"1",
      "Group":{
         "id":"1",
         "name":"Weinberg IT",
         "displayname":"Weinberg IT",
         "organization_id":"1",
         "Organization":{
            "id":"1",
            "name":"Weinberg College of Arts and Sciences"
         }
      }
   },
   "Sections":{
      "Part1-of-form":{
         "SectionInstance":{
            "id":"1519",
            "created":"2015-03-26 13:41:38",
            "modified":"2015-03-26 13:41:38",
            "data":{
               "Part1-of-form":{
                  "Date":"3/26/2015",
                  "Student_ID":"123",
                  "First_Name":"Samuel",
                  "Middle_Initial":"X",
                  "Last_Name":"Tudent"
               }
            },
            "section_template_id":"682",
            "user_id":"9",
            "last_saved_by_user_id":"9",
            "parent_section_instance_id":null,
            "approved":true,
            "rejected":false,
            "returned":false,
            "archived":false,
            "optional_not_activated":false,
            "ready":false,
            "group_id":"0",
            "User":{
               "id":"9",
               "firstname":"Samuel",
               "lastname":"Tudent",
               "displayname":"Samuel Tudent",
               "netid":"student"
            },
            "LastSavedByUser":{
               "id":"9",
               "firstname":"Samuel",
               "lastname":"Tudent",
               "displayname":"Samuel Tudent",
               "netid":"student"
            },
            "Group":{
               "id":null,
               "name":null,
               "displayname":null,
               "organization_id":null
            }
         },
         "SectionTemplate":{
            "id":"682",
            "name":"Part1-of-form",
            "form_version_id":"266",
            "order":"1",
            "from_email_address":null,
            "from_email_name":null
         },
         "Attachment":[
         ]
      },
      "Part2":{
         "SectionInstance":{
            "id":"1520",
            "created":"2015-03-26 13:41:38",
            "modified":"2015-03-26 13:41:38",
            "data":[
            ],
            "section_template_id":"683",
            "user_id":"0",
            "last_saved_by_user_id":"0",
            "parent_section_instance_id":"1519",
            "approved":false,
            "rejected":false,
            "returned":false,
            "archived":false,
            "optional_not_activated":false,
            "ready":true,
            "group_id":"0",
            "User":{
               "id":null,
               "firstname":null,
               "lastname":null,
               "displayname":null,
               "netid":null
            },
            "LastSavedByUser":{
               "id":null,
               "firstname":null,
               "lastname":null,
               "displayname":null,
               "netid":null
            },
            "Group":{
               "id":null,
               "name":null,
               "displayname":null,
               "organization_id":null
            }
         },
         "SectionTemplate":{
            "id":"683",
            "name":"Part2",
            "form_version_id":"266",
            "order":"2",
            "from_email_address":null,
            "from_email_name":null
         },
         "Attachment":[
         ]
      },
      "Part3":{
         "SectionInstance":{
            "id":"1521",
            "created":"2015-03-26 13:41:38",
            "modified":"2015-03-26 13:41:38",
            "data":[
            ],
            "section_template_id":"684",
            "user_id":"0",
            "last_saved_by_user_id":"0",
            "parent_section_instance_id":"1519",
            "approved":false,
            "rejected":false,
            "returned":false,
            "archived":false,
            "optional_not_activated":false,
            "ready":false,
            "group_id":"0",
            "User":{
               "id":null,
               "firstname":null,
               "lastname":null,
               "displayname":null,
               "netid":null
            },
            "LastSavedByUser":{
               "id":null,
               "firstname":null,
               "lastname":null,
               "displayname":null,
               "netid":null
            },
            "Group":{
               "id":null,
               "name":null,
               "displayname":null,
               "organization_id":null
            }
         },
         "SectionTemplate":{
            "id":"684",
            "name":"Part3",
            "form_version_id":"266",
            "order":"3",
            "from_email_address":null,
            "from_email_name":null
         },
         "Attachment":[
         ]
      }
   }
}

 

Return data format for web services called by service sections

The web services called by service sections must respond in certain ways to allow Online Forms to understand what should occur with the returned data and the workflow of the form.  There may also be additional data fields that a creator of a web service called by service sections should consider returning.  Below is a list of things a web service must and should do:

 

Return data format for a web service called by Online Forms.

 {
   "status":HTTP_STATUS_CODE,
   "formcycle-action":"ACTION",
   "formcycle-reject-reason":"REASON", (optional, only for formcycle-action = reject)
   "formcycle-return-reason":"REASON", (optional, only for formcycle-action = return)
   "formcycle-return-section-instance-id":"SECTION INSTANCE ID", (required, only for formcycle-action = return)
   "formcycle-data":{				   (optional, only if web service wants data saved in section)
      "FIELDNAME":"DATA", 
      "FIELDNAME":"DATA",          
      "FIELDNAME":"DATA"
   }
}

 

Test web services available to Online Form creators

To make the testing of webhooks / services sections in Online Forms easier we have made several test web services available.  These will each return a specific formcycle-action, and formcycle-data.  These services are available from anywhere on the NU network (129.105.0.0/16, 165.124.0.0/16, 10.0.0.0/8).  Do not POST any sensitive data to these test services, as anything POSTed to them will be recorded in a public log file for debug purposes.

ServiceDescriptionService URLService Log fileNotes
ApproveThis service always approves any request made to ithttps://webapps6-test.weinberg.northwestern.edu/forms-testservices/approve.phphttps://webapps6-test.weinberg.northwestern.edu/forms-testservices/logs/approve.log 
SaveThis service always suggests a save for any request made to ithttps://webapps6-test.weinberg.northwestern.edu/forms-testservices/save.phphttps://webapps6-test.weinberg.northwestern.edu/forms-testservices/logs/save.log 
ReturnThis service always suggests a return to the first section of a form for any request made to ithttps://webapps6-test.weinberg.northwestern.edu/forms-testservices/return.phphttps://webapps6-test.weinberg.northwestern.edu/forms-testservices/logs/return.log 
RejectThis service always suggests a rejection for any request made to ithttps://webapps6-test.weinberg.northwestern.edu/forms-testservices/reject.phphttps://webapps6-test.weinberg.northwestern.edu/forms-testservices/logs/reject.log 
Bad responseThis service always returns a bad response, causing Online Forms to queue the service section action and try again.https://webapps6-test.weinberg.northwestern.edu/forms-testservices/bad-response.phphttps://webapps6-test.weinberg.northwestern.edu/forms-testservices/logs/bad-response.log 
503This service always returns a HTTP 503, service unavailable, causing Online Forms to queue the service section action and try againhttps://webapps6-test.weinberg.northwestern.edu/forms-testservices/503.phphttps://webapps6-test.weinberg.northwestern.edu/forms-testservices/logs/503.log 

All of the test web services will return a HTTP 405 Unsupported Method if you use any HTTP method other than POST.

There is nothing special about the 'usermsg' field in formcycle-data in these services, the field could be named anything in your own service. However, if you call the test services from your own test form and want to see the returned message, you will have to have a field named usermsg in your service section.

 

 

Example returned data from a POST to approve.php test service:

{
   "status":200,
   "formcycle-action":"approve",
   "formcycle-data":{
      "usermsg":"The operation succeeded: Approve."
   }
}

 

Example returned data from a POST to save.php test service:

{
   "status":200,
   "formcycle-data":{
      "usermsg":"Returning a save command."
   },
   "formcycle-action":"save"
}

 

Example returned data from a POST to return.php test service.  Note that the formcycle-return-section-instance-id field value will be the section instance tied to the first section template (field 'order' = 1) in the form.  If return.php is unable to figure out which section instance is the first one it will instead issue a reject action, a reject-reason and usermsg explaining why.

{
	"status":200,
	"formcycle-action":"return",
	"formcycle-data":{
		"usermsg":"The operation succeeded: Return."
	},
	"formcycle-return-section-instance-id":"1519",
	"formcycle-return-reason":"Form submission returned back to first section by test service."
}

 

Example returned data from a POST to return.php test service, where it was unable to determine what section to return the form to.  In this case it issues a reject instead.

{
	"status":200,
	"formcycle-action":"reject",
	"formcycle-reject-reason":"Unable to determine where to return form to, rejecting form instead.",
	"formcycle-data":{
		"usermsg":"Unable to determine where to return form to, rejecting form instead."
	}
}

 

 

Example returned data from a POST to reject.php test service:

{
	"status":200,
	"formcycle-action":"reject",
	"formcycle-reject-reason":"This submission was rejected due to not being good enough.",
	"formcycle-data":{
		"usermsg":"This submission has been rejected."
	}
}

 

Example returned data from a POST to 503.php:

 {
	"status":503,
	"formcycle-data":{
		"usermsg":"Service Unavailable: The server is currently unavailable (because it is overloaded or down for maintenance). Generally, this is a temporary state."
	}
}

 

Example returned data from a POST to bad-reponse.php:

<html>
<head>
<title>Bad html response</title>
</head>
<body>
This is a bad response, in that it is HTML as opposed to JSON.
</body>
</html>