Generic api for any entity

This commit is contained in:
2022-08-12 08:57:36 -05:00
parent d1495df5a1
commit f65ae56f74
5 changed files with 118 additions and 84 deletions

View File

@@ -0,0 +1,22 @@
import Ajv from "ajv";
import addFormats from "ajv-formats";
const ajv = new Ajv();
addFormats(ajv);
const validateId = ajv.compile({
type: "string",
minLength: 1,
maxLength: 10,
});
const validatePostBody = ajv.compile({
type: "object",
properties: {
title: { type: "string" },
url: { type: "string", format: "uri" },
},
required: ["title", "url"],
});
export { validateId, validatePostBody };

3
web/lib/models/index.js Normal file
View File

@@ -0,0 +1,3 @@
export default {
bookmarks: require("./bookmarks"),
};

View File

@@ -1,5 +1,6 @@
import db from "../../../../lib/db";
import { withErrorHandling, withSession } from "../../../../lib/apiHelpers";
import models from "../../../../lib/models";
const handler = withErrorHandling(
withSession(async (req, res, session) => {
@@ -8,19 +9,27 @@ const handler = withErrorHandling(
switch (method) {
case "GET":
await getBookmark(req, res, user);
await getEntity(req, res, user);
break;
default:
res.setHeader("Allow", ["GET", "POST"]);
res.setHeader("Allow", ["GET"]);
res.status(405).end(`Method ${method} Not Allowed`);
}
})
);
const getBookmark = async (req, res, user) => {
const { bookmarkId } = req.query;
const getEntity = async (req, res, user) => {
const { entityName, entityId } = req.query;
if (!bookmarkId) {
if (!models[entityName]) {
res.status(404).end();
return;
}
var model = models[entityName];
if (!model.validateId(entityId)) {
console.warn(model.validateId.errors);
res.status(404).end();
return;
}
@@ -30,14 +39,14 @@ const getBookmark = async (req, res, user) => {
KeyConditionExpression: "hk = :hk AND sk = :sk",
ExpressionAttributeValues: {
":hk": `user#${user.sub}`,
":sk": `bookmark#${bookmarkId}`,
":sk": `${entityName}#${entityId}`,
},
};
let bookmarks = await db.query(params).promise();
let entities = await db.query(params).promise();
if (bookmarks.Items.length == 1) {
res.status(200).json(bookmarks.Items[0]);
if (entities.Items.length == 1) {
res.status(200).json(entities.Items[0]);
} else {
res.status(404).end();
}

View File

@@ -0,0 +1,75 @@
import db from "../../../../lib/db";
import { withErrorHandling, withSession } from "../../../../lib/apiHelpers";
import models from "../../../../lib/models";
const handler = withErrorHandling(
withSession(async (req, res, session) => {
const { method } = req;
const { user } = session;
switch (method) {
case "GET":
await getEntities(req, res, user);
break;
case "POST":
await createEntity(req, res, user);
break;
default:
res.setHeader("Allow", ["GET", "POST"]);
res.status(405).end(`Method ${method} Not Allowed`);
}
})
);
const getEntities = async (req, res, user) => {
const { entityName } = req.query;
if (!models[entityName]) {
res.status(404).end();
return;
}
const params = {
TableName: process.env.FMN_DYNAMODB_TABLENAME,
KeyConditionExpression: "hk = :hk AND begins_with(sk, :sk)",
ExpressionAttributeValues: {
":hk": `user#${user.sub}`,
":sk": `${entityName}#`,
},
};
let entities = await db.query(params).promise();
res.status(200).json(entities.Items);
};
const createEntity = async (req, res, user) => {
const { entityName } = req.query;
if (!models[entityName]) {
res.status(404).end();
return;
}
var model = models[entityName];
if (!model.validatePostBody(req.body)) {
console.warn(validatePostBody.errors);
res.status(400).json(validatePostBody.errors);
return;
}
const params = {
TableName: process.env.FMN_DYNAMODB_TABLENAME,
Item: {
hk: `user#${user.sub}`,
sk: `${entityName}#${"abc"}`,
title: req.body.title,
url: req.body.url,
},
};
await db.put(params).promise();
res.status(200).json(params.Item);
};
export default handler;

View File

@@ -1,75 +0,0 @@
import Ajv from "ajv";
import addFormats from "ajv-formats";
import db from "../../../lib/db";
import { withErrorHandling, withSession } from "../../../lib/apiHelpers";
const handler = withErrorHandling(
withSession(async (req, res, session) => {
const { method } = req;
const { user } = session;
switch (method) {
case "GET":
await getBookmarks(req, res, user);
break;
case "POST":
await createBookmark(req, res, user);
break;
default:
res.setHeader("Allow", ["GET", "POST"]);
res.status(405).end(`Method ${method} Not Allowed`);
}
})
);
const ajv = new Ajv();
addFormats(ajv);
const getBookmarks = async (req, res, user) => {
const params = {
TableName: process.env.FMN_DYNAMODB_TABLENAME,
KeyConditionExpression: "hk = :hk AND begins_with(sk, :sk)",
ExpressionAttributeValues: {
":hk": `user#${user.sub}`,
":sk": "bookmark#",
},
};
let bookmarks = await db.query(params).promise();
res.status(200).json(bookmarks.Items);
};
const createBookmarkSchema = {
type: "object",
properties: {
title: { type: "string" },
url: { type: "string", format: "uri" },
},
required: ["title", "url"],
};
const validateCreateBookmarkSchema = ajv.compile(createBookmarkSchema);
const createBookmark = async (req, res, user) => {
if (!validateCreateBookmarkSchema(req.body)) {
console.warn(validateCreateBookmarkSchema.errors);
res.status(400).json(validateCreateBookmarkSchema.errors);
return;
}
const params = {
TableName: process.env.FMN_DYNAMODB_TABLENAME,
Item: {
hk: `user#${user.sub}`,
sk: `bookmark#${"abc"}`,
title: req.body.title,
url: req.body.url,
},
};
await db.put(params).promise();
res.status(200).json(params.Item);
};
export default handler;