Starting on working bookmarks api
This commit is contained in:
12
web/lib/apiHelpers.js
Normal file
12
web/lib/apiHelpers.js
Normal file
@@ -0,0 +1,12 @@
|
||||
function withErrorHandling(handler) {
|
||||
return async (req, res) => {
|
||||
try {
|
||||
await handler(req, res);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
res.status(error.status || 500).end(error.message);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export { withErrorHandling };
|
||||
13
web/lib/db.js
Normal file
13
web/lib/db.js
Normal file
@@ -0,0 +1,13 @@
|
||||
const AWS = require("aws-sdk");
|
||||
|
||||
AWS.config.update({
|
||||
accessKeyId: process.env.FMN_AWS_ACCESS_KEY_ID, // Do NOT HARD-CODE your secret credentials here
|
||||
secretAccessKey: process.env.FMN_AWS_SECRET_ACCESS_KEY, // Do NOT HARD-CODE your secret credentials here
|
||||
region: process.env.FMN_AWS_REGION,
|
||||
});
|
||||
|
||||
const dynamodb = new AWS.DynamoDB.DocumentClient({
|
||||
region: process.env.FMN_AWS_REGION,
|
||||
});
|
||||
|
||||
export default dynamodb;
|
||||
78
web/package-lock.json
generated
78
web/package-lock.json
generated
@@ -63,6 +63,26 @@
|
||||
"js-yaml": "^4.1.0",
|
||||
"minimatch": "^3.1.2",
|
||||
"strip-json-comments": "^3.1.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"ajv": {
|
||||
"version": "6.12.6",
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
|
||||
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"fast-deep-equal": "^3.1.1",
|
||||
"fast-json-stable-stringify": "^2.0.0",
|
||||
"json-schema-traverse": "^0.4.1",
|
||||
"uri-js": "^4.2.2"
|
||||
}
|
||||
},
|
||||
"json-schema-traverse": {
|
||||
"version": "0.4.1",
|
||||
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
|
||||
"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"@hapi/hoek": {
|
||||
@@ -388,17 +408,24 @@
|
||||
}
|
||||
},
|
||||
"ajv": {
|
||||
"version": "6.12.6",
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
|
||||
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
|
||||
"dev": true,
|
||||
"version": "8.11.0",
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz",
|
||||
"integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==",
|
||||
"requires": {
|
||||
"fast-deep-equal": "^3.1.1",
|
||||
"fast-json-stable-stringify": "^2.0.0",
|
||||
"json-schema-traverse": "^0.4.1",
|
||||
"json-schema-traverse": "^1.0.0",
|
||||
"require-from-string": "^2.0.2",
|
||||
"uri-js": "^4.2.2"
|
||||
}
|
||||
},
|
||||
"ajv-formats": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz",
|
||||
"integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==",
|
||||
"requires": {
|
||||
"ajv": "^8.0.0"
|
||||
}
|
||||
},
|
||||
"ansi-regex": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
|
||||
@@ -852,6 +879,26 @@
|
||||
"strip-json-comments": "^3.1.0",
|
||||
"text-table": "^0.2.0",
|
||||
"v8-compile-cache": "^2.0.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"ajv": {
|
||||
"version": "6.12.6",
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
|
||||
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"fast-deep-equal": "^3.1.1",
|
||||
"fast-json-stable-stringify": "^2.0.0",
|
||||
"json-schema-traverse": "^0.4.1",
|
||||
"uri-js": "^4.2.2"
|
||||
}
|
||||
},
|
||||
"json-schema-traverse": {
|
||||
"version": "0.4.1",
|
||||
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
|
||||
"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"eslint-config-next": {
|
||||
@@ -1130,8 +1177,7 @@
|
||||
"fast-deep-equal": {
|
||||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
|
||||
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
|
||||
"dev": true
|
||||
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="
|
||||
},
|
||||
"fast-glob": {
|
||||
"version": "3.2.11",
|
||||
@@ -1665,10 +1711,9 @@
|
||||
"integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ=="
|
||||
},
|
||||
"json-schema-traverse": {
|
||||
"version": "0.4.1",
|
||||
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
|
||||
"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
|
||||
"dev": true
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
|
||||
"integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="
|
||||
},
|
||||
"json-stable-stringify-without-jsonify": {
|
||||
"version": "1.0.1",
|
||||
@@ -2099,8 +2144,7 @@
|
||||
"punycode": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
|
||||
"integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
|
||||
"dev": true
|
||||
"integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A=="
|
||||
},
|
||||
"querystring": {
|
||||
"version": "0.2.0",
|
||||
@@ -2164,6 +2208,11 @@
|
||||
"integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==",
|
||||
"dev": true
|
||||
},
|
||||
"require-from-string": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
|
||||
"integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw=="
|
||||
},
|
||||
"resolve": {
|
||||
"version": "1.22.0",
|
||||
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz",
|
||||
@@ -2444,7 +2493,6 @@
|
||||
"version": "4.4.1",
|
||||
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
|
||||
"integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"punycode": "^2.1.0"
|
||||
}
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@auth0/nextjs-auth0": "^1.8.0",
|
||||
"ajv": "^8.11.0",
|
||||
"ajv-formats": "^2.1.1",
|
||||
"aws-sdk": "^2.1131.0",
|
||||
"next": "12.1.6",
|
||||
"react": "18.1.0",
|
||||
|
||||
67
web/pages/api/bookmarks.js
Normal file
67
web/pages/api/bookmarks.js
Normal file
@@ -0,0 +1,67 @@
|
||||
import db from "../../lib/db";
|
||||
import Ajv from "ajv";
|
||||
import addFormats from "ajv-formats";
|
||||
import { withErrorHandling } from "../../lib/apiHelpers";
|
||||
|
||||
const handler = withErrorHandling(async (req, res) => {
|
||||
const { method } = req;
|
||||
|
||||
switch (method) {
|
||||
case "GET":
|
||||
await getBookmark(req, res);
|
||||
break;
|
||||
case "POST":
|
||||
await createBookmark(req, res);
|
||||
break;
|
||||
default:
|
||||
res.setHeader("Allow", ["GET", "POST"]);
|
||||
res.status(405).end(`Method ${method} Not Allowed`);
|
||||
}
|
||||
});
|
||||
|
||||
const ajv = new Ajv();
|
||||
addFormats(ajv);
|
||||
|
||||
const createBookmarkSchema = {
|
||||
type: "object",
|
||||
properties: {
|
||||
title: { type: "string" },
|
||||
url: { type: "string", format: "uri" },
|
||||
},
|
||||
required: ["title", "url"],
|
||||
};
|
||||
|
||||
const validateCreateBookmarkSchema = ajv.compile(createBookmarkSchema);
|
||||
|
||||
const getBookmark = async (req, res) => {
|
||||
const params = {
|
||||
TableName: process.env.FMN_DYNAMODB_TABLENAME,
|
||||
KeyConditionExpression: "hk = :hk",
|
||||
ExpressionAttributeValues: { ":hk": "user#123" },
|
||||
};
|
||||
|
||||
let bookmark = await db.query(params).promise();
|
||||
res.status(200).json(bookmark);
|
||||
};
|
||||
|
||||
const createBookmark = async (req, res) => {
|
||||
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#${123}`,
|
||||
sk: `bookmark#${"abc"}`,
|
||||
title: req.body.title,
|
||||
url: req.body.url,
|
||||
},
|
||||
};
|
||||
|
||||
await db.put(params).promise();
|
||||
};
|
||||
|
||||
export default handler;
|
||||
@@ -1,10 +1,6 @@
|
||||
import auth0 from "../../lib/auth0";
|
||||
import { withErrorHandling } from "../../lib/apiHelpers";
|
||||
|
||||
export default async function callback(req, res) {
|
||||
try {
|
||||
await auth0.handleCallback(req, res);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
res.status(error.status || 500).end(error.message);
|
||||
}
|
||||
}
|
||||
export default callback = withErrorHandling(async (req, res) => {
|
||||
await auth0.handleCallback(req, res);
|
||||
});
|
||||
|
||||
@@ -1,23 +1,26 @@
|
||||
const AWS = require("aws-sdk");
|
||||
import db from "../../lib/db";
|
||||
import { withErrorHandling } from "../../lib/apiHelpers";
|
||||
|
||||
AWS.config.update({
|
||||
accessKeyId: process.env.FMN_AWS_ACCESS_KEY_ID, // Do NOT HARD-CODE your secret credentials here
|
||||
secretAccessKey: process.env.FMN_AWS_SECRET_ACCESS_KEY, // Do NOT HARD-CODE your secret credentials here
|
||||
region: process.env.FMN_AWS_REGION,
|
||||
const handler = withErrorHandling(async (req, res) => {
|
||||
const { method } = req;
|
||||
|
||||
switch (method) {
|
||||
case "GET":
|
||||
await get(req, res);
|
||||
default:
|
||||
res.setHeader("Allow", ["GET"]);
|
||||
res.status(405).end(`Method ${method} Not Allowed`);
|
||||
}
|
||||
});
|
||||
|
||||
const dynamodb = new AWS.DynamoDB.DocumentClient({
|
||||
region: process.env.FMN_AWS_REGION,
|
||||
});
|
||||
|
||||
const handler = async (req, res) => {
|
||||
const get = async (req, res) => {
|
||||
const params = {
|
||||
TableName: process.env.FMN_DYNAMODB_TABLENAME,
|
||||
KeyConditionExpression: "hk = :hk",
|
||||
ExpressionAttributeValues: { ":hk": "benramey@fastmail.com" },
|
||||
};
|
||||
|
||||
let user = await dynamodb.query(params).promise();
|
||||
let user = await db.query(params).promise();
|
||||
|
||||
res.status(200).json(user);
|
||||
};
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
import auth0 from "../../lib/auth0";
|
||||
import { withErrorHandling } from "../../lib/apiHelpers";
|
||||
|
||||
export default async function login(req, res) {
|
||||
try {
|
||||
await auth0.handleLogin(req, res);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
res.status(error.status || 500).end(error.message);
|
||||
}
|
||||
}
|
||||
export default login = withErrorHandling(async (req, res) => {
|
||||
await auth0.handleLogin(req, res);
|
||||
});
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
import auth0 from "../../lib/auth0";
|
||||
import { withErrorHandling } from "../../lib/apiHelpers";
|
||||
|
||||
export default async function logout(req, res) {
|
||||
try {
|
||||
await auth0.handleLogout(req, res);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
res.status(error.status || 500).end(error.message);
|
||||
}
|
||||
}
|
||||
export default logout = withErrorHandling(async (req, res) => {
|
||||
await auth0.handleLogout(req, res);
|
||||
});
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
import auth0 from "../../lib/auth0";
|
||||
import { withErrorHandling } from "../../lib/apiHelpers";
|
||||
|
||||
export default async function me(req, res) {
|
||||
try {
|
||||
await auth0.handleProfile(req, res);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
res.status(error.status || 500).end(error.message);
|
||||
}
|
||||
}
|
||||
export default me = withErrorHandling(async (req, res) => {
|
||||
await auth0.handleProfile(req, res);
|
||||
});
|
||||
|
||||
@@ -19,6 +19,16 @@ function Home() {
|
||||
Once you have logged in you should be able to click in{" "}
|
||||
<i>Profile</i> and <i>Logout</i>
|
||||
</p>
|
||||
<p>
|
||||
<form method="POST" action="/api/bookmarks">
|
||||
<label for="title">title: </label>
|
||||
<input type="text" name="title"/>
|
||||
<br />
|
||||
<label for="url">url:</label>
|
||||
<input type="text" name="url"/>
|
||||
<button type="submit">Add bookmark</button>
|
||||
</form>
|
||||
</p>
|
||||
</>
|
||||
)}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user