Skip to content

Commit

Permalink
✨ add backend that will serve API
Browse files Browse the repository at this point in the history
Boy, was this a hassle. Writing the actual Express server was fine,
but getting it setup properly with `now` and adding Google's private key
as a secret variable took forever. THEN when that was solved I couldn't
for the life of me get the server deployed using `now` v2.

Ultimately ended up deciding to deploy the backend using v1 and will
have to read up on `now` lambdas and think about rewriting this as
serverless functions.
  • Loading branch information
cedricium committed Dec 9, 2018
1 parent 643dd6a commit 1cfc5bf
Show file tree
Hide file tree
Showing 9 changed files with 240 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Expand Up @@ -18,6 +18,9 @@ node_modules
.env.test.local
.env.production.local

package-lock.json
now-secrets.json

npm-debug.log*
yarn-debug.log*
yarn-error.log*
Expand Down
2 changes: 2 additions & 0 deletions server/.nowignore
@@ -0,0 +1,2 @@
now-secrets.json
now-secrets.json.example
8 changes: 8 additions & 0 deletions server/api/index.js
@@ -0,0 +1,8 @@
const { Router } = require('express')
const router = Router()

const riddles = require('./riddles')

router.use('/riddles', riddles)

module.exports = router
64 changes: 64 additions & 0 deletions server/api/riddles.js
@@ -0,0 +1,64 @@
const atob = require('atob');
const admin = require('firebase-admin')
const { Router } = require('express')
const router = Router()

const NODE_ENV = process.env.NODE_ENV || 'development'
const PRIVATE_KEY = NODE_ENV === 'production'
? atob(process.env.PRIVATE_KEY)
: process.env.PRIVATE_KEY

admin.initializeApp({
credential: admin.credential.cert({
"type": process.env.TYPE,
"project_id": process.env.PROJECT_ID,
"private_key_id": process.env.PRIVATE_KEY_ID,
"private_key": PRIVATE_KEY,
"client_email": process.env.CLIENT_EMAIL,
"client_id": process.env.CLIENT_ID,
"auth_uri": process.env.AUTH_URI,
"token_uri": process.env.TOKEN_URI,
"auth_provider_x509_cert_url": process.env.AUTH_PROVIDER_X509_CERT_URL,
"client_x509_cert_url": process.env.CLIENT_X509_CERT_URL,
}),
})
const db = admin.firestore()
const riddlesRef = db.collection('riddles')

router.get('/', async (req, res) => {
try {
const riddlesSnapshot = await riddlesRef.get()
const riddles = []
riddlesSnapshot.forEach((doc) => {
const r = doc.data()
r['id'] = doc.id
riddles.push(r)
})
res.json(riddles)
} catch (e) {
res.status(400).json({
error: e.message
})
}
})

router.get('/:id', async (req, res) => {
try {
const id = req.params.id
const riddle = await riddlesRef.doc(id).get()

if (!riddle.exists) {
throw new Error(`No such document with 'id': ${id}`)
} else {
const r = riddle.data()
r['id'] = id
res.json(r)
}
} catch (e) {
res.status(400).json({
error: e.message
})
}
})

module.exports = router
20 changes: 20 additions & 0 deletions server/app.js
@@ -0,0 +1,20 @@
const express = require('express')
const path = require('path')
const cookieParser = require('cookie-parser')
const cors = require('cors')
const logger = require('morgan')

require('now-env')

const api = require('./api')
const app = express()

app.use(logger('dev'))
app.use(express.json())
app.use(express.urlencoded({ extended: false }))
app.use(cookieParser())
app.use(cors())

app.use('/api/v1/', api)

module.exports = app
90 changes: 90 additions & 0 deletions server/bin/www
@@ -0,0 +1,90 @@
#!/usr/bin/env node

/**
* Module dependencies.
*/

var app = require('../app');
var debug = require('debug')('server:server');
var http = require('http');

/**
* Get port from environment and store in Express.
*/

var port = normalizePort(process.env.PORT || '3000');
app.set('port', port);

/**
* Create HTTP server.
*/

var server = http.createServer(app);

/**
* Listen on provided port, on all network interfaces.
*/

server.listen(port);
server.on('error', onError);
server.on('listening', onListening);

/**
* Normalize a port into a number, string, or false.
*/

function normalizePort(val) {
var port = parseInt(val, 10);

if (isNaN(port)) {
// named pipe
return val;
}

if (port >= 0) {
// port number
return port;
}

return false;
}

/**
* Event listener for HTTP server "error" event.
*/

function onError(error) {
if (error.syscall !== 'listen') {
throw error;
}

var bind = typeof port === 'string'
? 'Pipe ' + port
: 'Port ' + port;

// handle specific listen errors with friendly messages
switch (error.code) {
case 'EACCES':
console.error(bind + ' requires elevated privileges');
process.exit(1);
break;
case 'EADDRINUSE':
console.error(bind + ' is already in use');
process.exit(1);
break;
default:
throw error;
}
}

/**
* Event listener for HTTP server "listening" event.
*/

function onListening() {
var addr = server.address();
var bind = typeof addr === 'string'
? 'pipe ' + addr
: 'port ' + addr.port;
debug('Listening on ' + bind);
}
12 changes: 12 additions & 0 deletions server/now-secrets.json.example
@@ -0,0 +1,12 @@
{
"@type": "service_account",
"@project_id": "",
"@private_key_id": "",
"@private_key": "",
"@client_email": "",
"@client_id": "",
"@auth_uri": "",
"@token_uri": "",
"@auth_provider_x509_cert_url": "",
"@client_x509_cert_url": ""
}
18 changes: 18 additions & 0 deletions server/now.json
@@ -0,0 +1,18 @@
{
"version": 1,
"name": "conundrum-api",
"public": false,
"env": {
"PORT": "3001",
"TYPE": "@type",
"PROJECT_ID": "@project_id",
"PRIVATE_KEY_ID": "@private_key_id",
"PRIVATE_KEY": "@private_key",
"CLIENT_EMAIL": "@client_email",
"CLIENT_ID": "@client_id",
"AUTH_URI": "@auth_uri",
"TOKEN_URI": "@token_uri",
"AUTH_PROVIDER_X509_CERT_URL": "@auth_provider_x509_cert_url",
"CLIENT_X509_CERT_URL": "@client_x509_cert_url"
}
}
23 changes: 23 additions & 0 deletions server/package.json
@@ -0,0 +1,23 @@
{
"name": "conundrum-api",
"version": "1.0.0",
"private": true,
"scripts": {
"dev": "NODE_ENV=development nodemon -r now-env ./bin/www",
"start": "NODE_ENV=production node ./bin/www"
},
"dependencies": {
"atob": "^2.1.2",
"cookie-parser": "~1.4.3",
"cors": "^2.8.5",
"debug": "~2.6.9",
"dotenv": "^6.2.0",
"express": "~4.16.0",
"firebase-admin": "^6.3.0",
"morgan": "~1.9.0"
},
"devDependencies": {
"nodemon": "^1.18.7",
"now-env": "^3.1.0"
}
}

0 comments on commit 1cfc5bf

Please sign in to comment.