init
This commit is contained in:
21
backend/src/index.ts
Normal file
21
backend/src/index.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import * as dotenv from 'dotenv'
|
||||
import { AppConfig } from './types/config'
|
||||
import { serverOf, serverStart } from './server'
|
||||
|
||||
dotenv.config()
|
||||
|
||||
const server = serverOf()
|
||||
|
||||
const appConfig: AppConfig = {
|
||||
host: process.env.HOST || 'localhost',
|
||||
port: process.env.PORT ? parseInt(process.env.PORT) : 3000,
|
||||
mongoConnectionString: process.env.MONGO_CONNECTION_STRING || ''
|
||||
}
|
||||
|
||||
serverStart(appConfig)(server)
|
||||
.then(() => {
|
||||
console.log(`Server listening on ${appConfig.host}:${appConfig.port}`)
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error(err)
|
||||
})
|
||||
30
backend/src/models/todo.ts
Normal file
30
backend/src/models/todo.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
import mongoose from 'mongoose'
|
||||
|
||||
import { Todo } from '../types/todo'
|
||||
|
||||
const todoSchema: mongoose.Schema = new mongoose.Schema(
|
||||
{
|
||||
name: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
description: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
status: {
|
||||
type: Boolean,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
{
|
||||
timestamps: true
|
||||
}
|
||||
)
|
||||
|
||||
todoSchema.set('toJSON', {
|
||||
virtuals: true,
|
||||
versionKey: false
|
||||
})
|
||||
|
||||
export default mongoose.models.Todo || mongoose.model<Todo>('Todo', todoSchema)
|
||||
3
backend/src/plugins/mongodb.ts
Normal file
3
backend/src/plugins/mongodb.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
import mongoose from 'mongoose'
|
||||
|
||||
export const establishConnection = (connectionString: string) => mongoose.connect(connectionString)
|
||||
14
backend/src/repo/todo.ts
Normal file
14
backend/src/repo/todo.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import { ModifyResult, UpdateQuery } from 'mongoose'
|
||||
|
||||
import TodoModel from '../models/todo'
|
||||
import { Todo, TodoBody } from '../types/todo'
|
||||
|
||||
export const findAllTodos: () => Promise<Array<Todo>> = () => TodoModel.find().exec()
|
||||
|
||||
export const createTodo: (todoBody: TodoBody) => Promise<Todo> = (todoBody) => TodoModel.create(todoBody)
|
||||
|
||||
export const updateTodoById: (id: string, update: UpdateQuery<TodoBody>) => Promise<Todo | null> = (id, update) =>
|
||||
TodoModel.findByIdAndUpdate(id, update, { new: true })
|
||||
|
||||
export const deleteTodoById: (id: string) => Promise<ModifyResult<Todo>> = (id) =>
|
||||
TodoModel.findByIdAndDelete(id).exec()
|
||||
67
backend/src/routes/todo.ts
Normal file
67
backend/src/routes/todo.ts
Normal file
@@ -0,0 +1,67 @@
|
||||
import { FastifyInstance, RouteShorthandOptions } from 'fastify'
|
||||
|
||||
import { addTodo, deleteTodo, getTodos, updateTodoStatus } from '../services/todo'
|
||||
import { TodoBody } from '../types/todo'
|
||||
|
||||
export const TodoRouter = (server: FastifyInstance, opts: RouteShorthandOptions, done: (error?: Error) => void) => {
|
||||
interface IdParam {
|
||||
id: string
|
||||
}
|
||||
interface StatusBody {
|
||||
status: boolean
|
||||
}
|
||||
|
||||
server.get('/v1/todos', async (request, reply) => {
|
||||
try {
|
||||
const todos = await getTodos()
|
||||
return reply.status(200).send({ todos })
|
||||
} catch (error) {
|
||||
server.log.error(`GET /v1/todos Error: ${error}`)
|
||||
return reply.status(500).send(`[Server Error]: ${error}`)
|
||||
}
|
||||
})
|
||||
|
||||
server.post<{ Body: TodoBody }>('/v1/todos', async (request, reply) => {
|
||||
try {
|
||||
const todoBody = request.body
|
||||
const todo = await addTodo(todoBody)
|
||||
return reply.status(201).send({ todo })
|
||||
} catch (error) {
|
||||
server.log.error(`POST /v1/todos Error: ${error}`)
|
||||
return reply.status(500).send(`[Server Error]: ${error}`)
|
||||
}
|
||||
})
|
||||
|
||||
server.put<{ Params: IdParam; Body: StatusBody }>('/v1/todos/:id', opts, async (request, reply) => {
|
||||
try {
|
||||
const id = request.params.id
|
||||
const status = request.body.status
|
||||
const todo = await updateTodoStatus(id, status)
|
||||
if (todo) {
|
||||
return reply.status(200).send({ todo })
|
||||
} else {
|
||||
return reply.status(404).send({ msg: `Not Found Todo:${id}` })
|
||||
}
|
||||
} catch (error) {
|
||||
server.log.error(`PUT /v1/todos/${request.params.id} Error: ${error}`)
|
||||
return reply.status(500).send(`[Server Error]: ${error}`)
|
||||
}
|
||||
})
|
||||
|
||||
server.delete<{ Params: IdParam }>('/v1/todos/:id', opts, async (request, reply) => {
|
||||
try {
|
||||
const id = request.params.id
|
||||
const todo = await deleteTodo(id)
|
||||
if (todo) {
|
||||
return reply.status(204).send()
|
||||
} else {
|
||||
return reply.status(404).send({ msg: `Not Found Todo:${id}` })
|
||||
}
|
||||
} catch (error) {
|
||||
server.log.error(`DELETE /v1/todos/${request.params.id} Error: ${error}`)
|
||||
return reply.status(500).send(`[Server Error]: ${error}`)
|
||||
}
|
||||
})
|
||||
|
||||
done()
|
||||
}
|
||||
27
backend/src/server.ts
Normal file
27
backend/src/server.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
import fastify, { FastifyInstance, FastifyListenOptions } from 'fastify'
|
||||
import { AppConfig } from './types/config'
|
||||
import { establishConnection } from './plugins/mongodb'
|
||||
import { TodoRouter } from './routes/todo'
|
||||
|
||||
export const serverOf: () => FastifyInstance = () => {
|
||||
const server = fastify()
|
||||
|
||||
server.get('/ping', async (request, reply) => {
|
||||
return reply.status(200).send({ msg: 'pong!' })
|
||||
})
|
||||
|
||||
server.register(TodoRouter, { prefix: '/api' })
|
||||
|
||||
return server
|
||||
}
|
||||
|
||||
export const serverStart: (appConfig: AppConfig) => (server: FastifyInstance) => Promise<FastifyInstance> =
|
||||
(appConfig) => async (server) => {
|
||||
await establishConnection(appConfig.mongoConnectionString)
|
||||
const listenOptions: FastifyListenOptions = {
|
||||
port: appConfig.port,
|
||||
host: appConfig.host
|
||||
}
|
||||
await server.listen(listenOptions)
|
||||
return server
|
||||
}
|
||||
25
backend/src/services/todo.ts
Normal file
25
backend/src/services/todo.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
import { ModifyResult } from 'mongoose'
|
||||
|
||||
import * as repo from '../repo/todo'
|
||||
import { Todo, TodoBody } from '../types/todo'
|
||||
|
||||
export const getTodos: () => Promise<Array<Todo>> = async () => {
|
||||
const todos = await repo.findAllTodos()
|
||||
return todos
|
||||
}
|
||||
|
||||
export const addTodo: (todoBody: TodoBody) => Promise<Todo> = async (todoBody) => {
|
||||
const newTodo = await repo.createTodo({
|
||||
...todoBody
|
||||
})
|
||||
return newTodo
|
||||
}
|
||||
|
||||
export const updateTodoStatus: (id: string, newStatus: boolean) => Promise<Todo | null> = async (id, newStatus) => {
|
||||
const todo = await repo.updateTodoById(id, { status: newStatus })
|
||||
return todo
|
||||
}
|
||||
export const deleteTodo: (id: string) => Promise<ModifyResult<Todo>> = async (id) => {
|
||||
const result = await repo.deleteTodoById(id)
|
||||
return result
|
||||
}
|
||||
5
backend/src/types/config.ts
Normal file
5
backend/src/types/config.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
export type AppConfig = {
|
||||
port: number
|
||||
host: string
|
||||
mongoConnectionString: string
|
||||
}
|
||||
8
backend/src/types/todo.ts
Normal file
8
backend/src/types/todo.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
export type Todo = {
|
||||
id: string
|
||||
name: string
|
||||
description: string
|
||||
status: boolean
|
||||
}
|
||||
|
||||
export type TodoBody = Omit<Todo, 'id'>
|
||||
Reference in New Issue
Block a user