From 9523890b65259f62e493e10312e61dc20fc10f78 Mon Sep 17 00:00:00 2001
From: bill bittner <bittner.w@gmail.com>
Date: Thu, 29 Mar 2018 11:24:52 -0700
Subject: [PATCH] fixed api and assets routes

---
 server/helpers/multipartMiddleware.js         |   5 +
 server/routes/api/channelAvailability.js      |  22 ++--
 server/routes/api/channelClaims.js            |  32 +++---
 server/routes/api/channelData.js              |  30 +++--
 server/routes/api/channelShortId.js           |  19 ++--
 server/routes/api/claimAvailability.js        |  22 ++--
 server/routes/api/claimData.js                |  31 +++---
 server/routes/api/claimGet.js                 |  51 +++++----
 server/routes/api/claimList.js                |  18 ++-
 server/routes/api/claimLongId.js              |  38 +++----
 server/routes/api/claimPublish.js             | 104 +++++++++---------
 server/routes/api/claimResolve.js             |  18 ++-
 server/routes/api/claimShortId.js             |  19 ++--
 server/routes/api/fileAvailability.js         |  42 ++++---
 server/routes/api/index.js                    |  33 +++---
 server/routes/asset/serveAssetByClaim.js      |  44 --------
 .../asset/serveAssetByIdentifierAndClaim.js   |  55 ---------
 server/routes/{asset => assets}/index.js      |   7 +-
 server/routes/assets/serveAssetByClaim.js     |  42 +++++++
 .../assets/serveAssetByIdentifierAndClaim.js  |  58 ++++++++++
 server/routes/{page => pages}/index.js        |   0
 server/routes/{page => pages}/redirect.js     |   0
 .../routes/{page => pages}/sendEmbedPage.js   |   0
 server/routes/{page => pages}/sendReactApp.js |   0
 server/server.js                              |  98 +++++++++++++++++
 speech.js                                     |   4 +-
 26 files changed, 439 insertions(+), 353 deletions(-)
 create mode 100644 server/helpers/multipartMiddleware.js
 delete mode 100644 server/routes/asset/serveAssetByClaim.js
 delete mode 100644 server/routes/asset/serveAssetByIdentifierAndClaim.js
 rename server/routes/{asset => assets}/index.js (51%)
 create mode 100644 server/routes/assets/serveAssetByClaim.js
 create mode 100644 server/routes/assets/serveAssetByIdentifierAndClaim.js
 rename server/routes/{page => pages}/index.js (100%)
 rename server/routes/{page => pages}/redirect.js (100%)
 rename server/routes/{page => pages}/sendEmbedPage.js (100%)
 rename server/routes/{page => pages}/sendReactApp.js (100%)
 create mode 100644 server/server.js

diff --git a/server/helpers/multipartMiddleware.js b/server/helpers/multipartMiddleware.js
new file mode 100644
index 00000000..c483754b
--- /dev/null
+++ b/server/helpers/multipartMiddleware.js
@@ -0,0 +1,5 @@
+const multipart = require('connect-multiparty');
+const { publishing: { uploadDirectory } } = require('siteConfig.js');
+const multipartMiddleware = multipart({uploadDir: uploadDirectory});
+
+module.exports = multipartMiddleware;
diff --git a/server/routes/api/channelAvailability.js b/server/routes/api/channelAvailability.js
index d008b445..128aff44 100644
--- a/server/routes/api/channelAvailability.js
+++ b/server/routes/api/channelAvailability.js
@@ -8,18 +8,16 @@ const { handleErrorResponse } = require('helpers/errorHandlers.js');
 
 */
 
