Last active
September 18, 2017 17:19
-
-
Save ElectricImpSampleCode/1d958fef70e11b6dd1eeb6193c03210b to your computer and use it in GitHub Desktop.
impCentral API Example Code: Working with Access Tokens
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// CONSTANTS | |
// Replace the 'USERNAME' and 'PASSWORD' values with your own | |
const USERNAME = '...' | |
const PASSWORD = '...' | |
const API_URL = 'api.electricimp.com' | |
const API_VER = '/v5/' | |
const FILE_NAME = '.impCentralData' | |
// GLOBALS | |
var https = require('https'); | |
var fs = require('fs'); | |
var products = []; | |
var accessToken = null; | |
var expiryDate = null; | |
var refreshToken = null; | |
// FUNCTIONS | |
function setLoginOptions() { | |
// Returns an HTTPS request options object primed to get your access token | |
return { | |
hostname: API_URL, | |
path: API_VER + 'auth', | |
method: 'POST', | |
headers: { | |
'Content-Type': 'application/json' | |
} | |
}; | |
} | |
function setTokenUpdateOptions(token) { | |
// Returns an HTTPS request options object primed to refresh your access token | |
return { | |
hostname: API_URL, | |
path: API_VER + 'auth/token', | |
method: 'POST', | |
headers: { | |
'Content-Type': 'application/json' | |
} | |
}; | |
} | |
function setOptions(verb, path, token) { | |
// Returns an HTTPS request options object primed for API usage | |
return { | |
hostname: API_URL, | |
path: API_VER + path, | |
method: verb, | |
headers: { | |
'Content-Type': 'application/vnd.api+json', | |
'Authorization': 'Bearer ' + token | |
} | |
}; | |
} | |
function showError(resp) { | |
console.log(`STATUS: ${resp.statusCode}`); | |
console.log(`HEADERS: ${JSON.stringify(resp.headers)}`); | |
} | |
function login(cb = null) { | |
// Login to the server - ie. get the initial access token | |
let req = https.request(setLoginOptions(), (resp) => { | |
// Construct the returned response body | |
let body = ''; | |
resp.setEncoding('utf8'); | |
resp.on('data', (chunk) => { body += chunk; }); | |
// Code that's called when the body is retrieved | |
resp.on('end', () => { | |
if (body.length > 0) { | |
try { | |
// Is the returned data valid JSON? | |
const data = JSON.parse(body); | |
if (resp.statusCode === 200) { | |
// We have the new access token and other credentials | |
accessToken = data.access_token; | |
expiryDate = data.expires_at; | |
refreshToken = data.refresh_token; | |
// Save the credentials locally | |
writeData(); | |
// Call the passed in function | |
if (cb) checkAccessToken(cb); | |
} else { | |
// API Error | |
console.log('API ERROR: ' + data.code + ' (' + data.message + ')'); | |
} | |
} catch (err) { | |
// JSON error | |
console.error(err.message); | |
} | |
} else { | |
// HTTP Error | |
showError(resp); | |
} | |
}); | |
}); | |
// Error callback | |
req.on('error', (err) => { console.error(`REQUEST ERROR: ${err.message}`); }); | |
// Begin by setting credentials as request body | |
req.write(JSON.stringify({ | |
'id': USERNAME, | |
'password': PASSWORD | |
})); | |
// Send the request | |
req.end(); | |
} | |
function checkAccessToken(cb = null) { | |
if (accessToken === null) { | |
// Don't have the token, so load it | |
console.log('We don\'t have an access token - trying local file'); | |
fs.readFile(FILE_NAME, {'encoding': 'utf8', 'flag': 'a+'}, (err, data) => { | |
if (err) return console.error(err); | |
if (data !== null && data.length > 0) { | |
try { | |
let fdata = JSON.parse(data); | |
if ('at' in fdata) { | |
accessToken = fdata.at; | |
refreshToken = fdata.rt; | |
expiryDate = fdata.ed; | |
console.log('Read in access token'); | |
checkAccessToken(cb); | |
} else { | |
console.log('No locally stored access token - getting a new one'); | |
login(cb); | |
} | |
} catch (e) { | |
console.error(e); | |
} | |
} else { | |
console.log('No locally stored access token - getting a new one'); | |
login(cb); | |
} | |
}); | |
} else { | |
console.log('We have an access token - checking it'); | |
let expiry = new Date(expiryDate); | |
let now = new Date(); | |
if (expiry < now) { | |
// Access token expired | |
console.log('Access Token Expired - updating...'); | |
let req = https.request(setTokenUpdateOptions(), (resp) => { | |
// Construct the returned response body | |
let body = ''; | |
resp.setEncoding('utf8'); | |
resp.on('data', (chunk) => { body += chunk; }); | |
// Code that's called when the body is retrieved | |
resp.on('end', () => { | |
if (body.length > 0) { | |
try { | |
// Is the returned data valid JSON? | |
const data = JSON.parse(body); | |
if (resp.statusCode < 400) { | |
// Success - retain the new token and expiry info | |
accessToken = data.access_token; | |
expiryDate = data.expires_at; | |
// Store the data locally | |
writeData(); | |
// Call the passed in function | |
if (cb) cb(); | |
} else { | |
// API Error | |
console.error('API ERROR: ' + data.code + ' (' + data.message + ')'); | |
} | |
} catch (err) { | |
// JSON error | |
console.error(err.message); | |
} | |
} else { | |
// HTTP Error | |
showError(resp); | |
} | |
}); | |
}); | |
// Error callback | |
req.on('error', (err) => { console.error(`REQUEST ERROR: ${err.message}`); }); | |
req.write(JSON.stringify({ | |
'token': refreshToken | |
})); | |
// Send the request | |
req.end(); | |
} else { | |
// Access token is good - use it | |
console.log("Access Token OK - ready to access impCentral"); | |
if (cb) cb(); | |
} | |
} | |
} | |
function writeData() { | |
// Write the access token data | |
let data = {}; | |
data.at = accessToken; | |
data.rt = refreshToken; | |
data.ed = expiryDate; | |
fs.writeFile(FILE_NAME, JSON.stringify(data), (err) => { | |
if (err) return console.error(err); | |
console.log("Access Token acquired, written to local storage"); | |
}); | |
} | |
// RUNTIME | |
checkAccessToken(() => { | |
// Create a request to get the account's products | |
let req = https.request(setOptions('GET', 'products', accessToken), (resp) => { | |
let body = ''; | |
resp.setEncoding('utf8'); | |
resp.on('data', (chunk) => { body += chunk; }); | |
resp.on('end', () => { | |
if (body.length > 0) { | |
try { | |
let data = JSON.parse(body); | |
data = data.data; | |
if (resp.statusCode === 200) { | |
// 'data' is an array of product objects | |
for (let item of data) { | |
let product = {}; | |
product.id = item.id; | |
product.name = item.attributes.name; | |
product.devicegroups = []; | |
products.push(product); | |
} | |
console.log(`You have ${products.length} product(s) in your account:`); | |
let tabs = 0; | |
for (let product of products) { | |
if (product.name.length > tabs) { | |
tabs = product.name.length; | |
} | |
} | |
let pcount = 0; | |
for (let product of products) { | |
let sp = " ".substring(0, tabs - product.name.length + 1); | |
console.log(` ${pcount + 1}. ${product.name}${sp}(ID: ${product.id})`); | |
pcount += 1; | |
} | |
} else { | |
// API Error | |
console.log('API ERROR: ' + data.code + ' (' + data.message + ')'); | |
} | |
} catch (err) { | |
// JSON Error | |
console.error(err.message); | |
} | |
} else { | |
// HTTP Error | |
showError(resp); | |
} | |
}); | |
}); | |
// Error callback | |
req.on('error', (err) => { console.error(`REQUEST ERROR: ${err.message}`); }); | |
// Send the request | |
req.end(); | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment