Created
September 19, 2021 20:36
-
-
Save gpDA/3e4e87381d1109b3c1245420561c9002 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Things to go over | |
// 1 - mongodb (mongoose ORM) list of strings & default | |
// 2 - router middleware (koa) | |
// 3 - CRUD (with simple validation) write / read /remove / update | |
////\\\\ | |
// models/post.js | |
////\\\\ | |
const mongoose = require('mongoose'); | |
const { Schema } = mongoose; | |
const Post = new Schema({ | |
title: String, | |
body: String, | |
tags: [String], // list of strings | |
publishedDate: { | |
type: Date, | |
default: new Date() // current date default | |
////\\\\ | |
// api/posts/index.js | |
////\\\\ | |
const Router = require('koa-router'); | |
const postsCtrl = require('./posts.ctrl'); | |
const posts = new Router(); | |
posts.get('/', postsCtrl.list); | |
posts.get('/:id', postsCtrl.checkObjectId, postsCtrl.read); | |
posts.post('/', postsCtrl.write); | |
posts.delete('/:id', postsCtrl.checkObjectId, postsCtrl.remove); | |
posts.patch('/:id', postsCtrl.checkObjectId, postsCtrl.update); | |
module.exports = posts; | |
} | |
}); | |
module.exports = mongoose.model('Post', Post); | |
////\\\\ | |
// api/posts/posts.ctrl.js | |
////\\\\ | |
const Post = require('models/post'); | |
const Joi = require('joi'); | |
const { ObjectId } = require('mongoose').Types; | |
exports.checkObjectId = (ctx, next) => { | |
const { id } = ctx.params; | |
// validation | |
if (!ObjectId.isValid(id)) { | |
ctx.status = 400; // 400 Bad Request | |
return null; | |
} | |
return next(); // return next to execute the next ctx.body | |
}; | |
/* | |
POST /api/posts | |
{ title, body, tags } | |
*/ | |
exports.write = async (ctx) => { | |
// required validation | |
const schema = Joi.object().keys({ | |
title: Joi.string().required(), | |
body: Joi.string().required(), | |
tags: Joi.array().items(Joi.string()).required() | |
}); | |
// validation | |
const result = Joi.validate(ctx.request.body, schema); | |
// error | |
if (result.error) { | |
ctx.status = 400; | |
ctx.body = result.error; | |
return; | |
} | |
const { title, body, tags } = ctx.request.body; | |
// new Post instance | |
const post = new Post({ | |
title, body, tags | |
}); | |
try { | |
await post.save(); // save to database | |
ctx.body = post; // return saved data | |
} catch (e) { | |
// database error | |
ctx.throw(e, 500); | |
} | |
}; | |
/* | |
GET /api/posts | |
*/ | |
exports.list = async (ctx) => { | |
// default page: 1 | |
const page = parseInt(ctx.query.page || 1, 10); | |
const { tag } = ctx.query; | |
const query = tag ? { | |
tags: tag // filter by tag from tags list | |
} : {}; | |
// if given page number is wrong | |
if (page < 1) { | |
ctx.status = 400; | |
return; | |
} | |
try { | |
const posts = await Post.find(query) | |
.sort({ _id: -1 }) | |
.limit(3) | |
.skip((page - 1) * 3) | |
.lean() | |
.exec(); | |
const postCount = await Post.countDocuments(query).exec(); | |
const limitBodyLength = post => ({ | |
...post, | |
body: post.body.length < 350 ? post.body : `${post.body.slice(0, 350)}...` | |
}); | |
ctx.body = posts.map(limitBodyLength); | |
// if last page | |
// set the `last page` as a response header | |
ctx.set('Last-Page', Math.ceil(postCount / 3)); | |
} catch (e) { | |
ctx.throw(500, e); | |
} | |
}; | |
/* | |
GET /api/posts/:id | |
*/ | |
exports.read = async (ctx) => { | |
const { id } = ctx.params; | |
try { | |
const post = await Post.findById(id).exec(); | |
// post not exists | |
if (!post) { | |
ctx.status = 404; | |
return; | |
} | |
ctx.body = post; | |
} catch (e) { | |
ctx.throw(e, 500); | |
} | |
}; | |
/* | |
DELETE /api/posts/:id | |
*/ | |
exports.remove = async (ctx) => { | |
const { id } = ctx.params; | |
try { | |
await Post.findByIdAndRemove(id).exec(); | |
ctx.status = 204; | |
} catch (e) { | |
ctx.throw(e, 500); | |
} | |
}; | |
/* | |
PATCH /api/posts/:id | |
{ title, body, tags } | |
*/ | |
exports.update = async (ctx) => { | |
const { id } = ctx.params; | |
try { | |
const post = await Post.findByIdAndUpdate(id, ctx.request.body, { | |
new: true | |
// return updated object | |
}).exec(); | |
// if no post exists | |
if (!post) { | |
ctx.status = 404; | |
return; | |
} | |
ctx.body = post; | |
} catch (e) { | |
ctx.throw(e, 500); | |
} | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment