new todo-backend

This commit is contained in:
Guy Bianco IV
2021-05-19 12:50:48 -04:00
parent 20d773370e
commit 0bc1c87dda
17 changed files with 7782 additions and 342 deletions

View File

@@ -0,0 +1,43 @@
import cookieParser from "cookie-parser";
import express, { Request, Response } from "express";
import "express-async-errors";
import cors from "cors";
import { Sequelize } from "sequelize";
import BaseRouter from "./routes";
import { dbConnectionOptions } from "./entities/db";
const app = express();
// DO NOT USE in production as this allows any site to use our backend
// you will need to configure cors separately for your application
app.use(cors());
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(cookieParser());
const sequelize = new Sequelize(dbConnectionOptions);
sequelize
.authenticate()
.then(() => {
console.log("Connection has been established successfully.");
})
.catch((err) => {
console.error("Unable to connect to the database:", err);
});
// Add APIs
app.use("/api", BaseRouter);
// Print API errors
// eslint-disable-next-line @typescript-eslint/no-unused-vars
app.use((err: Error, req: Request, res: Response) => {
console.error(err, true);
return res.status(500).json({
error: err.message,
});
});
// Export express instance
export default app;

View File

@@ -0,0 +1,54 @@
import { Sequelize, DataTypes, Model, Optional } from "sequelize";
import { dbConnectionOptions } from "./db";
export interface TodoItemAttributes {
id: number;
description: string;
done: boolean;
}
type TodoItemCreationAttributes = Optional<TodoItemAttributes, "id">;
interface TodoItemInstance
extends Model<TodoItemAttributes, TodoItemCreationAttributes> {
createdAt: Date;
updatedAt: Date;
}
const sequelize = new Sequelize(dbConnectionOptions);
export const TodoItem = sequelize.define<TodoItemInstance>(
"TodoItem",
{
id: {
type: DataTypes.BIGINT,
primaryKey: true,
unique: true,
allowNull: false,
autoIncrement: true,
},
description: { type: DataTypes.STRING, allowNull: true },
done: { type: DataTypes.BOOLEAN, allowNull: true },
},
{
timestamps: false,
freezeTableName: true,
}
);
// (re-)creates table (NOT database)
if (process.env.DATABASE_INIT === "true") {
TodoItem.sync({ force: true });
}
export async function createTodoItem(todoItem: TodoItemCreationAttributes) {
return TodoItem.create(todoItem).then((item) => item.get());
}
export async function deleteTodoItem(id: number) {
return TodoItem.destroy({ where: { id } });
}
export async function listAllTodoItems(): Promise<TodoItemAttributes[]> {
return TodoItem.findAll({}).then((items) => items.map((i) => i.get()));
}

View File

@@ -0,0 +1,18 @@
import { Options } from "sequelize";
const {
DATABASE_NAME,
DATABASE_USER,
DATABASE_PASSWORD,
DATABASE_SVC,
DATABASE_PORT,
} = process.env;
export const dbConnectionOptions: Options = {
database: DATABASE_NAME ?? "todo",
username: DATABASE_USER ?? "root",
password: DATABASE_PASSWORD ?? "",
host: DATABASE_SVC ?? "localhost",
port: Number(DATABASE_PORT) ?? 3306,
dialect: "mysql",
};

View File

@@ -0,0 +1,7 @@
import app from "@server";
// Start the server
const port = Number(process.env.PORT || 8080);
app.listen(port, () => {
console.log("Express server started on port: " + port);
});

View File

@@ -0,0 +1,27 @@
import {
createTodoItem,
deleteTodoItem,
listAllTodoItems,
} from "@entities/Item";
import { Request, Response } from "express";
export function handleCreate(req: Request, res: Response) {
const { description, done } = req.body;
// NOTE production applications should use a validation framework
if (typeof description !== "string" || typeof done !== "boolean") {
res
.status(400)
.send("required parameters were either missing or the wrong type");
} else {
createTodoItem({ description, done }).then((item) => res.json(item));
}
}
export function handleReadAll(req: Request, res: Response) {
listAllTodoItems().then((items) => res.json(items));
}
export function handleDelete(req: Request, res: Response) {
deleteTodoItem(Number(req.params.id)).then(() => res.json({}));
}

View File

@@ -0,0 +1,13 @@
import { Router } from "express";
import { handleCreate, handleReadAll, handleDelete } from "./Items";
// Item routes
const itemRouter = Router();
itemRouter.get("/", handleReadAll);
itemRouter.post("/", handleCreate);
itemRouter.delete("/:id", handleDelete);
// Export the base-router
const baseRouter = Router();
baseRouter.use("/items", itemRouter);
export default baseRouter;