blob: e146294779cf0a2141732b00d861121541970264 [file] [log] [blame]
<!DOCTYPE html><html><head><title>Contribute a Webhooks Connector</title><meta charset="utf-8"/><meta content="IE=edge,chrome=1" http-equiv="X-UA-Compatible"/><meta name="viewport" content="width=device-width, initial-scale=1.0"/><meta class="swiftype" name="title" data-type="string" content="Contribute a Webhooks Connector"/><link rel="canonical" href="https://docs.prediction.io/community/contribute-webhook/"/><link href="/images/favicon/normal-b330020a.png" rel="shortcut icon"/><link href="/images/favicon/apple-c0febcf2.png" rel="apple-touch-icon"/><link href="//fonts.googleapis.com/css?family=Open+Sans:300italic,400italic,600italic,700italic,800italic,400,300,600,700,800" rel="stylesheet"/><link href="//maxcdn.bootstrapcdn.com/font-awesome/4.2.0/css/font-awesome.min.css" rel="stylesheet"/><link href="/stylesheets/application-3598c7d7.css" rel="stylesheet" type="text/css"/><script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.2/html5shiv.min.js"></script><script src="//cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script><script src="//use.typekit.net/pqo0itb.js"></script><script>try{Typekit.load({ async: true });}catch(e){}</script></head><body><div id="global"><header><div class="container" id="header-wrapper"><div class="row"><div class="col-sm-12"><div id="logo-wrapper"><span id="drawer-toggle"></span><a href="#"></a><a href="http://predictionio.incubator.apache.org/"><img alt="PredictionIO" id="logo" src="/images/logos/logo-ee2b9bb3.png"/></a></div><div id="menu-wrapper"><div id="header-nav-options-wrapper"><ul><li><a href="/">Install & Doc</a></li> <li><a href="/support">Support</a></li> </ul></div><div id="pill-wrapper"><a class="pill left" href="//templates.prediction.io/">TEMPLATES</a> <a class="pill right" href="//github.com/apache/incubator-predictionio/">OPEN SOURCE</a></div></div><img class="mobile-search-bar-toggler hidden-md hidden-lg" src="/images/icons/search-glass-704bd4ff.png"/></div></div></div></header><div id="search-bar-row-wrapper"><div class="container-fluid" id="search-bar-row"><div class="row"><div class="col-md-9 col-sm-11 col-xs-11"><div class="hidden-md hidden-lg" id="mobile-page-heading-wrapper"><p>PredictionIO Docs</p><h4>Contribute a Webhook</h4></div><h4 class="hidden-sm hidden-xs">PredictionIO Docs</h4></div><div class="col-md-3 col-sm-1 col-xs-1 hidden-md hidden-lg"><img id="left-menu-indicator" src="/images/icons/down-arrow-dfe9f7fe.png"/></div><div class="col-md-3 col-sm-12 col-xs-12 swiftype-wrapper"><div class="swiftype"><form class="search-form"><img class="search-box-toggler hidden-xs hidden-sm" src="/images/icons/search-glass-704bd4ff.png"/><div class="search-box"><img src="/images/icons/search-glass-704bd4ff.png"/><input type="text" id="st-search-input" class="st-search-input" placeholder="Search Doc..."/></div><img class="swiftype-row-hider hidden-md hidden-lg" src="/images/icons/drawer-toggle-active-fcbef12a.png"/></form></div></div><div class="mobile-left-menu-toggler hidden-md hidden-lg"></div></div></div></div><div id="page" class="container-fluid"><div class="row"><div id="left-menu-wrapper" class="col-md-3"><nav id="nav-main"><ul><li class="level-1"><a class="expandible" href="/"><span>Apache PredictionIO (incubating) Documentation</span></a><ul><li class="level-2"><a class="final" href="/"><span>Welcome to Apache PredictionIO (incubating)</span></a></li></ul></li><li class="level-1"><a class="expandible" href="#"><span>Getting Started</span></a><ul><li class="level-2"><a class="final" href="/start/"><span>A Quick Intro</span></a></li><li class="level-2"><a class="final" href="/install/"><span>Installing Apache PredictionIO (incubating)</span></a></li><li class="level-2"><a class="final" href="/start/download/"><span>Downloading an Engine Template</span></a></li><li class="level-2"><a class="final" href="/start/deploy/"><span>Deploying Your First Engine</span></a></li><li class="level-2"><a class="final" href="/start/customize/"><span>Customizing the Engine</span></a></li></ul></li><li class="level-1"><a class="expandible" href="#"><span>Integrating with Your App</span></a><ul><li class="level-2"><a class="final" href="/appintegration/"><span>App Integration Overview</span></a></li><li class="level-2"><a class="expandible" href="/sdk/"><span>List of SDKs</span></a><ul><li class="level-3"><a class="final" href="/sdk/java/"><span>Java & Android SDK</span></a></li><li class="level-3"><a class="final" href="/sdk/php/"><span>PHP SDK</span></a></li><li class="level-3"><a class="final" href="/sdk/python/"><span>Python SDK</span></a></li><li class="level-3"><a class="final" href="/sdk/ruby/"><span>Ruby SDK</span></a></li><li class="level-3"><a class="final" href="/sdk/community/"><span>Community Powered SDKs</span></a></li></ul></li></ul></li><li class="level-1"><a class="expandible" href="#"><span>Deploying an Engine</span></a><ul><li class="level-2"><a class="final" href="/deploy/"><span>Deploying as a Web Service</span></a></li><li class="level-2"><a class="final" href="/cli/#engine-commands"><span>Engine Command-line Interface</span></a></li><li class="level-2"><a class="final" href="/deploy/engineparams/"><span>Setting Engine Parameters</span></a></li><li class="level-2"><a class="final" href="/deploy/enginevariants/"><span>Deploying Multiple Engine Variants</span></a></li></ul></li><li class="level-1"><a class="expandible" href="#"><span>Customizing an Engine</span></a><ul><li class="level-2"><a class="final" href="/customize/"><span>Learning DASE</span></a></li><li class="level-2"><a class="final" href="/customize/dase/"><span>Implement DASE</span></a></li><li class="level-2"><a class="final" href="/customize/troubleshooting/"><span>Troubleshooting Engine Development</span></a></li><li class="level-2"><a class="final" href="/api/current/#package"><span>Engine Scala APIs</span></a></li></ul></li><li class="level-1"><a class="expandible" href="#"><span>Collecting and Analyzing Data</span></a><ul><li class="level-2"><a class="final" href="/datacollection/"><span>Event Server Overview</span></a></li><li class="level-2"><a class="final" href="/cli/#event-server-commands"><span>Event Server Command-line Interface</span></a></li><li class="level-2"><a class="final" href="/datacollection/eventapi/"><span>Collecting Data with REST/SDKs</span></a></li><li class="level-2"><a class="final" href="/datacollection/eventmodel/"><span>Events Modeling</span></a></li><li class="level-2"><a class="final" href="/datacollection/webhooks/"><span>Unifying Multichannel Data with Webhooks</span></a></li><li class="level-2"><a class="final" href="/datacollection/channel/"><span>Channel</span></a></li><li class="level-2"><a class="final" href="/datacollection/batchimport/"><span>Importing Data in Batch</span></a></li><li class="level-2"><a class="final" href="/datacollection/analytics/"><span>Using Analytics Tools</span></a></li></ul></li><li class="level-1"><a class="expandible" href="#"><span>Choosing an Algorithm(s)</span></a><ul><li class="level-2"><a class="final" href="/algorithm/"><span>Built-in Algorithm Libraries</span></a></li><li class="level-2"><a class="final" href="/algorithm/switch/"><span>Switching to Another Algorithm</span></a></li><li class="level-2"><a class="final" href="/algorithm/multiple/"><span>Combining Multiple Algorithms</span></a></li><li class="level-2"><a class="final" href="/algorithm/custom/"><span>Adding Your Own Algorithms</span></a></li></ul></li><li class="level-1"><a class="expandible" href="#"><span>ML Tuning and Evaluation</span></a><ul><li class="level-2"><a class="final" href="/evaluation/"><span>Overview</span></a></li><li class="level-2"><a class="final" href="/evaluation/paramtuning/"><span>Hyperparameter Tuning</span></a></li><li class="level-2"><a class="final" href="/evaluation/evaluationdashboard/"><span>Evaluation Dashboard</span></a></li><li class="level-2"><a class="final" href="/evaluation/metricchoose/"><span>Choosing Evaluation Metrics</span></a></li><li class="level-2"><a class="final" href="/evaluation/metricbuild/"><span>Building Evaluation Metrics</span></a></li></ul></li><li class="level-1"><a class="expandible" href="#"><span>System Architecture</span></a><ul><li class="level-2"><a class="final" href="/system/"><span>Architecture Overview</span></a></li><li class="level-2"><a class="final" href="/system/anotherdatastore/"><span>Using Another Data Store</span></a></li></ul></li><li class="level-1"><a class="expandible" href="#"><span>Engine Template Gallery</span></a><ul><li class="level-2"><a class="final" href="http://templates.prediction.io"><span>Browse</span></a></li><li class="level-2"><a class="final" href="/community/submit-template/"><span>Submit your Engine as a Template</span></a></li></ul></li><li class="level-1"><a class="expandible" href="#"><span>Demo Tutorials</span></a><ul><li class="level-2"><a class="final" href="/demo/tapster/"><span>Comics Recommendation Demo</span></a></li><li class="level-2"><a class="final" href="/demo/community/"><span>Community Contributed Demo</span></a></li><li class="level-2"><a class="final" href="/demo/textclassification/"><span>Text Classification Engine Tutorial</span></a></li></ul></li><li class="level-1"><a class="expandible" href="/community/"><span>Getting Involved</span></a><ul><li class="level-2"><a class="final" href="/community/contribute-code/"><span>Contribute Code</span></a></li><li class="level-2"><a class="final" href="/community/contribute-documentation/"><span>Contribute Documentation</span></a></li><li class="level-2"><a class="final" href="/community/contribute-sdk/"><span>Contribute a SDK</span></a></li><li class="level-2"><a class="final active" href="/community/contribute-webhook/"><span>Contribute a Webhook</span></a></li><li class="level-2"><a class="final" href="/community/projects/"><span>Community Projects</span></a></li></ul></li><li class="level-1"><a class="expandible" href="#"><span>Getting Help</span></a><ul><li class="level-2"><a class="final" href="/resources/faq/"><span>FAQs</span></a></li><li class="level-2"><a class="final" href="/support/"><span>Community Support</span></a></li><li class="level-2"><a class="final" href="/support/#enterprise-support"><span>Enterprise Support</span></a></li></ul></li><li class="level-1"><a class="expandible" href="#"><span>Resources</span></a><ul><li class="level-2"><a class="final" href="/resources/intellij/"><span>Developing Engines with IntelliJ IDEA</span></a></li><li class="level-2"><a class="final" href="/resources/upgrade/"><span>Upgrade Instructions</span></a></li><li class="level-2"><a class="final" href="/resources/glossary/"><span>Glossary</span></a></li></ul></li></ul></nav></div><div class="col-md-9 col-sm-12"><div class="content-header hidden-md hidden-lg"><div id="breadcrumbs" class="hidden-sm hidden xs"><ul><li><a href="/community/">Getting Involved</a><span class="spacer">&gt;</span></li><li><span class="last">Contribute a Webhook</span></li></ul></div><div id="page-title"><h1>Contribute a Webhooks Connector</h1></div></div><div id="table-of-content-wrapper"><h5>On this page</h5><aside id="table-of-contents"><ul> <li> <a href="#example">Example</a> <ul> <li> <a href="#1-implement-webhooks-connector">1. Implement Webhooks Connector</a> </li> <li> <a href="#2-integrate-the-connector-into-event-server">2. Integrate the Connector into Event Server</a> </li> </ul> </li> </ul> </aside><hr/><a id="edit-page-link" href="https://github.com/apache/incubator-predictionio/tree/livedoc/docs/manual/source/community/contribute-webhook.html.md"><img src="/images/icons/edit-pencil-d6c1bb3d.png"/>Edit this page</a></div><div class="content-header hidden-sm hidden-xs"><div id="breadcrumbs" class="hidden-sm hidden xs"><ul><li><a href="/community/">Getting Involved</a><span class="spacer">&gt;</span></li><li><span class="last">Contribute a Webhook</span></li></ul></div><div id="page-title"><h1>Contribute a Webhooks Connector</h1></div></div><div class="content"><div class="alert-message note"><p>Please check out the <a href="https://github.com/apache/incubator-predictionio">latest develop branch</a>.</p></div><p>Event server can collect data from other third-party sites or software through their webhooks services (for example, SegmentIO, MailChimp). To support that, a <em>Webhooks Connector</em> for the third-party data is needed to be integrated into Event Server. The job of the <em>Webhooks Connector</em> is as simply as converting the third-party data into Event JSON. You can find an example below.</p><p>Currently we support two types of connectors: <code>JsonConnector</code> and <code>FormConnector</code>, which is responsible for accepting <em>JSON</em> data and <em>Form-submission</em> data, respectively.</p><p><strong>JsonConnector</strong>:</p><div class="highlight scala"><table style="border-spacing: 0"><tbody><tr><td class="gutter gl" style="text-align: right"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13</pre></td><td class="code"><pre><span class="k">package</span> <span class="nn">io.prediction.data.webhooks</span>
<span class="cm">/** Connector for Webhooks connection */</span>
<span class="k">private</span><span class="o">[</span><span class="kt">prediction</span><span class="o">]</span> <span class="k">trait</span> <span class="nc">JsonConnector</span> <span class="o">{</span>
<span class="cm">/** Convert from original JObject to Event JObject
* @param data original JObject recevived through webhooks
* @return Event JObject
*/</span>
<span class="k">def</span> <span class="n">toEventJson</span><span class="o">(</span><span class="n">data</span><span class="k">:</span> <span class="kt">JObject</span><span class="o">)</span><span class="k">:</span> <span class="kt">JObject</span>
<span class="o">}</span>
</pre></td></tr></tbody></table> </div> <p>The EventServer URL path to collect webhooks JSON data:</p><div class="highlight shell"><table style="border-spacing: 0"><tbody><tr><td class="gutter gl" style="text-align: right"><pre class="lineno">1</pre></td><td class="code"><pre>http://&lt;EVENT SERVER URL&gt;/webhooks/&lt;CONNECTOR_NAME&gt;.json?accessKey<span class="o">=</span>&lt;YOUR_ACCESS_KEY&gt;&amp;channel<span class="o">=</span>&lt;CHANNEL_NAME&gt;
</pre></td></tr></tbody></table> </div> <p>Note that you may collect Webhooks data into default channel (without the <code>channel</code> parameter in the URL) but it&#39;s highly recommended to create dedicated <a href="/datacollection/channel/">Channel</a> to collect specific Webhooks data (e.g. create one channel &quot;segmentio&quot; for SegmentIO and another channel &quot;mailchimp&quot; for Mailchimp data) because it allows you to manage and query data more easily, and the Webhooks data won&#39;t be mixed with your other normal app data.</p><p><strong>FormConnector</strong>:</p><div class="highlight scala"><table style="border-spacing: 0"><tbody><tr><td class="gutter gl" style="text-align: right"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14</pre></td><td class="code"><pre><span class="k">package</span> <span class="nn">io.prediction.data.webhooks</span>
<span class="cm">/** Connector for Webhooks connection with Form submission data format
*/</span>
<span class="k">private</span><span class="o">[</span><span class="kt">prediction</span><span class="o">]</span> <span class="k">trait</span> <span class="nc">FormConnector</span> <span class="o">{</span>
<span class="cm">/** Convert from original Form submission data to Event JObject
* @param data Map of key-value pairs in String type received through webhooks
* @return Event JObject
*/</span>
<span class="k">def</span> <span class="n">toEventJson</span><span class="o">(</span><span class="n">data</span><span class="k">:</span> <span class="kt">Map</span><span class="o">[</span><span class="kt">String</span>, <span class="kt">String</span><span class="o">])</span><span class="k">:</span> <span class="kt">JObject</span>
<span class="o">}</span>
</pre></td></tr></tbody></table> </div> <p>The EventServer URL path to collect webhooks form-subimssion data (no .json):</p><div class="highlight shell"><table style="border-spacing: 0"><tbody><tr><td class="gutter gl" style="text-align: right"><pre class="lineno">1</pre></td><td class="code"><pre>http://&lt;EVENT SERVER URL&gt;/webhooks/&lt;CONNECTOR_NAME&gt;?accessKey<span class="o">=</span>&lt;YOUR_ACCESS_KEY&gt;&amp;channel<span class="o">=</span>&lt;CHANNEL_NAME&gt;
</pre></td></tr></tbody></table> </div> <p>Note that you may collect Webhooks data into default channel (without the <code>channel</code> parameter in the URL) but it&#39;s highly recommended to create dedicated <a href="/datacollection/channel/">Channel</a> to collect specific Webhooks data (e.g. create one channel &quot;segmentio&quot; for SegmentIO and another channel &quot;mailchimp&quot; for Mailchimp data) because it allows you to manage and query data more easily, and the Webhooks data won&#39;t be mixed with your other normal app data.</p><h1 id='example' class='header-anchors'>Example</h1><p>For example, let&#39;s say there is a third-party website (say, it is named &quot;ExampleJson&quot;) which can send the following JSON data through its webhooks service and we would like to collect it into Event Store.</p><p><strong>UserActionItem</strong>:</p><div class="highlight json"><table style="border-spacing: 0"><tbody><tr><td class="gutter gl" style="text-align: right"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14</pre></td><td class="code"><pre><span class="p">{</span><span class="w">
</span><span class="s2">"type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"userActionItem"</span><span class="p">,</span><span class="w">
</span><span class="s2">"userId"</span><span class="p">:</span><span class="w"> </span><span class="s2">"as34smg4"</span><span class="p">,</span><span class="w">
</span><span class="s2">"event"</span><span class="p">:</span><span class="w"> </span><span class="s2">"do_something_on"</span><span class="p">,</span><span class="w">
</span><span class="s2">"itemId"</span><span class="p">:</span><span class="w"> </span><span class="s2">"kfjd312bc"</span><span class="p">,</span><span class="w">
</span><span class="s2">"context"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="s2">"ip"</span><span class="p">:</span><span class="w"> </span><span class="s2">"1.23.4.56"</span><span class="p">,</span><span class="w">
</span><span class="s2">"prop1"</span><span class="p">:</span><span class="w"> </span><span class="mf">2.345</span><span class="p">,</span><span class="w">
</span><span class="s2">"prop2"</span><span class="p">:</span><span class="w"> </span><span class="s2">"value1"</span><span class="w">
</span><span class="p">},</span><span class="w">
</span><span class="s2">"anotherPropertyA"</span><span class="p">:</span><span class="w"> </span><span class="mf">4.567</span><span class="p">,</span><span class="w">
</span><span class="s2">"anotherPropertyB"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="p">,</span><span class="w">
</span><span class="s2">"timestamp"</span><span class="p">:</span><span class="w"> </span><span class="s2">"2015-01-15T04:20:23.567Z"</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></pre></td></tr></tbody></table> </div> <h2 id='1.-implement-webhooks-connector' class='header-anchors'>1. Implement Webhooks Connector</h2><p>Because the data sent by this third-party &quot;ExampleJson&quot; site is in JSON format, we implement an object <code>ExampleJsonConnector</code> which extends <code>JsonConnector</code>:</p><div class="highlight scala"><table style="border-spacing: 0"><tbody><tr><td class="gutter gl" style="text-align: right"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66</pre></td><td class="code"><pre><span class="k">private</span><span class="o">[</span><span class="kt">prediction</span><span class="o">]</span> <span class="k">object</span> <span class="nc">ExampleJsonConnector</span> <span class="k">extends</span> <span class="nc">JsonConnector</span> <span class="o">{</span>
<span class="k">implicit</span> <span class="k">val</span> <span class="n">json4sFormats</span><span class="k">:</span> <span class="kt">Formats</span> <span class="o">=</span> <span class="nc">DefaultFormats</span>
<span class="k">override</span> <span class="k">def</span> <span class="n">toEventJson</span><span class="o">(</span><span class="n">data</span><span class="k">:</span> <span class="kt">JObject</span><span class="o">)</span><span class="k">:</span> <span class="kt">JObject</span> <span class="o">=</span> <span class="o">{</span>
<span class="k">val</span> <span class="n">common</span> <span class="k">=</span> <span class="k">try</span> <span class="o">{</span>
<span class="n">data</span><span class="o">.</span><span class="n">extract</span><span class="o">[</span><span class="kt">Common</span><span class="o">]</span>
<span class="o">}</span> <span class="k">catch</span> <span class="o">{</span>
<span class="k">case</span> <span class="n">e</span><span class="k">:</span> <span class="kt">Exception</span> <span class="o">=&gt;</span> <span class="k">throw</span> <span class="k">new</span> <span class="nc">ConnectorException</span><span class="o">(</span>
<span class="n">s</span><span class="s">"Cannot extract Common field from ${data}. ${e.getMessage()}"</span><span class="o">,</span> <span class="n">e</span><span class="o">)</span>
<span class="o">}</span>
<span class="k">val</span> <span class="n">json</span> <span class="k">=</span> <span class="k">try</span> <span class="o">{</span>
<span class="n">common</span><span class="o">.</span><span class="n">`type`</span> <span class="k">match</span> <span class="o">{</span>
<span class="k">case</span> <span class="s">"userActionItem"</span> <span class="k">=&gt;</span>
<span class="n">toEventJson</span><span class="o">(</span><span class="n">common</span> <span class="k">=</span> <span class="n">common</span><span class="o">,</span> <span class="n">userActionItem</span> <span class="k">=</span> <span class="n">data</span><span class="o">.</span><span class="n">extract</span><span class="o">[</span><span class="kt">UserActionItem</span><span class="o">])</span>
<span class="k">case</span> <span class="n">x</span><span class="k">:</span> <span class="kt">String</span> <span class="o">=&gt;</span>
<span class="k">throw</span> <span class="k">new</span> <span class="nc">ConnectorException</span><span class="o">(</span>
<span class="n">s</span><span class="s">"Cannot convert unknown type '${x}' to Event JSON."</span><span class="o">)</span>
<span class="o">}</span>
<span class="o">}</span> <span class="k">catch</span> <span class="o">{</span>
<span class="k">case</span> <span class="n">e</span><span class="k">:</span> <span class="kt">ConnectorException</span> <span class="o">=&gt;</span> <span class="k">throw</span> <span class="n">e</span>
<span class="k">case</span> <span class="n">e</span><span class="k">:</span> <span class="kt">Exception</span> <span class="o">=&gt;</span> <span class="k">throw</span> <span class="k">new</span> <span class="nc">ConnectorException</span><span class="o">(</span>
<span class="n">s</span><span class="s">"Cannot convert ${data} to eventJson. ${e.getMessage()}"</span><span class="o">,</span> <span class="n">e</span><span class="o">)</span>
<span class="o">}</span>
<span class="n">json</span>
<span class="o">}</span>
<span class="c1">// Convert the UserActionItem JSON to Event JSON
</span> <span class="k">def</span> <span class="n">toEventJson</span><span class="o">(</span><span class="n">common</span><span class="k">:</span> <span class="kt">Common</span><span class="o">,</span> <span class="n">userActionItem</span><span class="k">:</span> <span class="kt">UserActionItem</span><span class="o">)</span><span class="k">:</span> <span class="kt">JObject</span> <span class="o">=</span> <span class="o">{</span>
<span class="k">import</span> <span class="nn">org.json4s.JsonDSL._</span>
<span class="c1">// map to EventAPI JSON
</span> <span class="k">val</span> <span class="n">json</span> <span class="k">=</span>
<span class="o">(</span><span class="s">"event"</span> <span class="o">-&gt;</span> <span class="n">userActionItem</span><span class="o">.</span><span class="n">event</span><span class="o">)</span> <span class="o">~</span>
<span class="o">(</span><span class="s">"entityType"</span> <span class="o">-&gt;</span> <span class="s">"user"</span><span class="o">)</span> <span class="o">~</span>
<span class="o">(</span><span class="s">"entityId"</span> <span class="o">-&gt;</span> <span class="n">userActionItem</span><span class="o">.</span><span class="n">userId</span><span class="o">)</span> <span class="o">~</span>
<span class="o">(</span><span class="s">"targetEntityType"</span> <span class="o">-&gt;</span> <span class="s">"item"</span><span class="o">)</span> <span class="o">~</span>
<span class="o">(</span><span class="s">"targetEntityId"</span> <span class="o">-&gt;</span> <span class="n">userActionItem</span><span class="o">.</span><span class="n">itemId</span><span class="o">)</span> <span class="o">~</span>
<span class="o">(</span><span class="s">"eventTime"</span> <span class="o">-&gt;</span> <span class="n">userActionItem</span><span class="o">.</span><span class="n">timestamp</span><span class="o">)</span> <span class="o">~</span>
<span class="o">(</span><span class="s">"properties"</span> <span class="o">-&gt;</span> <span class="o">(</span>
<span class="o">(</span><span class="s">"context"</span> <span class="o">-&gt;</span> <span class="n">userActionItem</span><span class="o">.</span><span class="n">context</span><span class="o">)</span> <span class="o">~</span>
<span class="o">(</span><span class="s">"anotherPropertyA"</span> <span class="o">-&gt;</span> <span class="n">userActionItem</span><span class="o">.</span><span class="n">anotherPropertyA</span><span class="o">)</span> <span class="o">~</span>
<span class="o">(</span><span class="s">"anotherPropertyB"</span> <span class="o">-&gt;</span> <span class="n">userActionItem</span><span class="o">.</span><span class="n">anotherPropertyB</span><span class="o">)</span>
<span class="o">))</span>
<span class="n">json</span>
<span class="o">}</span>
<span class="c1">// Common required fields
</span> <span class="k">case</span> <span class="k">class</span> <span class="nc">Common</span><span class="o">(</span>
<span class="n">`type`</span><span class="k">:</span> <span class="kt">String</span>
<span class="o">)</span>
<span class="c1">// UserActionItem fields
</span> <span class="k">case</span> <span class="k">class</span> <span class="nc">UserActionItem</span> <span class="o">(</span>
<span class="n">userId</span><span class="k">:</span> <span class="kt">String</span><span class="o">,</span>
<span class="n">event</span><span class="k">:</span> <span class="kt">String</span><span class="o">,</span>
<span class="n">itemId</span><span class="k">:</span> <span class="kt">String</span><span class="o">,</span>
<span class="n">context</span><span class="k">:</span> <span class="kt">JObject</span><span class="o">,</span>
<span class="n">anotherPropertyA</span><span class="k">:</span> <span class="kt">Option</span><span class="o">[</span><span class="kt">Double</span><span class="o">],</span>
<span class="n">anotherPropertyB</span><span class="k">:</span> <span class="kt">Option</span><span class="o">[</span><span class="kt">Boolean</span><span class="o">],</span>
<span class="n">timestamp</span><span class="k">:</span> <span class="kt">String</span>
<span class="o">)</span>
<span class="o">}</span>
</pre></td></tr></tbody></table> </div> <p>You can find the complete example in <a href="https://github.com/apache/incubator-predictionio/blob/develop/data/src/main/scala/io/prediction/data/webhooks/examplejson/ExampleJsonConnector.scala">the GitHub repo</a> and how to write <a href="https://github.com/apache/incubator-predictionio/blob/develop/data/src/test/scala/io/prediction/data/webhooks/examplejson/ExampleJsonConnectorSpec.scala">tests for the connector</a>.</p><p>Please put the connector code in a separate directory for each site. For example, code for segmentio connector should be in</p><div class="highlight shell"><table style="border-spacing: 0"><tbody><tr><td class="gutter gl" style="text-align: right"><pre class="lineno">1</pre></td><td class="code"><pre>data/src/main/scala/io/prediction/data/webhooks/segmentio/
</pre></td></tr></tbody></table> </div> <p>and tests should be in</p><div class="highlight shell"><table style="border-spacing: 0"><tbody><tr><td class="gutter gl" style="text-align: right"><pre class="lineno">1</pre></td><td class="code"><pre>data/src/test/scala/io/prediction/data/webhooks/segmentio/
</pre></td></tr></tbody></table> </div> <p><strong>For form-submission data</strong>, you can find the comple example <a href="https://github.com/apache/incubator-predictionio/blob/develop/data/src/main/scala/io/prediction/data/webhooks/exampleform/ExampleFormConnector.scala">the GitHub repo</a> and how to write <a href="https://github.com/apache/incubator-predictionio/blob/develop/data/src/test/scala/io/prediction/data/webhooks/exampleform/ExampleFormConnectorSpec.scala">tests for the connector</a>.</p><h2 id='2.-integrate-the-connector-into-event-server' class='header-anchors'>2. Integrate the Connector into Event Server</h2><p>Once we have the connector implemented, we can add this to the EventServer so we can collect real-time data.</p><p>Add the connector to <a href="https://github.com/apache/incubator-predictionio/blob/develop/data/src/main/scala/io/prediction/data/api/WebhooksConnectors.scala"><code>WebhooksConnectors</code> object</a>:</p><div class="highlight scala"><table style="border-spacing: 0"><tbody><tr><td class="gutter gl" style="text-align: right"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17</pre></td><td class="code"><pre>
<span class="k">import</span> <span class="nn">io.prediction.data.webhooks.examplejson.ExampleJsonConnector</span> <span class="c1">// ADDED
</span>
<span class="k">private</span><span class="o">[</span><span class="kt">prediction</span><span class="o">]</span> <span class="k">object</span> <span class="nc">WebhooksConnectors</span> <span class="o">{</span>
<span class="c1">// Map of Connector Name to Connector
</span> <span class="k">val</span> <span class="n">json</span><span class="k">:</span> <span class="kt">Map</span><span class="o">[</span><span class="kt">String</span>, <span class="kt">JsonConnector</span><span class="o">]</span> <span class="k">=</span> <span class="nc">Map</span><span class="o">(</span>
<span class="s">"segmentio"</span> <span class="o">-&gt;</span> <span class="nc">SegmentIOConnector</span><span class="o">,</span>
<span class="s">"examplejson"</span> <span class="o">-&gt;</span> <span class="nc">ExampleJsonConnector</span> <span class="c1">// ADDED
</span> <span class="o">)</span>
<span class="c1">// Map of Connector Name to Connector
</span> <span class="k">val</span> <span class="n">form</span><span class="k">:</span> <span class="kt">Map</span><span class="o">[</span><span class="kt">String</span>, <span class="kt">FormConnector</span><span class="o">]</span> <span class="k">=</span> <span class="nc">Map</span><span class="o">(</span>
<span class="s">"mailchimp"</span> <span class="o">-&gt;</span> <span class="nc">MailChimpConnector</span>
<span class="o">)</span>
<span class="o">}</span>
</pre></td></tr></tbody></table> </div> <p>Note that the name of the connectors (e.g. &quot;examplejson&quot;, &quot;segmentio&quot;) will be used as the webhooks URL. In this example, the event server URL to collect data from &quot;ExampleJson&quot; would be:</p><div class="highlight shell"><table style="border-spacing: 0"><tbody><tr><td class="gutter gl" style="text-align: right"><pre class="lineno">1</pre></td><td class="code"><pre>http://&lt;EVENT SERVER URL&gt;/webhooks/examplejson.json?accessKey<span class="o">=</span>&lt;YOUR_ACCESS_KEY&gt;&amp;channel<span class="o">=</span>&lt;CHANNEL_NAME&gt;
</pre></td></tr></tbody></table> </div> <p>For <code>FormConnector</code>, the URL doesn&#39;t have <code>.json</code>. For example,</p><div class="highlight shell"><table style="border-spacing: 0"><tbody><tr><td class="gutter gl" style="text-align: right"><pre class="lineno">1</pre></td><td class="code"><pre>http://&lt;EVENT SERVER URL&gt;/webhooks/mailchimp?accessKey<span class="o">=</span>&lt;YOUR_ACCESS_KEY&gt;&amp;channel<span class="o">=</span>&lt;CHANNEL_NAME&gt;
</pre></td></tr></tbody></table> </div> <p>That&#39;s it. Once you re-compile Apache PredictionIO (incubating), you can send the ExampleJson data to the following URL and the data will be stored to the App of the corresponding Access Key.</p></div></div></div></div><footer><div class="container"><div class="seperator"></div><div class="row"><div class="col-md-6 col-xs-6 footer-link-column"><div class="footer-link-column-row"><h4>Community</h4><ul><li><a href="//docs.prediction.io/install/" target="blank">Download</a></li><li><a href="//docs.prediction.io/" target="blank">Docs</a></li><li><a href="//github.com/apache/incubator-predictionio" target="blank">GitHub</a></li><li><a href="mailto:user-subscribe@predictionio.incubator.apache.org" target="blank">Subscribe to User Mailing List</a></li><li><a href="//stackoverflow.com/questions/tagged/predictionio" target="blank">Stackoverflow</a></li></ul></div></div><div class="col-md-6 col-xs-6 footer-link-column"><div class="footer-link-column-row"><h4>Contribute</h4><ul><li><a href="//predictionio.incubator.apache.org/community/contribute-code/" target="blank">Contribute</a></li><li><a href="//github.com/apache/incubator-predictionio" target="blank">Source Code</a></li><li><a href="//issues.apache.org/jira/browse/PIO" target="blank">Bug Tracker</a></li><li><a href="mailto:dev-subscribe@predictionio.incubator.apache.org" target="blank">Subscribe to Development Mailing List</a></li></ul></div></div></div></div><div id="footer-bottom"><div class="container"><div class="row"><div class="col-md-12"><div id="footer-logo-wrapper"><img alt="PredictionIO" src="/images/logos/logo-white-d1e9c6e6.png"/></div><div id="social-icons-wrapper"><a class="github-button" href="https://github.com/apache/incubator-predictionio" data-style="mega" data-count-href="/apache/incubator-predictionio/stargazers" data-count-api="/repos/apache/incubator-predictionio#stargazers_count" data-count-aria-label="# stargazers on GitHub" aria-label="Star apache/incubator-predictionio on GitHub">Star</a> <a class="github-button" href="https://github.com/apache/incubator-predictionio/fork" data-icon="octicon-git-branch" data-style="mega" data-count-href="/apache/incubator-predictionio/network" data-count-api="/repos/apache/incubator-predictionio#forks_count" data-count-aria-label="# forks on GitHub" aria-label="Fork apache/incubator-predictionio on GitHub">Fork</a> <script id="github-bjs" async="" defer="" src="https://buttons.github.io/buttons.js"></script><a href="//www.facebook.com/predictionio" target="blank"><img alt="PredictionIO on Twitter" src="/images/icons/twitter-ea9dc152.png"/></a> <a href="//twitter.com/predictionio" target="blank"><img alt="PredictionIO on Facebook" src="/images/icons/facebook-5c57939c.png"/></a> </div></div></div></div></div></footer></div><script>(function(w,d,t,u,n,s,e){w['SwiftypeObject']=n;w[n]=w[n]||function(){
(w[n].q=w[n].q||[]).push(arguments);};s=d.createElement(t);
e=d.getElementsByTagName(t)[0];s.async=1;s.src=u;e.parentNode.insertBefore(s,e);
})(window,document,'script','//s.swiftypecdn.com/install/v1/st.js','_st');
_st('install','HaUfpXXV87xoB_zzCQ45');</script><script src="/javascripts/application-5a24945b.js"></script></body></html>