-const channelAvailability = () => {
-  return ({ ip, originalUrl, params: { name } }, res) => {
-    const gaStartTime = Date.now();
-    checkChannelAvailability(name)
-      .then(availableName => {
-        res.status(200).json(availableName);
-        sendGATimingEvent('end-to-end', 'claim name availability', name, gaStartTime, Date.now());
-      })
-      .catch(error => {
-        handleErrorResponse(originalUrl, ip, error, res);
-      });
-  };
+const channelAvailability = ({ ip, originalUrl, params: { name } }, res) => {
+  const gaStartTime = Date.now();
+  checkChannelAvailability(name)
+    .then(availableName => {
+      res.status(200).json(availableName);
+      sendGATimingEvent('end-to-end', 'claim name availability', name, gaStartTime, Date.now());
+    })
+    .catch(error => {
+      handleErrorResponse(originalUrl, ip, error, res);
+    });
 };
 
 module.exports = channelAvailability;
diff --git a/server/routes/api/channelClaims.js b/server/routes/api/channelClaims.js
index 84c44442..8f99a148 100644
--- a/server/routes/api/channelClaims.js
+++ b/server/routes/api/channelClaims.js
@@ -9,23 +9,21 @@ const NO_CHANNEL = 'NO_CHANNEL';
 
 */
 
-const channelClaims = () => {
-  return ({ ip, originalUrl, body, params }, res) => {
-    const channelName = params.channelName;
-    let channelClaimId = params.channelClaimId;
-    if (channelClaimId === 'none') channelClaimId = null;
-    const page = params.page;
-    getChannelClaims(channelName, channelClaimId, page)
-      .then(data => {
-        if (data === NO_CHANNEL) {
-          return res.status(404).json({success: false, message: 'No matching channel was found'});
-        }
-        res.status(200).json({success: true, data});
-      })
-      .catch(error => {
-        handleErrorResponse(originalUrl, ip, error, res);
-      });
-  };
+const channelClaims = ({ ip, originalUrl, body, params }, res) => {
+  const channelName = params.channelName;
+  let channelClaimId = params.channelClaimId;
+  if (channelClaimId === 'none') channelClaimId = null;
+  const page = params.page;
+  getChannelClaims(channelName, channelClaimId, page)
+    .then(data => {
+      if (data === NO_CHANNEL) {
+        return res.status(404).json({success: false, message: 'No matching channel was found'});
+      }
+      res.status(200).json({success: true, data});
+    })
+    .catch(error => {
+      handleErrorResponse(originalUrl, ip, error, res);
+    });
 };
 
 module.exports = channelClaims;
diff --git a/server/routes/api/channelData.js b/server/routes/api/channelData.js
index 5ce66b48..d6a3f026 100644
--- a/server/routes/api/channelData.js
+++ b/server/routes/api/channelData.js
@@ -9,22 +9,20 @@ const NO_CHANNEL = 'NO_CHANNEL';
 
 */
 
-const channelData = () => {
-  return ({ ip, originalUrl, body, params }, res) => {
-    const channelName = params.channelName;
-    let channelClaimId = params.channelClaimId;
-    if (channelClaimId === 'none') channelClaimId = null;
-    getChannelData(channelName, channelClaimId, 0)
-      .then(data => {
-        if (data === NO_CHANNEL) {
-          return res.status(404).json({success: false, message: 'No matching channel was found'});
-        }
-        res.status(200).json({success: true, data});
-      })
-      .catch(error => {
-        handleErrorResponse(originalUrl, ip, error, res);
-      });
-  };
+const channelData = ({ ip, originalUrl, body, params }, res) => {
+  const channelName = params.channelName;
+  let channelClaimId = params.channelClaimId;
+  if (channelClaimId === 'none') channelClaimId = null;
+  getChannelData(channelName, channelClaimId, 0)
+    .then(data => {
+      if (data === NO_CHANNEL) {
+        return res.status(404).json({success: false, message: 'No matching channel was found'});
+      }
+      res.status(200).json({success: true, data});
+    })
+    .catch(error => {
+      handleErrorResponse(originalUrl, ip, error, res);
+    });
 };
 
 module.exports = channelData;
diff --git a/server/routes/api/channelShortId.js b/server/routes/api/channelShortId.js
index 15b4e655..0e6b17ec 100644
--- a/server/routes/api/channelShortId.js
+++ b/server/routes/api/channelShortId.js
@@ -1,4 +1,5 @@
 const { handleErrorResponse } = require('helpers/errorHandlers.js');
+const db = require('models');
 
 /*
 
@@ -6,16 +7,14 @@ route to get a short channel id from long channel Id
 
 */
 
-const channelShortIdRoute = (db) => {
-  return ({ ip, originalUrl, params }, res) => {
-    db.Certificate.getShortChannelIdFromLongChannelId(params.longId, params.name)
-      .then(shortId => {
-        res.status(200).json(shortId);
-      })
-      .catch(error => {
-        handleErrorResponse(originalUrl, ip, error, res);
-      });
-  };
+const channelShortIdRoute = ({ ip, originalUrl, params }, res) => {
+  db.Certificate.getShortChannelIdFromLongChannelId(params.longId, params.name)
+    .then(shortId => {
+      res.status(200).json(shortId);
+    })
+    .catch(error => {
+      handleErrorResponse(originalUrl, ip, error, res);
+    });
 };
 
 module.exports = channelShortIdRoute;
diff --git a/server/routes/api/claimAvailability.js b/server/routes/api/claimAvailability.js
index 82e76af5..5138d1d7 100644
--- a/server/routes/api/claimAvailability.js
+++ b/server/routes/api/claimAvailability.js
@@ -8,18 +8,16 @@ const { handleErrorResponse } = require('helpers/errorHandlers.js');
 
 */
 
-const claimAvailability = () => {
-  return ({ ip, originalUrl, params: { name } }, res) => {
-    const gaStartTime = Date.now();
-    claimNameIsAvailable(name)
-      .then(result => {
-        res.status(200).json(result);
-        sendGATimingEvent('end-to-end', 'claim name availability', name, gaStartTime, Date.now());
-      })
-      .catch(error => {
-        handleErrorResponse(originalUrl, ip, error, res);
-      });
-  };
+const claimAvailability = ({ ip, originalUrl, params: { name } }, res) => {
+  const gaStartTime = Date.now();
+  claimNameIsAvailable(name)
+    .then(result => {
+      res.status(200).json(result);
+      sendGATimingEvent('end-to-end', 'claim name availability', name, gaStartTime, Date.now());
+    })
+    .catch(error => {
+      handleErrorResponse(originalUrl, ip, error, res);
+    });
 };
 
 module.exports = claimAvailability;
diff --git a/server/routes/api/claimData.js b/server/routes/api/claimData.js
index 0d307faa..d8b6c448 100644
--- a/server/routes/api/claimData.js
+++ b/server/routes/api/claimData.js
@@ -1,4 +1,5 @@
 const { handleErrorResponse } = require('helpers/errorHandlers.js');
+const db = require('models');
 
 /*
 
@@ -6,22 +7,20 @@ const { handleErrorResponse } = require('helpers/errorHandlers.js');
 
 */
 
-const claimData = (db) => {
-  return ({ ip, originalUrl, body, params }, res) => {
-    const claimName = params.claimName;
-    let claimId = params.claimId;
-    if (claimId === 'none') claimId = null;
-    db.Claim.resolveClaim(claimName, claimId)
-      .then(claimInfo => {
-        if (!claimInfo) {
-          return res.status(404).json({success: false, message: 'No claim could be found'});
-        }
-        res.status(200).json({success: true, data: claimInfo});
-      })
-      .catch(error => {
-        handleErrorResponse(originalUrl, ip, error, res);
-      });
-  };
+const claimData = ({ ip, originalUrl, body, params }, res) => {
+  const claimName = params.claimName;
+  let claimId = params.claimId;
+  if (claimId === 'none') claimId = null;
+  db.Claim.resolveClaim(claimName, claimId)
+    .then(claimInfo => {
+      if (!claimInfo) {
+        return res.status(404).json({success: false, message: 'No claim could be found'});
+      }
+      res.status(200).json({success: true, data: claimInfo});
+    })
+    .catch(error => {
+      handleErrorResponse(originalUrl, ip, error, res);
+    });
 };
 
 module.exports = claimData;
diff --git a/server/routes/api/claimGet.js b/server/routes/api/claimGet.js
index 1fbfafe2..0d066140 100644
--- a/server/routes/api/claimGet.js
+++ b/server/routes/api/claimGet.js
@@ -1,6 +1,7 @@
 const { getClaim } = require('helpers/lbryApi.js');
 const { addGetResultsToFileData, createFileData } = require('../../helpers/publishHelpers.js');
 const { handleErrorResponse } = require('helpers/errorHandlers.js');
+const db = require('models');
 
 /*
 
@@ -8,32 +9,30 @@ const { handleErrorResponse } = require('helpers/errorHandlers.js');
 
 */
 
-const claimGet = (db) => {
-  return ({ ip, originalUrl, params }, res) => {
-    const name = params.name;
-    const claimId = params.claimId;
-    // resolve the claim
-    db.Claim.resolveClaim(name, claimId)
-      .then(resolveResult => {
-        // make sure a claim actually exists at that uri
-        if (!resolveResult) {
-          throw new Error('No matching uri found in Claim table');
-        }
-        let fileData = createFileData(resolveResult);
-        // get the claim
-        return Promise.all([fileData, getClaim(`${name}#${claimId}`)]);
-      })
-      .then(([ fileData, getResult ]) => {
-        fileData = addGetResultsToFileData(fileData, getResult);
-        return Promise.all([db.upsert(db.File, fileData, {name, claimId}, 'File'), getResult]);
-      })
-      .then(([ fileRecord, {message, completed} ]) => {
-        res.status(200).json({ success: true, message, completed });
-      })
-      .catch(error => {
-        handleErrorResponse(originalUrl, ip, error, res);
-      });
-  };
+const claimGet = ({ ip, originalUrl, params }, res) => {
+  const name = params.name;
+  const claimId = params.claimId;
+  // resolve the claim
+  db.Claim.resolveClaim(name, claimId)
+    .then(resolveResult => {
+      // make sure a claim actually exists at that uri
+      if (!resolveResult) {
+        throw new Error('No matching uri found in Claim table');
+      }
+      let fileData = createFileData(resolveResult);
+      // get the claim
+      return Promise.all([fileData, getClaim(`${name}#${claimId}`)]);
+    })
+    .then(([ fileData, getResult ]) => {
+      fileData = addGetResultsToFileData(fileData, getResult);
+      return Promise.all([db.upsert(db.File, fileData, {name, claimId}, 'File'), getResult]);
+    })
+    .then(([ fileRecord, {message, completed} ]) => {
+      res.status(200).json({ success: true, message, completed });
+    })
+    .catch(error => {
+      handleErrorResponse(originalUrl, ip, error, res);
+    });
 };
 
 module.exports = claimGet;
diff --git a/server/routes/api/claimList.js b/server/routes/api/claimList.js
index fc1d124a..6cd7a349 100644
--- a/server/routes/api/claimList.js
+++ b/server/routes/api/claimList.js
@@ -7,16 +7,14 @@ const { handleErrorResponse } = require('helpers/errorHandlers.js');
 
 */
 
-const claimList = (db) => {
-  return ({ ip, originalUrl, params }, res) => {
-    getClaimList(params.name)
-      .then(claimsList => {
-        res.status(200).json(claimsList);
-      })
-      .catch(error => {
-        handleErrorResponse(originalUrl, ip, error, res);
-      });
-  };
+const claimList = ({ ip, originalUrl, params }, res) => {
+  getClaimList(params.name)
+    .then(claimsList => {
+      res.status(200).json(claimsList);
+    })
+    .catch(error => {
+      handleErrorResponse(originalUrl, ip, error, res);
+    });
 };
 
 module.exports = claimList;
diff --git a/server/routes/api/claimLongId.js b/server/routes/api/claimLongId.js
index a4caebc2..98e80770 100644
--- a/server/routes/api/claimLongId.js
+++ b/server/routes/api/claimLongId.js
@@ -10,26 +10,24 @@ const NO_CLAIM = 'NO_CLAIM';
 
 */
 
-const claimLongId = () => {
-  return ({ ip, originalUrl, body, params }, res) => {
-    const channelName = body.channelName;
-    const channelClaimId = body.channelClaimId;
-    const claimName = body.claimName;
-    const claimId = body.claimId;
-    getClaimId(channelName, channelClaimId, claimName, claimId)
-      .then(result => {
-        if (result === NO_CHANNEL) {
-          return res.status(404).json({success: false, message: 'No matching channel could be found'});
-        }
-        if (result === NO_CLAIM) {
-          return res.status(404).json({success: false, message: 'No matching claim id could be found'});
-        }
-        res.status(200).json({success: true, data: result});
-      })
-      .catch(error => {
-        handleErrorResponse(originalUrl, ip, error, res);
-      });
-  };
+const claimLongId = ({ ip, originalUrl, body, params }, res) => {
+  const channelName = body.channelName;
+  const channelClaimId = body.channelClaimId;
+  const claimName = body.claimName;
+  const claimId = body.claimId;
+  getClaimId(channelName, channelClaimId, claimName, claimId)
+    .then(result => {
+      if (result === NO_CHANNEL) {
+        return res.status(404).json({success: false, message: 'No matching channel could be found'});
+      }
+      if (result === NO_CLAIM) {
+        return res.status(404).json({success: false, message: 'No matching claim id could be found'});
+      }
+      res.status(200).json({success: true, data: result});
+    })
+    .catch(error => {
+      handleErrorResponse(originalUrl, ip, error, res);
+    });
 };
 
 module.exports = claimLongId;
diff --git a/server/routes/api/claimPublish.js b/server/routes/api/claimPublish.js
index d5f4dff5..5d5b1e52 100644
--- a/server/routes/api/claimPublish.js
+++ b/server/routes/api/claimPublish.js
@@ -11,60 +11,58 @@ const { details: { host } } = require('siteConfig.js');
 
 */
 
-const claimPublish = (db) => {
-  return ({ body, files, headers, ip, originalUrl, user }, res) => {
-    // define variables
-    let  channelName, channelId, channelPassword, description, fileName, filePath, fileType, gaStartTime, license, name, nsfw, thumbnail, thumbnailFileName, thumbnailFilePath, thumbnailFileType, title;
-    // record the start time of the request
-    gaStartTime = Date.now();
-    // validate the body and files of the request
-    try {
-      // validateApiPublishRequest(body, files);
-      ({name, nsfw, license, title, description, thumbnail} = parsePublishApiRequestBody(body));
-      ({fileName, filePath, fileType, thumbnailFileName, thumbnailFilePath, thumbnailFileType} = parsePublishApiRequestFiles(files));
-      ({channelName, channelId, channelPassword} = body);
-    } catch (error) {
-      return res.status(400).json({success: false, message: error.message});
-    }
-    // check channel authorization
-    Promise
-      .all([
-        authenticateUser(channelName, channelId, channelPassword, user),
-        claimNameIsAvailable(name),
-        createBasicPublishParams(filePath, name, title, description, license, nsfw, thumbnail),
-        createThumbnailPublishParams(thumbnailFilePath, name, license, nsfw),
-      ])
-      .then(([{channelName, channelClaimId}, validatedClaimName, publishParams, thumbnailPublishParams]) => {
-        // add channel details to the publish params
-        if (channelName && channelClaimId) {
-          publishParams['channel_name'] = channelName;
-          publishParams['channel_id'] = channelClaimId;
-        }
-        // publish the thumbnail
-        if (thumbnailPublishParams) {
-          publish(thumbnailPublishParams, thumbnailFileName, thumbnailFileType);
-        }
-        // publish the asset
-        return publish(publishParams, fileName, fileType);
-      })
-      .then(result => {
-        res.status(200).json({
-          success: true,
-          message: 'publish completed successfully',
-          data   : {
-            name,
-            claimId: result.claim_id,
-            url    : `${host}/${result.claim_id}/${name}`,
-            lbryTx : result,
-          },
-        });
-        // record the publish end time and send to google analytics
-        sendGATimingEvent('end-to-end', 'publish', fileType, gaStartTime, Date.now());
-      })
-      .catch(error => {
-        handleErrorResponse(originalUrl, ip, error, res);
+const claimPublish = ({ body, files, headers, ip, originalUrl, user }, res) => {
+  // define variables
+  let  channelName, channelId, channelPassword, description, fileName, filePath, fileType, gaStartTime, license, name, nsfw, thumbnail, thumbnailFileName, thumbnailFilePath, thumbnailFileType, title;
+  // record the start time of the request
+  gaStartTime = Date.now();
+  // validate the body and files of the request
+  try {
+    // validateApiPublishRequest(body, files);
+    ({name, nsfw, license, title, description, thumbnail} = parsePublishApiRequestBody(body));
+    ({fileName, filePath, fileType, thumbnailFileName, thumbnailFilePath, thumbnailFileType} = parsePublishApiRequestFiles(files));
+    ({channelName, channelId, channelPassword} = body);
+  } catch (error) {
+    return res.status(400).json({success: false, message: error.message});
+  }
+  // check channel authorization
+  Promise
+    .all([
+      authenticateUser(channelName, channelId, channelPassword, user),
+      claimNameIsAvailable(name),
+      createBasicPublishParams(filePath, name, title, description, license, nsfw, thumbnail),
+      createThumbnailPublishParams(thumbnailFilePath, name, license, nsfw),
+    ])
+    .then(([{channelName, channelClaimId}, validatedClaimName, publishParams, thumbnailPublishParams]) => {
+      // add channel details to the publish params
+      if (channelName && channelClaimId) {
+        publishParams['channel_name'] = channelName;
+        publishParams['channel_id'] = channelClaimId;
+      }
+      // publish the thumbnail
+      if (thumbnailPublishParams) {
+        publish(thumbnailPublishParams, thumbnailFileName, thumbnailFileType);
+      }
+      // publish the asset
+      return publish(publishParams, fileName, fileType);
+    })
+    .then(result => {
+      res.status(200).json({
+        success: true,
+        message: 'publish completed successfully',
+        data   : {
+          name,
+          claimId: result.claim_id,
+          url    : `${host}/${result.claim_id}/${name}`,
+          lbryTx : result,
+        },
       });
-  };
+      // record the publish end time and send to google analytics
+      sendGATimingEvent('end-to-end', 'publish', fileType, gaStartTime, Date.now());
+    })
+    .catch(error => {
+      handleErrorResponse(originalUrl, ip, error, res);
+    });
 };
 
 module.exports = claimPublish;
diff --git a/server/routes/api/claimResolve.js b/server/routes/api/claimResolve.js
index 1b9cec12..5cf03b3f 100644
--- a/server/routes/api/claimResolve.js
+++ b/server/routes/api/claimResolve.js
@@ -7,16 +7,14 @@ const { handleErrorResponse } = require('helpers/errorHandlers.js');
 
 */
 
-const claimResolve = () => {
-  return ({ headers, ip, originalUrl, params }, res) => {
-    resolveUri(`${params.name}#${params.claimId}`)
-      .then(resolvedUri => {
-        res.status(200).json(resolvedUri);
-      })
-      .catch(error => {
-        handleErrorResponse(originalUrl, ip, error, res);
-      });
-  };
+const claimResolve = ({ headers, ip, originalUrl, params }, res) => {
+  resolveUri(`${params.name}#${params.claimId}`)
+    .then(resolvedUri => {
+      res.status(200).json(resolvedUri);
+    })
+    .catch(error => {
+      handleErrorResponse(originalUrl, ip, error, res);
+    });
 };
 
 module.exports = claimResolve;
diff --git a/server/routes/api/claimShortId.js b/server/routes/api/claimShortId.js
index e6983a78..a8a310d2 100644
--- a/server/routes/api/claimShortId.js
+++ b/server/routes/api/claimShortId.js
@@ -1,4 +1,5 @@
 const { handleErrorResponse } = require('helpers/errorHandlers.js');
+const db = require('models');
 
 /*
 
@@ -6,16 +7,14 @@ const { handleErrorResponse } = require('helpers/errorHandlers.js');
 
 */
 
-const claimShortId = (db) => {
-  return ({ ip, originalUrl, body, params }, res) => {
-    db.Claim.getShortClaimIdFromLongClaimId(params.longId, params.name)
-      .then(shortId => {
-        res.status(200).json({success: true, data: shortId});
-      })
-      .catch(error => {
-        handleErrorResponse(originalUrl, ip, error, res);
-      });
-  };
+const claimShortId = ({ ip, originalUrl, body, params }, res) => {
+  db.Claim.getShortClaimIdFromLongClaimId(params.longId, params.name)
+    .then(shortId => {
+      res.status(200).json({success: true, data: shortId});
+    })
+    .catch(error => {
+      handleErrorResponse(originalUrl, ip, error, res);
+    });
 };
 
 module.exports = claimShortId;
diff --git a/server/routes/api/fileAvailability.js b/server/routes/api/fileAvailability.js
index 11357f1a..650bdf6b 100644
--- a/server/routes/api/fileAvailability.js
+++ b/server/routes/api/fileAvailability.js
@@ -1,5 +1,5 @@
-
 const { handleErrorResponse } = require('helpers/errorHandlers.js');
+const db = require('models');
 
 /*
 
@@ -7,27 +7,25 @@ const { handleErrorResponse } = require('helpers/errorHandlers.js');
 
 */
 
-const fileAvailability = (db) => {
-  return ({ ip, originalUrl, params }, res) => {
-    const name = params.name;
-    const claimId = params.claimId;
-    db.File
-      .findOne({
-        where: {
-          name,
-          claimId,
-        },
-      })
-      .then(result => {
-        if (result) {
-          return res.status(200).json({success: true, data: true});
-        }
-        res.status(200).json({success: true, data: false});
-      })
-      .catch(error => {
-        handleErrorResponse(originalUrl, ip, error, res);
-      });
-  };
+const fileAvailability = ({ ip, originalUrl, params }, res) => {
+  const name = params.name;
+  const claimId = params.claimId;
+  db.File
+    .findOne({
+      where: {
+        name,
+        claimId,
+      },
+    })
+    .then(result => {
+      if (result) {
+        return res.status(200).json({success: true, data: true});
+      }
+      res.status(200).json({success: true, data: false});
+    })
+    .catch(error => {
+      handleErrorResponse(originalUrl, ip, error, res);
+    });
 };
 
 module.exports = fileAvailability;
diff --git a/server/routes/api/index.js b/server/routes/api/index.js
index e15046d3..8679ab78 100644
--- a/server/routes/api/index.js
+++ b/server/routes/api/index.js
@@ -12,18 +12,23 @@ const claimShortId = require('./claimShortId');
 const claimList = require('./claimList');
 const fileAvailability = require('./fileAvailability');
 
-module.exports = {
-  channelAvailability,
-  channelClaims,
-  channelData,
-  channelShortId,
-  claimAvailability,
-  claimData,
-  claimGet,
-  claimLongId,
-  claimPublish,
-  claimResolve,
-  claimShortId,
-  claimList,
-  fileAvailability,
+const multipartMiddleware = require('helpers/multipartMiddleware');
+
+module.exports = (app) => {
+  // channel routes
+  app.get('/api/channel/availability/:name', channelAvailability);
+  app.get('/api/channel/short-id/:longId/:name', channelShortId);
+  app.get('/api/channel/data/:channelName/:channelClaimId', channelData);
+  app.get('/api/channel/claims/:channelName/:channelClaimId/:page', channelClaims);
+  // claim routes
+  app.get('/api/claim/list/:name', claimList);
+  app.get('/api/claim/get/:name/:claimId', claimGet);
+  app.get('/api/claim/availability/:name', claimAvailability);
+  app.get('/api/claim/resolve/:name/:claimId', claimResolve);
+  app.post('/api/claim/publish', multipartMiddleware, claimPublish);
+  app.get('/api/claim/short-id/:longId/:name', claimShortId);
+  app.post('/api/claim/long-id', claimLongId);
+  app.get('/api/claim/data/:claimName/:claimId', claimData);
+  // file routes
+  app.get('/api/file/availability/:name/:claimId', fileAvailability);
 };
diff --git a/server/routes/asset/serveAssetByClaim.js b/server/routes/asset/serveAssetByClaim.js
deleted file mode 100644
index 7fe091df..00000000
--- a/server/routes/asset/serveAssetByClaim.js
+++ /dev/null
@@ -1,44 +0,0 @@
-const { sendGAServeEvent } = require('helpers/googleAnalytics');
-const { determineResponseType, logRequestData, getClaimIdAndServeAsset } = require('helpers/serveHelpers.js');
-const lbryUri = require('helpers/lbryUri.js');
-const handleShowRender = require('helpers/handleShowRender.jsx');
-const SERVE = 'SERVE';
-
-/*
-
-  route to serve an asset or the react app via the claim name only
-
-*/
-
-const claim = () => {
-  return (req, res) => {
-    const { headers, ip, originalUrl, params } = req;
-    // decide if this is a show request
-    let hasFileExtension;
-    try {
-      ({ hasFileExtension } = lbryUri.parseModifier(params.claim));
-    } catch (error) {
-      return res.status(400).json({success: false, message: error.message});
-    }
-    let responseType = determineResponseType(hasFileExtension, headers);
-    if (responseType !== SERVE) {
-      return handleShowRender(req, res);
-    }
-    // handle serve request
-    // send google analytics
-    sendGAServeEvent(headers, ip, originalUrl);
-    // parse the claim
-    let claimName;
-    try {
-      ({claimName} = lbryUri.parseClaim(params.claim));
-    } catch (error) {
-      return res.status(400).json({success: false, message: error.message});
-    }
-    // log the request data for debugging
-    logRequestData(responseType, claimName, null, null);
-    // get the claim Id and then serve the asset
-    getClaimIdAndServeAsset(null, null, claimName, null, originalUrl, ip, res);
-  };
-};
-
-module.exports = claim;
diff --git a/server/routes/asset/serveAssetByIdentifierAndClaim.js b/server/routes/asset/serveAssetByIdentifierAndClaim.js
deleted file mode 100644
index 5c305d51..00000000
--- a/server/routes/asset/serveAssetByIdentifierAndClaim.js
+++ /dev/null
@@ -1,55 +0,0 @@
-const { sendGAServeEvent } = require('helpers/googleAnalytics');
-const { determineResponseType, flipClaimNameAndIdForBackwardsCompatibility, logRequestData, getClaimIdAndServeAsset } = require('helpers/serveHelpers.js');
-const lbryUri = require('helpers/lbryUri.js');
-const handleShowRender = require('helpers/handleShowRender.jsx');
-
-const SERVE = 'SERVE';
-
-/*
-
-  route to serve an asset or the react app via the claim name and an identifier
-
-*/
-
-const identifierClaim = () => {
-  return (req, res) => {
-    const { headers, ip, originalUrl, params } = req;
-    // decide if this is a show request
-    let hasFileExtension;
-    try {
-      ({ hasFileExtension } = lbryUri.parseModifier(params.claim));
-    } catch (error) {
-      return res.status(400).json({success: false, message: error.message});
-    }
-    let responseType = determineResponseType(hasFileExtension, headers);
-    if (responseType !== SERVE) {
-      return handleShowRender(req, res);
-    }
-    // handle serve request
-    // send google analytics
-    sendGAServeEvent(headers, ip, originalUrl);
-    // parse the claim
-    let claimName;
-    try {
-      ({ claimName } = lbryUri.parseClaim(params.claim));
-    } catch (error) {
-      return res.status(400).json({success: false, message: error.message});
-    }
-    // parse the identifier
-    let isChannel, channelName, channelClaimId, claimId;
-    try {
-      ({ isChannel, channelName, channelClaimId, claimId } = lbryUri.parseIdentifier(params.identifier));
-    } catch (error) {
-      return res.status(400).json({success: false, message: error.message});
-    }
-    if (!isChannel) {
-      [claimId, claimName] = flipClaimNameAndIdForBackwardsCompatibility(claimId, claimName);
-    }
-    // log the request data for debugging
-    logRequestData(responseType, claimName, channelName, claimId);
-    // get the claim Id and then serve the asset
-    getClaimIdAndServeAsset(channelName, channelClaimId, claimName, claimId, originalUrl, ip, res);
-  };
-};
-
-module.exports = identifierClaim;
diff --git a/server/routes/asset/index.js b/server/routes/assets/index.js
similarity index 51%
rename from server/routes/asset/index.js
rename to server/routes/assets/index.js
index d988c234..4f358a74 100644
--- a/server/routes/asset/index.js
+++ b/server/routes/assets/index.js
@@ -1,8 +1,7 @@
 const serveAssetByClaim = require('./serveAssetByClaim');
 const serveAssetByIdentifierAndClaim = require('./serveAssetByIdentifierAndClaim');
 
-
-module.exports = {
-  serveAssetByClaim,
-  serveAssetByIdentifierAndClaim,
+module.exports = (app, db) => {
+  app.get('/:identifier/:claim', serveAssetByIdentifierAndClaim);
+  app.get('/:claim', serveAssetByClaim);
 };
diff --git a/server/routes/assets/serveAssetByClaim.js b/server/routes/assets/serveAssetByClaim.js
new file mode 100644
index 00000000..9eec9b93
--- /dev/null
+++ b/server/routes/assets/serveAssetByClaim.js
@@ -0,0 +1,42 @@
+const { sendGAServeEvent } = require('helpers/googleAnalytics');
+const { determineResponseType, logRequestData, getClaimIdAndServeAsset } = require('helpers/serveHelpers.js');
+const lbryUri = require('helpers/lbryUri.js');
+const handleShowRender = require('helpers/handleShowRender.jsx');
+const SERVE = 'SERVE';
+
+/*
+
+  route to serve an asset or the react app via the claim name only
+
+*/
+
+const serverAssetByClaim = (req, res) => {
+  const { headers, ip, originalUrl, params } = req;
+  // decide if this is a show request
+  let hasFileExtension;
+  try {
+    ({ hasFileExtension } = lbryUri.parseModifier(params.claim));
+  } catch (error) {
+    return res.status(400).json({success: false, message: error.message});
+  }
+  let responseType = determineResponseType(hasFileExtension, headers);
+  if (responseType !== SERVE) {
+    return handleShowRender(req, res);
+  }
+  // handle serve request
+  // send google analytics
+  sendGAServeEvent(headers, ip, originalUrl);
+  // parse the claim
+  let claimName;
+  try {
+    ({claimName} = lbryUri.parseClaim(params.claim));
+  } catch (error) {
+    return res.status(400).json({success: false, message: error.message});
+  }
+  // log the request data for debugging
+  logRequestData(responseType, claimName, null, null);
+  // get the claim Id and then serve the asset
+  getClaimIdAndServeAsset(null, null, claimName, null, originalUrl, ip, res);
+};
+
+module.exports = serverAssetByClaim;
diff --git a/server/routes/assets/serveAssetByIdentifierAndClaim.js b/server/routes/assets/serveAssetByIdentifierAndClaim.js
new file mode 100644
index 00000000..2357b520
--- /dev/null
+++ b/server/routes/assets/serveAssetByIdentifierAndClaim.js
@@ -0,0 +1,58 @@
+const { sendGAServeEvent } = require('helpers/googleAnalytics');
+const {
+  determineResponseType,
+  flipClaimNameAndIdForBackwardsCompatibility,
+  logRequestData,
+  getClaimIdAndServeAsset,
+} = require('helpers/serveHelpers.js');
+const lbryUri = require('helpers/lbryUri.js');
+const handleShowRender = require('helpers/handleShowRender.jsx');
+
+const SERVE = 'SERVE';
+
+/*
+
+  route to serve an asset or the react app via the claim name and an identifier
+
+*/
+
+const serverAssetByIdentifierAndClaim = (req, res) => {
+  const { headers, ip, originalUrl, params } = req;
+  // decide if this is a show request
+  let hasFileExtension;
+  try {
+    ({ hasFileExtension } = lbryUri.parseModifier(params.claim));
+  } catch (error) {
+    return res.status(400).json({success: false, message: error.message});
+  }
+  let responseType = determineResponseType(hasFileExtension, headers);
+  if (responseType !== SERVE) {
+    return handleShowRender(req, res);
+  }
+  // handle serve request
+  // send google analytics
+  sendGAServeEvent(headers, ip, originalUrl);
+  // parse the claim
+  let claimName;
+  try {
+    ({ claimName } = lbryUri.parseClaim(params.claim));
+  } catch (error) {
+    return res.status(400).json({success: false, message: error.message});
+  }
+  // parse the identifier
+  let isChannel, channelName, channelClaimId, claimId;
+  try {
+    ({ isChannel, channelName, channelClaimId, claimId } = lbryUri.parseIdentifier(params.identifier));
+  } catch (error) {
+    return res.status(400).json({success: false, message: error.message});
+  }
+  if (!isChannel) {
+    [claimId, claimName] = flipClaimNameAndIdForBackwardsCompatibility(claimId, claimName);
+  }
+  // log the request data for debugging
+  logRequestData(responseType, claimName, channelName, claimId);
+  // get the claim Id and then serve the asset
+  getClaimIdAndServeAsset(channelName, channelClaimId, claimName, claimId, originalUrl, ip, res);
+};
+
+module.exports = serverAssetByIdentifierAndClaim;
diff --git a/server/routes/page/index.js b/server/routes/pages/index.js
similarity index 100%
rename from server/routes/page/index.js
rename to server/routes/pages/index.js
diff --git a/server/routes/page/redirect.js b/server/routes/pages/redirect.js
similarity index 100%
rename from server/routes/page/redirect.js
rename to server/routes/pages/redirect.js
diff --git a/server/routes/page/sendEmbedPage.js b/server/routes/pages/sendEmbedPage.js
similarity index 100%
rename from server/routes/page/sendEmbedPage.js
rename to server/routes/pages/sendEmbedPage.js
diff --git a/server/routes/page/sendReactApp.js b/server/routes/pages/sendReactApp.js
similarity index 100%
rename from server/routes/page/sendReactApp.js
rename to server/routes/pages/sendReactApp.js
diff --git a/server/server.js b/server/server.js
new file mode 100644
index 00000000..a577536b
--- /dev/null
+++ b/server/server.js
@@ -0,0 +1,98 @@
+// app dependencies
+const express = require('express');
+const bodyParser = require('body-parser');
+const expressHandlebars = require('express-handlebars');
+const Handlebars = require('handlebars');
+const helmet = require('helmet');
+const passport = require('passport');
+const { serializeSpeechUser, deserializeSpeechUser } = require('./helpers/authHelpers.js');
+const cookieSession = require('cookie-session');
+const http = require('http');
+// logging dependencies
+const logger = require('winston');
+
+function Server () {
+  this.configureMysql = (mysqlConfig) => {
+    require('../config/mysqlConfig.js').configure(mysqlConfig);
+  };
+  this.configureSite = (siteConfig) => {
+    require('../config/siteConfig.js').configure(siteConfig);
+    this.sessionKey = siteConfig.auth.sessionKey;
+    this.PORT = siteConfig.details.port;
+  };
+  this.configureSlack = (slackConfig) => {
+    require('../config/slackConfig.js').configure(slackConfig);
+  };
+  this.createApp = () => {
+    // create an Express application
+    const app = express();
+
+    // trust the proxy to get ip address for us
+    app.enable('trust proxy');
+
+    // add middleware
+    app.use(helmet()); // set HTTP headers to protect against well-known web vulnerabilties
+    app.use(express.static(`${__dirname}/public`)); // 'express.static' to serve static files from public directory
+    app.use(bodyParser.json()); // 'body parser' for parsing application/json
+    app.use(bodyParser.urlencoded({ extended: true })); // 'body parser' for parsing application/x-www-form-urlencoded
+    app.use((req, res, next) => {  // custom logging middleware to log all incoming http requests
+      logger.verbose(`Request on ${req.originalUrl} from ${req.ip}`);
+      next();
+    });
+
+    // configure passport
+    passport.serializeUser(serializeSpeechUser);
+    passport.deserializeUser(deserializeSpeechUser);
+    const localSignupStrategy = require('./passport/local-signup.js');
+    const localLoginStrategy = require('./passport/local-login.js');
+    passport.use('local-signup', localSignupStrategy);
+    passport.use('local-login', localLoginStrategy);
+    // initialize passport
+    app.use(cookieSession({
+      name  : 'session',
+      keys  : [this.sessionKey],
+      maxAge: 24 * 60 * 60 * 1000, // i.e. 24 hours
+    }));
+    app.use(passport.initialize());
+    app.use(passport.session());
+
+    // configure handlebars & register it with express app
+    const hbs = expressHandlebars.create({
+      defaultLayout: 'embed',
+      handlebars   : Handlebars,
+    });
+    app.engine('handlebars', hbs.engine);
+    app.set('view engine', 'handlebars');
+
+    // set the routes on the app
+    require('./routes/auth.js')(app);
+    require('./routes/api.js')(app);
+    require('./routes/pages.js')(app);
+    require('./routes/assets.js')(app);
+    require('./routes/fallback.js')(app);
+
+    this.app = app;
+  };
+  this.initialize = () => {
+    require('./helpers/configureLogger.js')(logger);
+    require('./helpers/configureSlack.js')(logger);
+    this.createApp();
+    this.server = http.Server(this.app);
+  };
+  this.start = () => {
+    const db = require('./models/index');
+    // sync sequelize
+    db.sequelize.sync()
+    // start the server
+      .then(() => {
+        this.server.listen(this.PORT, () => {
+          logger.info(`Server is listening on PORT ${this.PORT}`);
+        });
+      })
+      .catch((error) => {
+        logger.error(`Startup Error:`, error);
+      });
+  };
+};
+
+module.exports = Server;
diff --git a/speech.js b/speech.js
index aab99668..6a92d8d8 100644
--- a/speech.js
+++ b/speech.js
@@ -4,9 +4,9 @@ import rootSaga  from 'sagas';
 import GAListener from 'components/GAListener';
 
 const api = require('./server/routes/api/');
-const asset = require('./server/routes/asset/');
+const asset = require('./server/routes/assets/');
 const auth = require('./server/routes/auth/');
-const page = require('./server/routes/page/');
+const page = require('./server/routes/pages/');
 const logger = require('./config/loggerConfig.js');
 const mysql = require('./config/mysqlConfig');
 const site = require('./config/siteConfig');