const { basename, dirname } = require("path")
const _ = require("lodash")
let checkpoint = $checkpoint || {}
this.savedCheckpoint = checkpoint
const path = new URL(event.url).pathname
const key = path === "/" ? path : path.replace(/\/+$/, "")
switch (event.method) {
case 'POST':
post(key)
break
case 'PUT':
update(key)
break
case 'PATCH':
update(key)
break
case 'GET':
get(key)
break
case 'DELETE':
del(key)
break
default:
console.log(`HTTP method ${event.method} doesn't have an action defined.
Try adding it in the switch statement above!`)
break
}
function post(key) {
if (key === '/') {
respondWithErr("Cannot issue a POST request against the root URI /. Try POSTing to /foo or /test (for example)")
}
try {
const id = getNextId(checkpoint, key)
const newResource = _.set({}, getKeyArrayFromPath(key), {
[id]: JSON.stringify(event.body),
counter: id + 1,
})
$checkpoint = _.merge(checkpoint, newResource)
$respond({
body: JSON.stringify({
id,
key: `${key}/${id}`
})
})
} catch (err) {
errHandler(err)
}
}
function update(key) {
if (key === '/') {
respondWithErr("Cannot issue a PUT request against the root URI /. Try PUT /foo or /test (for example)")
}
_.set(checkpoint, getKeyArrayFromPath(key), JSON.stringify(event.body))
$checkpoint = checkpoint
$respond({
body: { message: `Updated ${key}`}
})
}
function get(key) {
if (key === '/') {
const body = listKeys(checkpoint)
$respond({
status: 200,
body,
})
$end("GET /")
}
if (!(key.match(/\d+$/))) {
const keys = listKeys(checkpoint, key)
if (!keys || !keys.length) {
console.log("No keys under collection")
$respond({
status: 404,
})
$end(`No keys at collection ${key}`)
}
let collection = []
for (const key of keys) {
const keyId = basename(key)
if (keyId === 'counter') {
continue
}
const data = JSON.parse(_.get(checkpoint, getKeyArrayFromPath(key)))
const id = { id: parseInt(keyId) }
collection.push({
...id,
...data,
})
}
$respond({
status: 200,
body: collection,
})
$end(`GET ${key}`)
}
try {
const data = _.get(checkpoint, getKeyArrayFromPath(key))
if (!data) {
$respond({
status: 404,
})
$end(`No data at key ${key}`)
}
$respond({
body: data,
})
} catch (err) {
errHandler(err)
}
}
function del(key) {
if (key === '/') {
$checkpoint = {}
const message = "Deleted all resources, API reset"
$respond({
body: { message }
})
$end(message)
}
const keyArray = getKeyArrayFromPath(key)
removeProperty(checkpoint, keyArray)
$respond({
body: { message: `DELETE request received, deleting key ${key}` },
})
}
function removeProperty(obj, props) {
delete props.slice(0, -1).reduce((init, curr) => init && init[curr], obj)[[...props].pop()];
}
function getNextId(ch, key) {
return _.get(ch, getKeyArrayFromPath(key).concat('counter'), 1)
}
function listKeys(ch, collection) {
if (collection) {
const keyIds = Object.keys(_.get(ch, getKeyArrayFromPath(collection), {}))
return keyIds.map(k => `${collection}/${k}`)
}
return listAllNestedKeys(ch, '')
}
function listAllNestedKeys(obj, pathSoFar) {
return _.compact(_.flattenDeep(Object.keys(obj).map(key => {
if (_.isObject(obj[key])) {
return listAllNestedKeys(obj[key], pathSoFar + `/${key}`)
}
if (key !== 'counter') {
return pathSoFar + `/${key}`
}
})))
}
function getKeyArrayFromPath(path) {
return path.split("/").slice(1)
}
function respondWithErr(error) {
$respond({
status: 400,
body: { error },
})
$end("Error running workflow")
}
function errHandler(err) {
if (err.response && err.response.status && err.response.status === 404) {
$respond({
status: err.response.status,
})
}
throw err
}