├── .gitignore ├── LICENSE ├── README.md ├── lib └── index.js └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 EmilTholin 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # google-api-batch-utils 2 | Utility functions for creating request bodies and parsing batch responses for Google's REST APIs. 3 | 4 | ## Example usage 5 | 6 | List the latest three messages in a user's inbox, and then get a snippet of each message 7 | in a batch request to the Gmail API: 8 | 9 | ```js 10 | var rp = require('request-promise'); 11 | var batchUtils = require('google-api-batch-utils'); 12 | var createBatchBody = batchUtils.createBatchBody; 13 | var parseBatchResponse = batchUtils.parseBatchResponse; 14 | 15 | var BOUNDARY = 'example_boundary'; 16 | 17 | rp({ 18 | uri: 'https://www.googleapis.com/gmail/v1/users/me/messages', 19 | qs: { maxResults: 3 , fields: 'messages(id)'}, 20 | headers: { Authorization: 'Bearer {API_KEY}'}, 21 | json: true 22 | }).then(function(response) { 23 | var uris = response.messages.map(function(item) { 24 | return {uri: '/gmail/v1/users/me/messages/' + item.id, qs: { fields: 'snippet'}}; 25 | }); 26 | 27 | var batchBody = createBatchBody(uris, BOUNDARY); 28 | return rp({ 29 | method: 'POST', 30 | uri: 'https://www.googleapis.com/batch', 31 | headers: { 32 | Authorization: 'Bearer {API_KEY}' , 33 | 'Content-Type': 'multipart/mixed; boundary="' + BOUNDARY + '"' 34 | }, 35 | body: batchBody 36 | }); 37 | }).then(parseBatchResponse) 38 | .then(console.log.bind(console)); 39 | // => 40 | // [ 41 | // { snippet: 'Numberphile has uploaded The iPhone of Slide Rules - Numberphile Thanks Audible: http://www....' }, 42 | // { snippet: 'Feel the bern' }, 43 | // { snippet: 'See what is new with your LinkedIn connections...' } 44 | // ] 45 | 46 | ``` 47 | 48 | ## API 49 | 50 | 51 | ```js 52 | /** 53 | * Takes an array of API call objects and generates a string that can be used 54 | * as the body in a call to Google batch API. 55 | * @param {object[]} apiCalls 56 | * @param {string} apiCalls[].uri - Uri of the API call. 57 | * @param {string} apiCalls[].[method] - Optional HTTP method. Defaults to GET. 58 | * @param {object} apiCalls[].[qs] - Optional object with querystring parameters. 59 | * @param {string} apiCalls[].[body] - Optional request body string. 60 | * @param {string} boundary - String that delimits the calls. 61 | * @return {string} 62 | */ 63 | createBatchBody(apiCalls, boundary); 64 | 65 | /** 66 | * Parses a raw string response from the Google batch API into objects. 67 | * @param {string} response 68 | * @return {object[]} 69 | */ 70 | parseBatchResponse(response); 71 | ``` 72 | 73 | ## Licence 74 | MIT 75 | -------------------------------------------------------------------------------- /lib/index.js: -------------------------------------------------------------------------------- 1 | var querystring = require('querystring'); 2 | 3 | function parsePart(part) { 4 | var p = part.substring(part.indexOf("{"), part.lastIndexOf("}") + 1); 5 | return JSON.parse(p); 6 | } 7 | 8 | module.exports = { 9 | /** 10 | * Takes an array of API call objects and generates a string that can be used 11 | * as the body in a call to Google batch API. 12 | * @param {object[]} apiCalls 13 | * @param {string} apiCalls[].uri - Uri of the API call. 14 | * @param {string} apiCalls[].[method] - Optional HTTP method. Defaults to GET. 15 | * @param {object} apiCalls[].[qs] - Optional object with querystring parameters. 16 | * @param {string} apiCalls[].[body] - Optional request body string. 17 | * @param {string} boundary - String that delimits the calls. 18 | * @return {string} 19 | */ 20 | createBatchBody: function(apiCalls, boundary) { 21 | var batchBody = []; 22 | 23 | apiCalls.forEach(function(call) { 24 | var method = call.method || 'GET'; 25 | var uri = call.uri; 26 | if (call.qs) { 27 | uri += '?' + querystring.stringify(call.qs); 28 | } 29 | var body = '\r\n'; 30 | if (call.body) { 31 | body = [ 32 | 'Content-Type: application/json', '\r\n\r\n', 33 | 34 | JSON.stringify(call.body), '\r\n' 35 | ].join(''); 36 | } 37 | 38 | batchBody = batchBody.concat([ 39 | '--', boundary, '\r\n', 40 | 'Content-Type: application/http', '\r\n\r\n', 41 | 42 | method, ' ', uri, '\r\n', 43 | body 44 | ]); 45 | }); 46 | 47 | return batchBody.concat(['--', boundary, '--']).join(''); 48 | }, 49 | 50 | /** 51 | * Parses a raw string response from the Google batch API into objects. 52 | * @param {string} response 53 | * @return {object[]} 54 | */ 55 | parseBatchResponse: function(response) { 56 | // Not the same delimiter in the response as was specified in the request, 57 | // so we have to extract it. 58 | var delimiter = response.substr(0, response.indexOf('\r\n')); 59 | var parts = response.split(delimiter); 60 | // The first part will always be an empty string. Just remove it. 61 | parts.shift(); 62 | // The last part will be the "--". Just remove it. 63 | parts.pop(); 64 | 65 | var result = []; 66 | for (var i = 0; i < parts.length; i++) { 67 | var part = parts[i]; 68 | try { 69 | result.push(parsePart(part)); 70 | } catch (e) { 71 | // A Google API error will contain a JSON response with an array 'errors'. 72 | // If the parsing should fail, we mimic this. 73 | result.push({ errors: [{ message: part }] }); 74 | } 75 | } 76 | 77 | return result; 78 | } 79 | }; 80 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "google-api-batch-utils", 3 | "version": "1.0.1", 4 | "description": "Utility functions for creating request bodies and parsing batch responses for Google's REST APIs", 5 | "main": "lib", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "Tholle ", 10 | "license": "MIT", 11 | "repository": "EmilTholin/google-api-batch-utils", 12 | "dependencies": { 13 | "querystring": "^0.2.0" 14 | } 15 | } 16 | --------------------------------------------------------------------------------