├── index.html ├── README.md └── diffbot.js /index.html: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 | 5 | 6 | 7 | 115 | 116 | 117 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Diffbot API JavaScript client 2 | 3 | ## Preface 4 | 5 | This API uses the JSONP protocol to support cross domain communication. 6 | 7 | ## Installation 8 | 9 | Include the following JavaScript file just before the closing tag of your HTML document, this assumes your HTML document resides in the same folder. 10 | 11 | ``` 12 | 13 | ``` 14 | 15 | ## Configuration 16 | 17 | To access the API, you first need to create an instance of the Diffbot class. 18 | 19 | ```JavaScript 20 | var client = new Diffbot("DIFFBOT TOKEN"); 21 | ``` 22 | Replacing "DIFFBOT TOKEN" with your developer token, obtainable at http://www.diffbot.com/pricing. 23 | 24 | The library takes care of passing your API token with all API calls for the lifetime of the object. 25 | 26 | ## Usage 27 | 28 | ### Article API 29 | 30 | Assume that we have our `client` configured. Now we can call the get function on the article to retrieve the data we need. 31 | The url parameter must be an absolute url of the page you are retreiving data for. 32 | 33 | ```JavaScript 34 | client.article.get({ 35 | url: "http://www.xconomy.com/san-francisco/2012/07/25/diffbot-is-using-computer-vision-to-reinvent-the-semantic-web/" 36 | }, function onSuccess(response) { 37 | // output the title 38 | var element = document.getElementById("content"); 39 | element.innerHTML = response["objects"][0]["title"]; 40 | }, function onError(response) { 41 | switch(response.errorCode) { 42 | case 401: 43 | alert(response.error) 44 | break; 45 | case 404: 46 | alert(response.error) 47 | break; 48 | case 500: 49 | alert(response.error) 50 | break; 51 | } 52 | }); 53 | ``` 54 | 55 | The first parameter accepts an object with properties as specified in the DiffBot API documentation which can be found here: 56 | http://diffbot.com/products/automatic/article/ 57 | 58 | The second parameter is a callback function which is called if your lookup to the API is successful. The callback function is passed a single parameter containing a JSON object with all of the information returned from the DiffBot API. 59 | 60 | The third parameter is a callback function which is called should an error occur during your lookup. 61 | For example if the page you have request cannot be found, the example above demonstrates how you can differentiate between the error types using the errorCode property returned from 62 | the API 63 | 64 | For detailed documentation of the arguments for the request, and the JSON data returned as part of the response see the DiffBot article documentation. 65 | http://diffbot.com/products/automatic/article/ 66 | 67 | 68 | ### Analyze API 69 | 70 | Calling the Analyze API is the same as calling the article API, just calling a different function within the client. 71 | 72 | ```JavaScript 73 | client.analyze.get({ 74 | url: "http://www.xconomy.com/san-francisco/2012/07/25/diffbot-is-using-computer-vision-to-reinvent-the-semantic-web/" 75 | }, function onSuccess(response) { 76 | // output the type 77 | var element = document.getElementById("content"); 78 | element.innerHTML = response["type"]; 79 | }, function onError(response) { 80 | switch(response.errorCode) { 81 | case 401: 82 | alert(response.error) 83 | break; 84 | case 404: 85 | alert(response.error) 86 | break; 87 | case 500: 88 | alert(response.error) 89 | break; 90 | } 91 | }); 92 | ``` 93 | 94 | The first parameter accepts an object with properties as specified in the DiffBot API documentation which can be found here: 95 | http://diffbot.com/products/automatic/analyze/ 96 | 97 | The second parameter is a callback function which is called if your lookup to the API is successful. The callback function is passed a single parameter containing a JSON object with all of the information returned from the DiffBot API. 98 | 99 | The third parameter is a callback function which is called should an error occur during your lookup. 100 | For example if the page you have request cannot be found, the example above demonstrates how you can differentiate between the error types using the errorCode property returned from 101 | the API 102 | 103 | For detailed documentation of the arguments for the request, and the JSON data returned as part of the response see the DiffBot article documentation. 104 | http://diffbot.com/products/automatic/analyze/ 105 | 106 | 107 | ### Error handling 108 | 109 | Each function has a onError parameter which can be utilised to handle errors returned from the DiffBot API. 110 | 111 | The callback function passes a single argument which is an object returned by the service. 112 | 113 | Here's an example of an error object returned to the callback function : 114 | 115 | ``` 116 | { error: "Not authorized API token.", errorCode: 401 } 117 | ``` 118 | 119 | -Initial commit by Craig Cooke- -------------------------------------------------------------------------------- /diffbot.js: -------------------------------------------------------------------------------- 1 | /* 2 | Diffbot v1.1 3 | Author: Craig Cooke 4 | Updated: John Davi 5 | */ 6 | 7 | /** 8 | Constructor: Create an instance of the Diffbot class. 9 | Parameters: 10 | @token: Your Diffbot API token 11 | **/ 12 | Diffbot = function (token) { 13 | var apiUri = "https://api.diffbot.com/v3/"; // Base url for all requests 14 | 15 | // Utility to wrap private helper functions 16 | var utility = { 17 | callAPI: function callAPI(endpoint, params, successCallback, errorCallback) { 18 | var absoluteUrl = apiUri + endpoint; 19 | 20 | if (endpoint.indexOf('http') == 0) { 21 | absoluteUrl = endpoint; 22 | } 23 | 24 | // See if we have a callback function specified 25 | if (!errorCallback) errorCallback = function (r) { }; 26 | 27 | // Append token to parameters 28 | params.token = token; 29 | 30 | // Split the callback into success or failure. 31 | var callback = function (r) { 32 | if (r.error !== undefined) { 33 | errorCallback(r); 34 | } 35 | else { 36 | successCallback(r); 37 | } 38 | } 39 | 40 | // Make the ajax request 41 | JSONP.get(absoluteUrl, params, callback); 42 | }, 43 | extend: function extend(object1, object2) { 44 | // Append any properties set in object two onto object1 45 | for (var prop in object2) { 46 | object1[prop] = object2[prop]; 47 | } 48 | 49 | return object1; 50 | } 51 | }; 52 | 53 | return { 54 | /* 55 | Call the Article API 56 | params: 57 | @args: An object containing parameters to supply with the API call 58 | @onSuccess: A callback function which is invoked as a result of a successful lookup. Signature: onSuccess(response); 59 | @onError: A callback function which is invoked as a result of an error occuring during a lookup: Signature: onError(response); 60 | */ 61 | article: { 62 | get: function get(args, onSuccess, onError) { 63 | // Define default arguments which will be overridden by properties defined in args 64 | var arguments = utility.extend({ 65 | url: null, 66 | fields: "*" 67 | }, args); 68 | 69 | // Make the API call 70 | utility.callAPI("article", arguments, onSuccess, onError); 71 | } 72 | }, 73 | /* 74 | Call the Discussion API 75 | params: 76 | @args: An object containing parameters to supply with the API call 77 | @onSuccess: A callback function which is invoked as a result of a successful lookup. Signature: onSuccess(response); 78 | @onError: A callback function which is invoked as a result of an error occuring during a lookup: Signature: onError(response); 79 | */ 80 | discussion: { 81 | extract: function extract(args, onSuccess, onError) { 82 | // Define default arguments which will be overridden by properties defined in args 83 | var arguments = utility.extend({ 84 | url: null, 85 | fields: "*" 86 | }, args); 87 | 88 | arguments.format = "json"; // only support JSON? 89 | 90 | // Make the API call 91 | utility.callAPI("discussion", arguments, onSuccess, onError); 92 | } 93 | }, 94 | /* 95 | Call the Product API 96 | params: 97 | @args: An object containing parameters to supply with the API call 98 | @onSuccess: A callback function which is invoked as a result of a successful lookup. Signature: onSuccess(response); 99 | @onError: A callback function which is invoked as a result of an error occuring during a lookup: Signature: onError(response); 100 | */ 101 | product: { 102 | get: function get(args, onSuccess, onError) { 103 | // Define default arguments which will be overridden by properties defined in args 104 | var arguments = utility.extend({ 105 | url: null, 106 | fields: "*", 107 | }, args); 108 | 109 | // Make the API call 110 | utility.callAPI("product", arguments, onSuccess, onError); 111 | } 112 | }, 113 | /* 114 | Call the Image API 115 | params: 116 | @args: An object containing parameters to supply with the API call 117 | @onSuccess: A callback function which is invoked as a result of a successful lookup. Signature: onSuccess(response); 118 | @onError: A callback function which is invoked as a result of an error occuring during a lookup: Signature: onError(response); 119 | */ 120 | image: { 121 | get: function get(args, onSuccess, onError) { 122 | // Define default arguments which will be overridden by properties defined in args 123 | var arguments = utility.extend({ 124 | url: null, 125 | fields: "*" 126 | }, args); 127 | 128 | // Make the API call 129 | utility.callAPI("image", arguments, onSuccess, onError); 130 | } 131 | }, 132 | /* 133 | Call the Video API 134 | params: 135 | @args: An object containing parameters to supply with the API call 136 | @onSuccess: A callback function which is invoked as a result of a successful lookup. Signature: onSuccess(response); 137 | @onError: A callback function which is invoked as a result of an error occuring during a lookup: Signature: onError(response); 138 | */ 139 | video: { 140 | get: function get(args, onSuccess, onError) { 141 | // Define default arguments which will be overridden by properties defined in args 142 | var arguments = utility.extend({ 143 | url: null, 144 | fields: "*" 145 | }, args); 146 | 147 | // Make the API call 148 | utility.callAPI("video", arguments, onSuccess, onError); 149 | } 150 | }, 151 | /* 152 | Call the Analyze API 153 | params: 154 | @args: An object containing parameters to supply with the API call 155 | @onSuccess: A callback function which is invoked as a result of a successful lookup. Signature: onSuccess(response); 156 | @onError: A callback function which is invoked as a result of an error occuring during a lookup: Signature: onError(response); 157 | */ 158 | 159 | analyze: { 160 | get: function get(args, onSuccess, onError) { 161 | // Define default arguments which will be overridden by properties defined in args 162 | var arguments = utility.extend({ 163 | url: null, 164 | fields: "*" 165 | }, args); 166 | 167 | // Make the API call 168 | utility.callAPI("analyze", arguments, onSuccess, onError); 169 | } 170 | }, 171 | /* 172 | Exposes access to any of the DiffBot APIs 173 | params: 174 | @absoluteUrl: The absolute url of the API endpoint to call 175 | @args: An object containing parameters to supply with the API call 176 | @onSuccess: A callback function which is invoked as a result of a successful lookup. Signature: onSuccess(response); 177 | @onError: A callback function which is invoked as a result of an error occuring during a lookup: Signature: onError(response); 178 | */ 179 | call: function (absoluteUrl, args, onSuccess, onError) { 180 | // Make the API call 181 | utility.callAPI(absoluteUrl, args, onSuccess, onError); 182 | } 183 | }; 184 | } 185 | 186 | 187 | /* JSON Library created by Douglas Crockford for backwards compatibility */ 188 | var JSON; 189 | if (!JSON) { 190 | JSON = {}; 191 | } 192 | 193 | (function () { 194 | 'use strict'; 195 | 196 | function f(n) { 197 | // Format integers to have at least two digits. 198 | return n < 10 ? '0' + n : n; 199 | } 200 | 201 | if (typeof Date.prototype.toJSON !== 'function') { 202 | 203 | Date.prototype.toJSON = function (key) { 204 | 205 | return isFinite(this.valueOf()) 206 | ? this.getUTCFullYear() + '-' + 207 | f(this.getUTCMonth() + 1) + '-' + 208 | f(this.getUTCDate()) + 'T' + 209 | f(this.getUTCHours()) + ':' + 210 | f(this.getUTCMinutes()) + ':' + 211 | f(this.getUTCSeconds()) + 'Z' 212 | : null; 213 | }; 214 | 215 | String.prototype.toJSON = 216 | Number.prototype.toJSON = 217 | Boolean.prototype.toJSON = function (key) { 218 | return this.valueOf(); 219 | }; 220 | } 221 | 222 | var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, 223 | escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, 224 | gap, 225 | indent, 226 | meta = { // table of character substitutions 227 | '\b': '\\b', 228 | '\t': '\\t', 229 | '\n': '\\n', 230 | '\f': '\\f', 231 | '\r': '\\r', 232 | '"': '\\"', 233 | '\\': '\\\\' 234 | }, 235 | rep; 236 | 237 | 238 | function quote(string) { 239 | 240 | // If the string contains no control characters, no quote characters, and no 241 | // backslash characters, then we can safely slap some quotes around it. 242 | // Otherwise we must also replace the offending characters with safe escape 243 | // sequences. 244 | 245 | escapable.lastIndex = 0; 246 | return escapable.test(string) ? '"' + string.replace(escapable, function (a) { 247 | var c = meta[a]; 248 | return typeof c === 'string' 249 | ? c 250 | : '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4); 251 | }) + '"' : '"' + string + '"'; 252 | } 253 | 254 | 255 | function str(key, holder) { 256 | 257 | // Produce a string from holder[key]. 258 | 259 | var i, // The loop counter. 260 | k, // The member key. 261 | v, // The member value. 262 | length, 263 | mind = gap, 264 | partial, 265 | value = holder[key]; 266 | 267 | // If the value has a toJSON method, call it to obtain a replacement value. 268 | 269 | if (value && typeof value === 'object' && 270 | typeof value.toJSON === 'function') { 271 | value = value.toJSON(key); 272 | } 273 | 274 | // If we were called with a replacer function, then call the replacer to 275 | // obtain a replacement value. 276 | 277 | if (typeof rep === 'function') { 278 | value = rep.call(holder, key, value); 279 | } 280 | 281 | // What happens next depends on the value's type. 282 | 283 | switch (typeof value) { 284 | case 'string': 285 | return quote(value); 286 | 287 | case 'number': 288 | 289 | // JSON numbers must be finite. Encode non-finite numbers as null. 290 | 291 | return isFinite(value) ? String(value) : 'null'; 292 | 293 | case 'boolean': 294 | case 'null': 295 | 296 | // If the value is a boolean or null, convert it to a string. Note: 297 | // typeof null does not produce 'null'. The case is included here in 298 | // the remote chance that this gets fixed someday. 299 | 300 | return String(value); 301 | 302 | // If the type is 'object', we might be dealing with an object or an array or 303 | // null. 304 | 305 | case 'object': 306 | 307 | // Due to a specification blunder in ECMAScript, typeof null is 'object', 308 | // so watch out for that case. 309 | 310 | if (!value) { 311 | return 'null'; 312 | } 313 | 314 | // Make an array to hold the partial results of stringifying this object value. 315 | 316 | gap += indent; 317 | partial = []; 318 | 319 | // Is the value an array? 320 | 321 | if (Object.prototype.toString.apply(value) === '[object Array]') { 322 | 323 | // The value is an array. Stringify every element. Use null as a placeholder 324 | // for non-JSON values. 325 | 326 | length = value.length; 327 | for (i = 0; i < length; i += 1) { 328 | partial[i] = str(i, value) || 'null'; 329 | } 330 | 331 | // Join all of the elements together, separated with commas, and wrap them in 332 | // brackets. 333 | 334 | v = partial.length === 0 335 | ? '[]' 336 | : gap 337 | ? '[\n' + gap + partial.join(',\n' + gap) + '\n' + mind + ']' 338 | : '[' + partial.join(',') + ']'; 339 | gap = mind; 340 | return v; 341 | } 342 | 343 | // If the replacer is an array, use it to select the members to be stringified. 344 | 345 | if (rep && typeof rep === 'object') { 346 | length = rep.length; 347 | for (i = 0; i < length; i += 1) { 348 | if (typeof rep[i] === 'string') { 349 | k = rep[i]; 350 | v = str(k, value); 351 | if (v) { 352 | partial.push(quote(k) + (gap ? ': ' : ':') + v); 353 | } 354 | } 355 | } 356 | } else { 357 | 358 | // Otherwise, iterate through all of the keys in the object. 359 | 360 | for (k in value) { 361 | if (Object.prototype.hasOwnProperty.call(value, k)) { 362 | v = str(k, value); 363 | if (v) { 364 | partial.push(quote(k) + (gap ? ': ' : ':') + v); 365 | } 366 | } 367 | } 368 | } 369 | 370 | // Join all of the member texts together, separated with commas, 371 | // and wrap them in braces. 372 | 373 | v = partial.length === 0 374 | ? '{}' 375 | : gap 376 | ? '{\n' + gap + partial.join(',\n' + gap) + '\n' + mind + '}' 377 | : '{' + partial.join(',') + '}'; 378 | gap = mind; 379 | return v; 380 | } 381 | } 382 | 383 | // If the JSON object does not yet have a stringify method, give it one. 384 | 385 | if (typeof JSON.stringify !== 'function') { 386 | JSON.stringify = function (value, replacer, space) { 387 | 388 | // The stringify method takes a value and an optional replacer, and an optional 389 | // space parameter, and returns a JSON text. The replacer can be a function 390 | // that can replace values, or an array of strings that will select the keys. 391 | // A default replacer method can be provided. Use of the space parameter can 392 | // produce text that is more easily readable. 393 | 394 | var i; 395 | gap = ''; 396 | indent = ''; 397 | 398 | // If the space parameter is a number, make an indent string containing that 399 | // many spaces. 400 | 401 | if (typeof space === 'number') { 402 | for (i = 0; i < space; i += 1) { 403 | indent += ' '; 404 | } 405 | 406 | // If the space parameter is a string, it will be used as the indent string. 407 | 408 | } else if (typeof space === 'string') { 409 | indent = space; 410 | } 411 | 412 | // If there is a replacer, it must be a function or an array. 413 | // Otherwise, throw an error. 414 | 415 | rep = replacer; 416 | if (replacer && typeof replacer !== 'function' && 417 | (typeof replacer !== 'object' || 418 | typeof replacer.length !== 'number')) { 419 | throw new Error('JSON.stringify'); 420 | } 421 | 422 | // Make a fake root object containing our value under the key of ''. 423 | // Return the result of stringifying the value. 424 | 425 | return str('', { '': value }); 426 | }; 427 | } 428 | 429 | // If the JSON object does not yet have a parse method, give it one. 430 | if (typeof JSON.parse !== 'function') { 431 | JSON.parse = function (text, reviver) { 432 | 433 | // The parse method takes a text and an optional reviver function, and returns 434 | // a JavaScript value if the text is a valid JSON text. 435 | 436 | var j; 437 | 438 | function walk(holder, key) { 439 | 440 | // The walk method is used to recursively walk the resulting structure so 441 | // that modifications can be made. 442 | 443 | var k, v, value = holder[key]; 444 | if (value && typeof value === 'object') { 445 | for (k in value) { 446 | if (Object.prototype.hasOwnProperty.call(value, k)) { 447 | v = walk(value, k); 448 | if (v !== undefined) { 449 | value[k] = v; 450 | } else { 451 | delete value[k]; 452 | } 453 | } 454 | } 455 | } 456 | return reviver.call(holder, key, value); 457 | } 458 | 459 | 460 | // Parsing happens in four stages. In the first stage, we replace certain 461 | // Unicode characters with escape sequences. JavaScript handles many characters 462 | // incorrectly, either silently deleting them, or treating them as line endings. 463 | 464 | text = String(text); 465 | cx.lastIndex = 0; 466 | if (cx.test(text)) { 467 | text = text.replace(cx, function (a) { 468 | return '\\u' + 469 | ('0000' + a.charCodeAt(0).toString(16)).slice(-4); 470 | }); 471 | } 472 | 473 | // In the second stage, we run the text against regular expressions that look 474 | // for non-JSON patterns. We are especially concerned with '()' and 'new' 475 | // because they can cause invocation, and '=' because it can cause mutation. 476 | // But just to be safe, we want to reject all unexpected forms. 477 | 478 | // We split the second stage into 4 regexp operations in order to work around 479 | // crippling inefficiencies in IE's and Safari's regexp engines. First we 480 | // replace the JSON backslash pairs with '@' (a non-JSON character). Second, we 481 | // replace all simple value tokens with ']' characters. Third, we delete all 482 | // open brackets that follow a colon or comma or that begin the text. Finally, 483 | // we look to see that the remaining characters are only whitespace or ']' or 484 | // ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval. 485 | 486 | if (/^[\],:{}\s]*$/ 487 | .test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@') 488 | .replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']') 489 | .replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) { 490 | 491 | // In the third stage we use the eval function to compile the text into a 492 | // JavaScript structure. The '{' operator is subject to a syntactic ambiguity 493 | // in JavaScript: it can begin a block or an object literal. We wrap the text 494 | // in parens to eliminate the ambiguity. 495 | 496 | j = eval('(' + text + ')'); 497 | 498 | // In the optional fourth stage, we recursively walk the new structure, passing 499 | // each name/value pair to a reviver function for possible transformation. 500 | 501 | return typeof reviver === 'function' 502 | ? walk({ '': j }, '') 503 | : j; 504 | } 505 | 506 | // If the text is not JSON parseable, then a SyntaxError is thrown. 507 | 508 | throw new SyntaxError('JSON.parse'); 509 | }; 510 | } 511 | }()); 512 | 513 | /** 514 | * simple JSONP support 515 | * 516 | * JSONP.get('https://api.github.com/gists/1431613', function (data) { console.log(data); }); 517 | * JSONP.get('https://api.github.com/gists/1431613', {}, function (data) { console.log(data); }); 518 | * 519 | * gist: https://gist.github.com/gists/1431613 520 | */ 521 | var JSONP = (function (document) { 522 | var requests = 0, 523 | callbacks = {}; 524 | 525 | return { 526 | /** 527 | * makes a JSONP request 528 | * 529 | * @param {String} src 530 | * @param {Object} data 531 | * @param {Function} callback 532 | */ 533 | get: function (src, data, callback) { 534 | // check if data was passed 535 | if (!arguments[2]) { 536 | callback = arguments[1]; 537 | data = {}; 538 | } 539 | 540 | // determine if there already are params 541 | src += (src.indexOf('?') + 1 ? '&' : '?'); 542 | 543 | var head = document.getElementsByTagName('head')[0], 544 | script = document.createElement('script'), 545 | params = [], 546 | requestId = requests, 547 | param; 548 | 549 | // increment the requests 550 | requests++; 551 | 552 | // create external callback name 553 | data.callback = 'JSONP.callbacks.request_' + requestId; 554 | 555 | // set callback function 556 | callbacks['request_' + requestId] = function (data) { 557 | // clean up 558 | head.removeChild(script); 559 | delete callbacks['request_' + requestId]; 560 | 561 | // fire callback 562 | callback(data); 563 | }; 564 | 565 | // traverse data 566 | for (param in data) { 567 | params.push(param + '=' + encodeURIComponent(data[param])); 568 | } 569 | 570 | // generate params 571 | src += params.join('&'); 572 | 573 | // set script attributes 574 | script.type = 'text/javascript'; 575 | script.src = src; 576 | 577 | // add to the DOM 578 | head.appendChild(script); 579 | }, 580 | 581 | /** 582 | * keeps a public reference of the callbacks object 583 | */ 584 | callbacks: callbacks 585 | }; 586 | })(document); --------------------------------------------------------------------------------