coppa
Version:
🏇 A CLI tool for local development of google cloud functions
86 lines (72 loc) • 2.96 kB
JavaScript
const fs = require('fs')
const cors = require('cors')
const path = require('path')
const program = require('commander')
const express = require('express')
const morgan = require('morgan')
const bodyParser = require('body-parser')
const yaml = require('js-yaml')
const quantor = require('quantor')
const { Ok, Err, encaseRes } = require('pratica')
const readServerlessYaml = (filePath, stage) =>
encaseRes(() => yaml.safeLoad(fs.readFileSync(filePath, 'utf8')))
.mapErr(err => `Error reading yaml file: ${filePath}, \nError: ${err}`)
.chain(yml => yml.functions ? Ok(yml) : Err(`No functions declared in yaml file: ${config}`))
.map(({ functions, service }) => Object.keys(functions).map(key => ({
name: stage ? `/${service}-${stage}-${key}` : `/${service}-${key}`,
display: functions[key].name,
description: functions[key].description,
handler: functions[key].handler
})))
const readFunctionsJs = filePath =>
encaseRes(() => require(path.resolve(filePath)))
.mapErr(err => `Could not read main functions module: ${filePath}, \nError: ${err}`)
const sanitizeFuncs = ({ handlers, funcsMod }) => handlers
.map(({ name, display, description, handler }) => ({ name, display, description, handler: funcsMod[handler] }))
.filter(({ handler }) => !!handler)
const createServer = port => funcs => {
const app = express()
app.use(bodyParser.urlencoded({ extended: true }))
app.use(bodyParser.json())
app.use(morgan('dev'))
app.use(cors())
funcs.map(({ name, handler }) => console.log(name) || app.use(name, handler))
app.get('/', (req, res) => quantor({
title: 'Coppa Server',
endpoints: funcs.map(({ name, display, description }) => ({
name,
description: description || 'No description provided...',
display: display || 'No name provided...',
handlers: { GET: {}, POST: {}, PUT: {}, DELETE: {} }
}))
})(html => res.send(html)))
app.listen(port, () => console.log(`Coppa listening on port ${port}!`))
}
const start = opts => {
const port = opts.port || 8080
const config = opts.config || './serverless.yml'
const entry = opts.entry || './index.js'
const stage = opts.stage
readServerlessYaml(config, stage)
.chain(handlers => readFunctionsJs(entry).map(funcsMod => ({ handlers, funcsMod })))
.map(sanitizeFuncs)
.cata({
Ok: createServer(port),
Err: msg => {
console.error(msg)
process.exit(1)
}
})
}
// --- CLI PROGRAM --- //
program.version('1.0.0')
program
.command('start')
.description('Start the Coppa dev server')
.option('-c, --config [path]', 'Path to serverless config file (default: ./serverless.yml)')
.option('-e, --entry [path]', 'Path to JS entry point file (default: ./index.js)')
.option('-s, --stage [stage]', 'Stage to be used')
.option('-p, --port [port]', 'Port for server to use (default: 8080)')
.action(start)
program.parse(process.argv)