Skip to content

Instantly share code, notes, and snippets.

@leonderijke
Last active January 19, 2023 15:18
Show Gist options
  • Save leonderijke/525f8228fd1a1ce773e4 to your computer and use it in GitHub Desktop.
Save leonderijke/525f8228fd1a1ce773e4 to your computer and use it in GitHub Desktop.
Front Export: Little export script for exporting all conversations in a Front App inbox

Front export

✋ Heads up! This code uses the Front API V1, which is deprecated. @niklasravnsborg took this project further and created a Front API V2 compatible version: https://github.com/niklasravnsborg/front-export 🎉

Little export script for exporting all conversations in a Front inbox, using the Front API.

When using the awesome Front App, you want to export all conversations in an inbox. For example, for backup purposes.

Three environment variables are needed:

With these environment variables in place, run the script:

$ npm start

Disclaimer

Use at your own risk, no guarantees, don't try this at home, etc. etc.

'use strict';
const fs = require('fs');
const axios = require('axios');
const debug = require('debug')('front');
const delay = require('delay');
const FRONT_APP_ID = process.env.FRONT_APP_ID || '';
const FRONT_API_SECRET = process.env.FRONT_API_SECRET || '';
const FRONT_INBOX_ID = process.env.FRONT_INBOX_ID || '';
// Log all requests to the console if debug is enabled
axios.interceptors.request.use(config => {
debug(`Request: ${config.url}`);
return config;
});
/**
* Account for API rate limiting.
* http://docs.frontapp.com/docs/public-api#rate-limiting
*
* Will delay based on the Retry-After header and then retry. Unfortunately,
* this won't cancel any subsequent/parallel requests.
*/
axios.interceptors.response.use(null, err => {
if (err.status === 429 && err.headers['retry-after']) {
const ms = err.headers['retry-after'] * 1000;
debug(`Delaying because of rate limiting: ${err.headers['retry-after']} seconds`);
return delay(ms).then(() => {
return axios(err.config);
});
}
throw err;
});
/**
* Performs a request to the Front API.
*
* @param {String} url Relative or absolute URL. If relative, the base URL will be prepended
* @return {Promise}
*/
function performRequest(url) {
return axios
.get(url, {
// http://docs.frontapp.com/docs/public-api#target
baseURL: `https://api.frontapp.com/companies/${FRONT_APP_ID}`,
// http://docs.frontapp.com/docs/public-api#authentication
auth: {
username: FRONT_APP_ID,
password: FRONT_API_SECRET
},
params: {
pageSize: 1000
}
});
}
/**
* Writes the given contents to a file with the given filename.
*
* @param {String} filename
* @param {String} contents
* @return void
*/
function writeToFile(filename, contents) {
fs.writeFile(filename, contents, (err) => {
if (err) {
console.error(err);
}
debug(`Written: ${filename}`);
})
}
/**
* Retrieves all conversations for a given inbox.
* http://docs.frontapp.com/docs/inbox-conversations
*
* @param {String} inboxId
* @return {Promise}
*/
function getConversationsForInbox(inboxId) {
// http://docs.frontapp.com/v1.0/docs/pagination
const url = `/inboxes/${inboxId}/conversations/all`;
let conversations = [];
function handleResponse(res) {
if (res.data.conversations) {
conversations = conversations.concat(res.data.conversations);
}
if (res.data.pages.next_url) {
return performRequest(res.data.pages.next_url).then(handleResponse);
}
}
return performRequest(url)
.then(handleResponse)
.then(() => conversations);
}
/**
* Retrieves all data for a given conversation.
* http://docs.frontapp.com/docs/get-conversation
*
* Please note that the messages are paginated. We set the default pageSize to
* 1000 (maximum allowed). If you have conversations with more than 1000 messages,
* you need to adapt this script for message pagination.
*
* This endpoint doesn't have a `pages` object with pagination information, so
* you'd have to figure it out yourself by checking the length of the `messages`
* array and making additional requests (with the `page=n` param) if necessary.
*
* @param {Object} conversation
* @return {Promise}
*/
function getConversation(conversation) {
return performRequest(conversation.url).then(res => res.data);
}
/**
* Retrieves all data for a given message.
* http://docs.frontapp.com/docs/get-message
*
* @param {Object} message
* @return {Promise}
*/
function getMessage(message) {
return performRequest(message.url).then(res => res.data);
}
/**
* Retrieves all messages for a given conversation. Will update the `messages`
* key of the conversation with the retrieved messages.
*
* @param {Object} conversation
* @return {Promise}
*/
function getMessagesForConversation(conversation) {
return axios.all(conversation.messages.map(getMessage))
.then(messages => {
conversation.messages = messages;
return conversation;
});
}
console.time('export');
new Promise((resolve, reject) => {
if (!FRONT_INBOX_ID) {
reject(new Error('no FRONT_INBOX_ID specified'));
}
resolve(FRONT_INBOX_ID);
})
.then(getConversationsForInbox)
.then(conversations => {
return axios.all(conversations.map(getConversation))
})
.then(conversations => {
return axios.all(conversations.map(getMessagesForConversation))
})
.then(conversations => {
writeToFile(`${FRONT_INBOX_ID}.json`, JSON.stringify(conversations, null, 4));
console.timeEnd('export');
})
.catch(err => {
console.error(err);
});
{
"name": "front-export",
"version": "0.1.0",
"description": "Little export script for exporting all conversations in a Front inbox",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "node index.js"
},
"keywords": [],
"author": "Leon de Rijke",
"license": "MIT",
"dependencies": {
"axios": "^0.9.1",
"debug": "^2.2.0",
"delay": "^1.3.1"
},
"private": true
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment