├── blog-frontend ├── .env ├── .browserslistrc ├── babel.config.js ├── public │ ├── css │ │ └── style.css │ ├── favicon.ico │ └── index.html ├── src │ ├── utils │ │ └── helper.js │ ├── assets │ │ └── logo.png │ ├── main.js │ ├── App.vue │ ├── router.js │ ├── components │ │ └── post │ │ │ ├── Post.vue │ │ │ ├── Create.vue │ │ │ └── Edit.vue │ └── views │ │ └── Home.vue ├── postcss.config.js ├── .gitignore ├── README.md ├── .eslintrc.js └── package.json ├── blog-backend ├── .prettierrc ├── nodemon.json ├── tsconfig.spec.json ├── src │ ├── app.service.ts │ ├── blog │ │ ├── dto │ │ │ └── create-post.dto.ts │ │ ├── schemas │ │ │ └── blog.schema.ts │ │ ├── interfaces │ │ │ └── post.interface.ts │ │ ├── blog.module.ts │ │ ├── blog.service.spec.ts │ │ ├── blog.controller.spec.ts │ │ ├── blog.service.ts │ │ └── blog.controller.ts │ ├── main.ts │ ├── app.controller.ts │ ├── shared │ │ └── pipes │ │ │ └── validate-object-id.pipes.ts │ ├── app.module.ts │ └── app.controller.spec.ts ├── nodemon-debug.json ├── test │ ├── jest-e2e.json │ └── app.e2e-spec.ts ├── tsconfig.json ├── tslint.json ├── package.json ├── README.md └── .gitignore ├── .gitignore └── README.md /blog-frontend/.env: -------------------------------------------------------------------------------- 1 | baseURL=http://localhost:3000 -------------------------------------------------------------------------------- /blog-frontend/.browserslistrc: -------------------------------------------------------------------------------- 1 | > 1% 2 | last 2 versions 3 | not ie <= 8 4 | -------------------------------------------------------------------------------- /blog-backend/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true, 3 | "trailingComma": "all" 4 | } -------------------------------------------------------------------------------- /blog-frontend/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | '@vue/app' 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /blog-frontend/public/css/style.css: -------------------------------------------------------------------------------- 1 | .form-wrapper { 2 | width: 500px; 3 | margin: 0 auto; 4 | } -------------------------------------------------------------------------------- /blog-frontend/src/utils/helper.js: -------------------------------------------------------------------------------- 1 | export const server = { 2 | baseURL: 'http://localhost:3000' 3 | } -------------------------------------------------------------------------------- /blog-frontend/postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | autoprefixer: {} 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /blog-frontend/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/do-community/nest-vue-project/HEAD/blog-frontend/public/favicon.ico -------------------------------------------------------------------------------- /blog-frontend/src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/do-community/nest-vue-project/HEAD/blog-frontend/src/assets/logo.png -------------------------------------------------------------------------------- /blog-backend/nodemon.json: -------------------------------------------------------------------------------- 1 | { 2 | "watch": ["src"], 3 | "ext": "ts", 4 | "ignore": ["src/**/*.spec.ts"], 5 | "exec": "ts-node -r tsconfig-paths/register src/main.ts" 6 | } 7 | -------------------------------------------------------------------------------- /blog-backend/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "tsconfig.json", 3 | "compilerOptions": { 4 | "types": ["jest", "node"] 5 | }, 6 | "include": ["**/*.spec.ts", "**/*.d.ts"] 7 | } 8 | -------------------------------------------------------------------------------- /blog-backend/src/app.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@nestjs/common'; 2 | 3 | @Injectable() 4 | export class AppService { 5 | root(): string { 6 | return 'Hello World!'; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /blog-backend/nodemon-debug.json: -------------------------------------------------------------------------------- 1 | { 2 | "watch": ["src"], 3 | "ext": "ts", 4 | "ignore": ["src/**/*.spec.ts"], 5 | "exec": "node --inspect-brk -r ts-node/register -r tsconfig-paths/register src/main.ts" 6 | } 7 | -------------------------------------------------------------------------------- /blog-backend/src/blog/dto/create-post.dto.ts: -------------------------------------------------------------------------------- 1 | export class CreatePostDTO { 2 | readonly title: string; 3 | readonly description: string; 4 | readonly body: string; 5 | readonly author: string; 6 | readonly date_posted: string 7 | } -------------------------------------------------------------------------------- /blog-frontend/src/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import App from './App.vue' 3 | import router from './router' 4 | 5 | Vue.config.productionTip = false 6 | 7 | new Vue({ 8 | router, 9 | render: h => h(App) 10 | }).$mount('#app') 11 | -------------------------------------------------------------------------------- /blog-backend/test/jest-e2e.json: -------------------------------------------------------------------------------- 1 | { 2 | "moduleFileExtensions": ["js", "json", "ts"], 3 | "rootDir": ".", 4 | "testEnvironment": "node", 5 | "testRegex": ".e2e-spec.ts$", 6 | "transform": { 7 | "^.+\\.(t|j)s$": "ts-jest" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /blog-backend/src/blog/schemas/blog.schema.ts: -------------------------------------------------------------------------------- 1 | import * as mongoose from 'mongoose'; 2 | 3 | export const BlogSchema = new mongoose.Schema({ 4 | title: String, 5 | description: String, 6 | body: String, 7 | author: String, 8 | date_posted: String 9 | }) -------------------------------------------------------------------------------- /blog-backend/src/main.ts: -------------------------------------------------------------------------------- 1 | import { NestFactory } from '@nestjs/core'; 2 | import { AppModule } from './app.module'; 3 | 4 | async function bootstrap() { 5 | const app = await NestFactory.create(AppModule); 6 | app.enableCors(); 7 | await app.listen(3000); 8 | } 9 | bootstrap(); 10 | -------------------------------------------------------------------------------- /blog-backend/src/blog/interfaces/post.interface.ts: -------------------------------------------------------------------------------- 1 | import { Document } from 'mongoose'; 2 | 3 | export interface Post extends Document { 4 | readonly title: string; 5 | readonly description: string; 6 | readonly body: string; 7 | readonly author: string; 8 | readonly date_posted: string 9 | } -------------------------------------------------------------------------------- /blog-frontend/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | 5 | # local env files 6 | .env.local 7 | .env.*.local 8 | 9 | # Log files 10 | npm-debug.log* 11 | yarn-debug.log* 12 | yarn-error.log* 13 | 14 | # Editor directories and files 15 | .idea 16 | .vscode 17 | *.suo 18 | *.ntvs* 19 | *.njsproj 20 | *.sln 21 | *.sw* 22 | -------------------------------------------------------------------------------- /blog-backend/src/app.controller.ts: -------------------------------------------------------------------------------- 1 | import { Get, Controller } from '@nestjs/common'; 2 | import { AppService } from './app.service'; 3 | 4 | @Controller() 5 | export class AppController { 6 | constructor(private readonly appService: AppService) {} 7 | 8 | @Get() 9 | root(): string { 10 | return this.appService.root(); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /blog-frontend/README.md: -------------------------------------------------------------------------------- 1 | # blog-frontend 2 | 3 | ## Project setup 4 | ``` 5 | npm install 6 | ``` 7 | 8 | ### Compiles and hot-reloads for development 9 | ``` 10 | npm run serve 11 | ``` 12 | 13 | ### Compiles and minifies for production 14 | ``` 15 | npm run build 16 | ``` 17 | 18 | ### Lints and fixes files 19 | ``` 20 | npm run lint 21 | ``` 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | node_modules/ 5 | 6 | # testing 7 | /coverage 8 | 9 | # production 10 | /build 11 | 12 | # misc 13 | .DS_Store 14 | .env.local 15 | .env.development.local 16 | .env.test.local 17 | .env.production.local 18 | 19 | npm-debug.log* 20 | yarn-debug.log* 21 | yarn-error.log* 22 | 23 | # webstorm files 24 | .idea/ -------------------------------------------------------------------------------- /blog-frontend/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | env: { 4 | node: true 5 | }, 6 | 'extends': [ 7 | 'plugin:vue/essential', 8 | 'eslint:recommended' 9 | ], 10 | rules: { 11 | 'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off', 12 | 'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off' 13 | }, 14 | parserOptions: { 15 | parser: 'babel-eslint' 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /blog-backend/src/blog/blog.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { BlogController } from './blog.controller'; 3 | import { BlogService } from './blog.service'; 4 | import { MongooseModule } from '@nestjs/mongoose'; 5 | import { BlogSchema } from './schemas/blog.schema'; 6 | 7 | @Module({ 8 | imports: [ 9 | MongooseModule.forFeature([{ name: 'Post', schema: BlogSchema }]) 10 | ], 11 | controllers: [BlogController], 12 | providers: [BlogService] 13 | }) 14 | export class BlogModule { } -------------------------------------------------------------------------------- /blog-backend/src/shared/pipes/validate-object-id.pipes.ts: -------------------------------------------------------------------------------- 1 | import { PipeTransform, Injectable, ArgumentMetadata, BadRequestException } from '@nestjs/common'; 2 | import * as mongoose from 'mongoose'; 3 | 4 | @Injectable() 5 | export class ValidateObjectId implements PipeTransform { 6 | async transform(value: string, metadata: ArgumentMetadata) { 7 | const isValid = mongoose.Types.ObjectId.isValid(value); 8 | if (!isValid) throw new BadRequestException('Invalid ID!'); 9 | return value; 10 | } 11 | } -------------------------------------------------------------------------------- /blog-backend/src/app.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { AppController } from './app.controller'; 3 | import { AppService } from './app.service'; 4 | import { MongooseModule } from '@nestjs/mongoose'; 5 | import { BlogModule } from './blog/blog.module'; 6 | 7 | @Module({ 8 | imports: [ 9 | MongooseModule.forRoot('mongodb://localhost/nest-blog', { useNewUrlParser: true }), 10 | BlogModule, 11 | ], 12 | controllers: [AppController], 13 | providers: [AppService], 14 | }) 15 | export class AppModule { } -------------------------------------------------------------------------------- /blog-backend/src/blog/blog.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { Test, TestingModule } from '@nestjs/testing'; 2 | import { BlogService } from './blog.service'; 3 | 4 | describe('BlogService', () => { 5 | let service: BlogService; 6 | 7 | beforeAll(async () => { 8 | const module: TestingModule = await Test.createTestingModule({ 9 | providers: [BlogService], 10 | }).compile(); 11 | service = module.get(BlogService); 12 | }); 13 | it('should be defined', () => { 14 | expect(service).toBeDefined(); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /blog-backend/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "declaration": true, 5 | "noImplicitAny": false, 6 | "removeComments": true, 7 | "noLib": false, 8 | "allowSyntheticDefaultImports": true, 9 | "emitDecoratorMetadata": true, 10 | "experimentalDecorators": true, 11 | "target": "es6", 12 | "sourceMap": true, 13 | "outDir": "./dist", 14 | "baseUrl": "./" 15 | }, 16 | "include": [ 17 | "src/**/*" 18 | ], 19 | "exclude": [ 20 | "node_modules", 21 | "**/*.spec.ts" 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /blog-backend/src/blog/blog.controller.spec.ts: -------------------------------------------------------------------------------- 1 | import { Test, TestingModule } from '@nestjs/testing'; 2 | import { BlogController } from './blog.controller'; 3 | 4 | describe('Blog Controller', () => { 5 | let module: TestingModule; 6 | 7 | beforeAll(async () => { 8 | module = await Test.createTestingModule({ 9 | controllers: [BlogController], 10 | }).compile(); 11 | }); 12 | it('should be defined', () => { 13 | const controller: BlogController = module.get(BlogController); 14 | expect(controller).toBeDefined(); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /blog-frontend/src/App.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 32 | -------------------------------------------------------------------------------- /blog-frontend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "blog-frontend", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "serve": "vue-cli-service serve", 7 | "build": "vue-cli-service build", 8 | "lint": "vue-cli-service lint" 9 | }, 10 | "dependencies": { 11 | "axios": "^0.18.0", 12 | "vue": "^2.5.17", 13 | "vue-router": "^3.0.1" 14 | }, 15 | "devDependencies": { 16 | "@vue/cli-plugin-babel": "^3.0.3", 17 | "@vue/cli-plugin-eslint": "^3.0.3", 18 | "@vue/cli-service": "^3.0.3", 19 | "babel-eslint": "^10.0.1", 20 | "eslint": "^5.8.0", 21 | "eslint-plugin-vue": "^5.0.0-0", 22 | "vue-template-compiler": "^2.5.17" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /blog-backend/src/app.controller.spec.ts: -------------------------------------------------------------------------------- 1 | import { Test, TestingModule } from '@nestjs/testing'; 2 | import { AppController } from './app.controller'; 3 | import { AppService } from './app.service'; 4 | 5 | describe('AppController', () => { 6 | let app: TestingModule; 7 | 8 | beforeAll(async () => { 9 | app = await Test.createTestingModule({ 10 | controllers: [AppController], 11 | providers: [AppService], 12 | }).compile(); 13 | }); 14 | 15 | describe('root', () => { 16 | it('should return "Hello World!"', () => { 17 | const appController = app.get(AppController); 18 | expect(appController.root()).toBe('Hello World!'); 19 | }); 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /blog-backend/test/app.e2e-spec.ts: -------------------------------------------------------------------------------- 1 | import { INestApplication } from '@nestjs/common'; 2 | import { Test } from '@nestjs/testing'; 3 | import * as request from 'supertest'; 4 | import { AppModule } from './../src/app.module'; 5 | 6 | describe('AppController (e2e)', () => { 7 | let app: INestApplication; 8 | 9 | beforeAll(async () => { 10 | const moduleFixture = await Test.createTestingModule({ 11 | imports: [AppModule], 12 | }).compile(); 13 | 14 | app = moduleFixture.createNestApplication(); 15 | await app.init(); 16 | }); 17 | 18 | it('/ (GET)', () => { 19 | return request(app.getHttpServer()) 20 | .get('/') 21 | .expect(200) 22 | .expect('Hello World!'); 23 | }); 24 | }); 25 | -------------------------------------------------------------------------------- /blog-frontend/src/router.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Router from 'vue-router' 3 | import HomeComponent from '@/views/Home'; 4 | import EditComponent from '@/components/post/Edit'; 5 | import CreateComponent from '@/components/post/Create'; 6 | import PostComponent from '@/components/post/Post'; 7 | 8 | Vue.use(Router) 9 | 10 | export default new Router({ 11 | mode: 'history', 12 | base: process.env.BASE_URL, 13 | routes: [ 14 | { path: '/', redirect: { name: 'home' } }, 15 | { path: '/home', name: 'home', component: HomeComponent }, 16 | { path: '/create', name: 'Create', component: CreateComponent }, 17 | { path: '/edit/:id', name: 'Edit', component: EditComponent }, 18 | { path: '/post/:id', name: 'Post', component: PostComponent } 19 | ] 20 | }); -------------------------------------------------------------------------------- /blog-frontend/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | blog-frontend 12 | 13 | 14 | 15 | 18 |
19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /blog-frontend/src/components/post/Post.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 41 | 42 | -------------------------------------------------------------------------------- /blog-backend/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "defaultSeverity": "error", 3 | "extends": [ 4 | "tslint:recommended" 5 | ], 6 | "jsRules": { 7 | "no-unused-expression": true 8 | }, 9 | "rules": { 10 | "eofline": false, 11 | "quotemark": [ 12 | true, 13 | "single" 14 | ], 15 | "indent": false, 16 | "member-access": [ 17 | false 18 | ], 19 | "ordered-imports": [ 20 | false 21 | ], 22 | "max-line-length": [ 23 | true, 24 | 150 25 | ], 26 | "member-ordering": [ 27 | false 28 | ], 29 | "curly": false, 30 | "interface-name": [ 31 | false 32 | ], 33 | "array-type": [ 34 | false 35 | ], 36 | "no-empty-interface": false, 37 | "no-empty": false, 38 | "arrow-parens": false, 39 | "object-literal-sort-keys": false, 40 | "no-unused-expression": false, 41 | "max-classes-per-file": [ 42 | false 43 | ], 44 | "variable-name": [ 45 | false 46 | ], 47 | "one-line": [ 48 | false 49 | ], 50 | "one-variable-per-declaration": [ 51 | false 52 | ] 53 | }, 54 | "rulesDirectory": [] 55 | } 56 | -------------------------------------------------------------------------------- /blog-backend/src/blog/blog.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@nestjs/common'; 2 | import { Model } from 'mongoose'; 3 | import { InjectModel } from '@nestjs/mongoose'; 4 | import { Post } from './interfaces/post.interface'; 5 | import { CreatePostDTO } from './dto/create-post.dto'; 6 | 7 | @Injectable() 8 | export class BlogService { 9 | 10 | constructor(@InjectModel('Post') private readonly postModel: Model) { } 11 | 12 | async getPosts(): Promise { 13 | const posts = await this.postModel.find().exec(); 14 | return posts; 15 | } 16 | 17 | async getPost(postID): Promise { 18 | const post = await this.postModel 19 | .findById(postID) 20 | .exec(); 21 | return post; 22 | } 23 | 24 | async addPost(createPostDTO: CreatePostDTO): Promise { 25 | const newPost = await this.postModel(createPostDTO); 26 | return newPost.save(); 27 | } 28 | 29 | async editPost(postID, createPostDTO: CreatePostDTO): Promise { 30 | const editedPost = await this.postModel 31 | .findByIdAndUpdate(postID, createPostDTO, { new: true }); 32 | return editedPost; 33 | } 34 | 35 | async deletePost(postID): Promise { 36 | const deletedPost = await this.postModel 37 | .findByIdAndRemove(postID); 38 | return deletedPost; 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /blog-backend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "blog-backend", 3 | "version": "0.0.0", 4 | "description": "Backend API for a blog built with Nest.jss", 5 | "author": "Olususi Oluyemi", 6 | "license": "MIT", 7 | "scripts": { 8 | "build": "tsc", 9 | "format": "prettier --write \"src/**/*.ts\"", 10 | "start": "ts-node -r tsconfig-paths/register src/main.ts", 11 | "start:dev": "nodemon", 12 | "start:debug": "nodemon --config nodemon-debug.json", 13 | "prestart:prod": "rimraf dist && tsc", 14 | "start:prod": "node dist/main.js", 15 | "lint": "tslint -p tsconfig.json -c tslint.json", 16 | "test": "jest", 17 | "test:watch": "jest --watch", 18 | "test:cov": "jest --coverage", 19 | "test:e2e": "jest --config ./test/jest-e2e.json" 20 | }, 21 | "dependencies": { 22 | "@nestjs/common": "^5.4.0", 23 | "@nestjs/core": "^5.4.0", 24 | "@nestjs/mongoose": "^5.2.2", 25 | "mongoose": "^5.4.0", 26 | "reflect-metadata": "^0.1.12", 27 | "rimraf": "^2.6.2", 28 | "rxjs": "^6.2.2", 29 | "typescript": "^3.0.1" 30 | }, 31 | "devDependencies": { 32 | "@nestjs/testing": "^5.1.0", 33 | "@types/express": "^4.16.0", 34 | "@types/jest": "^23.3.1", 35 | "@types/node": "^10.7.1", 36 | "@types/supertest": "^2.0.5", 37 | "jest": "^23.5.0", 38 | "nodemon": "^1.18.3", 39 | "prettier": "^1.14.2", 40 | "supertest": "^3.1.0", 41 | "ts-jest": "^23.1.3", 42 | "ts-loader": "^4.4.2", 43 | "ts-node": "^7.0.1", 44 | "tsconfig-paths": "^3.5.0", 45 | "tslint": "5.11.0" 46 | }, 47 | "jest": { 48 | "moduleFileExtensions": [ 49 | "js", 50 | "json", 51 | "ts" 52 | ], 53 | "rootDir": "src", 54 | "testRegex": ".spec.ts$", 55 | "transform": { 56 | "^.+\\.(t|j)s$": "ts-jest" 57 | }, 58 | "coverageDirectory": "../coverage", 59 | "testEnvironment": "node" 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Build a blog using Nest.js, Vue.js and MongoDB 2 | 3 | Application repo for a simple blog application built with Nest.js, Vue.js and MongoDB. 4 | 5 | ## Getting Started 6 | This prototype is divided into two separate sections. Namely the Backend ( Built with Nest.js) and the frontend 7 | ( Built with Vue.js ). 8 | 9 | ### Clone the repository 10 | To easily set up the application, clone this repository which contains directory for both sections of the project ( i.e `blog-backend` and `blog-frontend`) 11 | 12 | ```bash 13 | git clone https://github.com/yemiwebby/nest-vue-project.git 14 | ``` 15 | 16 | ## Change directory into the newly cloned project 17 | ```bash 18 | cd nest-vue-project 19 | ``` 20 | 21 | ## Backend 22 | ### Change directory into the backend 23 | ```bash 24 | cd blog-backend 25 | ``` 26 | 27 | ### Install backend dependencies 28 | 29 | ```bash 30 | npm install 31 | ``` 32 | 33 | ### MongoDB 34 | Ensure that you have mongoDB installed on your machine before running the application. I have this fully setup on my mac already. 35 | 36 | Start mongoDB: 37 | 38 | ```bash 39 | sudo mongod 40 | ``` 41 | 42 | ### Run the application 43 | Open another terminal and still within the `blog-backend` project directory run the application with: 44 | 45 | ```bash 46 | npm run start:dev 47 | ``` 48 | 49 | This will start the backend application on port `3000`. 50 | 51 | ## Frontend 52 | Open another terminal from the `nest-vue-project` and navigate to the `blog-frontend` folder to setup the frontend 53 | 54 | ### Frontend dependencies 55 | ```bash 56 | cd blog-frontend 57 | npm install 58 | ``` 59 | 60 | ### Run the frontend app 61 | 62 | ```bash 63 | npm run serve 64 | ``` 65 | 66 | ### Test the application 67 | Finally open your browser and view the application on http://localhost:8080 68 | 69 | ## Prerequisites 70 | [Node.js](https://nodejs.org/en/), [Npm](https://www.npmjs.com/), [MongoDB](https://docs.mongodb.com/v3.2/installation/) 71 | 72 | ## Built With 73 | [Nest.js](https://nestjs.com/) 74 | [Vue.js](https://vuejs.org/) 75 | [MongoDB]() -------------------------------------------------------------------------------- /blog-frontend/src/views/Home.vue: -------------------------------------------------------------------------------- 1 | 38 | 39 | 68 | 69 | -------------------------------------------------------------------------------- /blog-backend/src/blog/blog.controller.ts: -------------------------------------------------------------------------------- 1 | import { Controller, Get, Res, HttpStatus, Param, NotFoundException, Post, Body, Query, Put, Delete } from '@nestjs/common'; 2 | import { BlogService } from './blog.service'; 3 | import { CreatePostDTO } from './dto/create-post.dto'; 4 | import { ValidateObjectId } from '../shared/pipes/validate-object-id.pipes'; 5 | 6 | 7 | @Controller('blog') 8 | export class BlogController { 9 | 10 | constructor(private blogService: BlogService) { } 11 | 12 | // Fetch all posts 13 | @Get('posts') 14 | async getPosts(@Res() res) { 15 | const posts = await this.blogService.getPosts(); 16 | return res.status(HttpStatus.OK).json(posts); 17 | } 18 | 19 | // Fetch a particular post using ID 20 | @Get('post/:postID') 21 | async getPost(@Res() res, @Param('postID', new ValidateObjectId()) postID) { 22 | const post = await this.blogService.getPost(postID); 23 | if (!post) throw new NotFoundException('Post does not exist!'); 24 | return res.status(HttpStatus.OK).json(post); 25 | 26 | } 27 | 28 | // Submit a post 29 | @Post('/post') 30 | async addPost(@Res() res, @Body() createPostDTO: CreatePostDTO) { 31 | const newPost = await this.blogService.addPost(createPostDTO); 32 | return res.status(HttpStatus.OK).json({ 33 | message: "Post has been submitted successfully!", 34 | post: newPost 35 | }) 36 | } 37 | 38 | 39 | // Edit a particular post using ID 40 | @Put('/edit') 41 | async editPost( 42 | @Res() res, 43 | @Query('postID', new ValidateObjectId()) postID, 44 | @Body() createPostDTO: CreatePostDTO 45 | ) { 46 | const editedPost = await this.blogService.editPost(postID, createPostDTO); 47 | if (!editedPost) throw new NotFoundException('Post does not exist!'); 48 | return res.status(HttpStatus.OK).json({ 49 | message: 'Post has been successfully updated', 50 | post: editedPost 51 | }) 52 | } 53 | 54 | // Delete a post using ID 55 | @Delete('/delete') 56 | async deletePost(@Res() res, @Query('postID', new ValidateObjectId()) postID) { 57 | const deletedPost = await this.blogService.deletePost(postID); 58 | if (!deletedPost) throw new NotFoundException('Post does not exist!'); 59 | return res.status(HttpStatus.OK).json({ 60 | message: 'Post has been deleted!', 61 | post: deletedPost 62 | }) 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /blog-frontend/src/components/post/Create.vue: -------------------------------------------------------------------------------- 1 | 30 | 31 | 68 | 69 | -------------------------------------------------------------------------------- /blog-frontend/src/components/post/Edit.vue: -------------------------------------------------------------------------------- 1 | 35 | 36 | 78 | 79 | -------------------------------------------------------------------------------- /blog-backend/README.md: -------------------------------------------------------------------------------- 1 |

2 | Nest Logo 3 |

4 | 5 | [travis-image]: https://api.travis-ci.org/nestjs/nest.svg?branch=master 6 | [travis-url]: https://travis-ci.org/nestjs/nest 7 | [linux-image]: https://img.shields.io/travis/nestjs/nest/master.svg?label=linux 8 | [linux-url]: https://travis-ci.org/nestjs/nest 9 | 10 |

A progressive Node.js framework for building efficient and scalable server-side applications, heavily inspired by Angular.

11 |

12 | NPM Version 13 | Package License 14 | NPM Downloads 15 | Travis 16 | Linux 17 | Coverage 18 | Gitter 19 | Backers on Open Collective 20 | Sponsors on Open Collective 21 | 22 | 23 |

24 | 26 | 27 | ## Description 28 | 29 | [Nest](https://github.com/nestjs/nest) framework TypeScript starter repository. 30 | 31 | ## Installation 32 | 33 | ```bash 34 | $ npm install 35 | ``` 36 | 37 | ## Running the app 38 | 39 | ```bash 40 | # development 41 | $ npm run start 42 | 43 | # watch mode 44 | $ npm run start:dev 45 | 46 | # incremental rebuild (webpack) 47 | $ npm run webpack 48 | $ npm run start:hmr 49 | 50 | # production mode 51 | $ npm run start:prod 52 | ``` 53 | 54 | ## Test 55 | 56 | ```bash 57 | # unit tests 58 | $ npm run test 59 | 60 | # e2e tests 61 | $ npm run test:e2e 62 | 63 | # test coverage 64 | $ npm run test:cov 65 | ``` 66 | 67 | ## Support 68 | 69 | Nest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support). 70 | 71 | ## Stay in touch 72 | 73 | - Author - [Kamil Myśliwiec](https://kamilmysliwiec.com) 74 | - Website - [https://nestjs.com](https://nestjs.com/) 75 | - Twitter - [@nestframework](https://twitter.com/nestframework) 76 | 77 | ## License 78 | 79 | Nest is [MIT licensed](LICENSE). 80 | -------------------------------------------------------------------------------- /blog-backend/.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | ### JetBrains template 3 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm 4 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 5 | 6 | # User-specific stuff: 7 | .idea/**/workspace.xml 8 | .idea/**/tasks.xml 9 | .idea/dictionaries 10 | 11 | # Sensitive or high-churn files: 12 | .idea/**/dataSources/ 13 | .idea/**/dataSources.ids 14 | .idea/**/dataSources.xml 15 | .idea/**/dataSources.local.xml 16 | .idea/**/sqlDataSources.xml 17 | .idea/**/dynamic.xml 18 | .idea/**/uiDesigner.xml 19 | 20 | # Gradle: 21 | .idea/**/gradle.xml 22 | .idea/**/libraries 23 | 24 | # CMake 25 | cmake-build-debug/ 26 | 27 | # Mongo Explorer plugin: 28 | .idea/**/mongoSettings.xml 29 | 30 | ## File-based project format: 31 | *.iws 32 | 33 | ## Plugin-specific files: 34 | 35 | # IntelliJ 36 | out/ 37 | 38 | # mpeltonen/sbt-idea plugin 39 | .idea_modules/ 40 | 41 | # JIRA plugin 42 | atlassian-ide-plugin.xml 43 | 44 | # Cursive Clojure plugin 45 | .idea/replstate.xml 46 | 47 | # Crashlytics plugin (for Android Studio and IntelliJ) 48 | com_crashlytics_export_strings.xml 49 | crashlytics.properties 50 | crashlytics-build.properties 51 | fabric.properties 52 | ### VisualStudio template 53 | ## Ignore Visual Studio temporary files, build results, and 54 | ## files generated by popular Visual Studio add-ons. 55 | ## 56 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 57 | 58 | # User-specific files 59 | *.suo 60 | *.user 61 | *.userosscache 62 | *.sln.docstates 63 | 64 | # User-specific files (MonoDevelop/Xamarin Studio) 65 | *.userprefs 66 | 67 | # Build results 68 | [Dd]ebug/ 69 | [Dd]ebugPublic/ 70 | [Rr]elease/ 71 | [Rr]eleases/ 72 | x64/ 73 | x86/ 74 | bld/ 75 | [Bb]in/ 76 | [Oo]bj/ 77 | [Ll]og/ 78 | 79 | # Visual Studio 2015 cache/options directory 80 | .vs/ 81 | # Uncomment if you have tasks that create the project's static files in wwwroot 82 | #wwwroot/ 83 | 84 | # MSTest test Results 85 | [Tt]est[Rr]esult*/ 86 | [Bb]uild[Ll]og.* 87 | 88 | # NUNIT 89 | *.VisualState.xml 90 | TestResult.xml 91 | 92 | # Build Results of an ATL Project 93 | [Dd]ebugPS/ 94 | [Rr]eleasePS/ 95 | dlldata.c 96 | 97 | # Benchmark Results 98 | BenchmarkDotNet.Artifacts/ 99 | 100 | # .NET Core 101 | project.lock.json 102 | project.fragment.lock.json 103 | artifacts/ 104 | **/Properties/launchSettings.json 105 | 106 | *_i.c 107 | *_p.c 108 | *_i.h 109 | *.ilk 110 | *.meta 111 | *.obj 112 | *.pch 113 | *.pdb 114 | *.pgc 115 | *.pgd 116 | *.rsp 117 | *.sbr 118 | *.tlb 119 | *.tli 120 | *.tlh 121 | *.tmp 122 | *.tmp_proj 123 | *.log 124 | *.vspscc 125 | *.vssscc 126 | .builds 127 | *.pidb 128 | *.svclog 129 | *.scc 130 | 131 | # Chutzpah Test files 132 | _Chutzpah* 133 | 134 | # Visual C++ cache files 135 | ipch/ 136 | *.aps 137 | *.ncb 138 | *.opendb 139 | *.opensdf 140 | *.sdf 141 | *.cachefile 142 | *.VC.db 143 | *.VC.VC.opendb 144 | 145 | # Visual Studio profiler 146 | *.psess 147 | *.vsp 148 | *.vspx 149 | *.sap 150 | 151 | # Visual Studio Trace Files 152 | *.e2e 153 | 154 | # TFS 2012 Local Workspace 155 | $tf/ 156 | 157 | # Guidance Automation Toolkit 158 | *.gpState 159 | 160 | # ReSharper is a .NET coding add-in 161 | _ReSharper*/ 162 | *.[Rr]e[Ss]harper 163 | *.DotSettings.user 164 | 165 | # JustCode is a .NET coding add-in 166 | .JustCode 167 | 168 | # TeamCity is a build add-in 169 | _TeamCity* 170 | 171 | # DotCover is a Code Coverage Tool 172 | *.dotCover 173 | 174 | # AxoCover is a Code Coverage Tool 175 | .axoCover/* 176 | !.axoCover/settings.json 177 | 178 | # Visual Studio code coverage results 179 | *.coverage 180 | *.coveragexml 181 | 182 | # NCrunch 183 | _NCrunch_* 184 | .*crunch*.local.xml 185 | nCrunchTemp_* 186 | 187 | # MightyMoose 188 | *.mm.* 189 | AutoTest.Net/ 190 | 191 | # Web workbench (sass) 192 | .sass-cache/ 193 | 194 | # Installshield output folder 195 | [Ee]xpress/ 196 | 197 | # DocProject is a documentation generator add-in 198 | DocProject/buildhelp/ 199 | DocProject/Help/*.HxT 200 | DocProject/Help/*.HxC 201 | DocProject/Help/*.hhc 202 | DocProject/Help/*.hhk 203 | DocProject/Help/*.hhp 204 | DocProject/Help/Html2 205 | DocProject/Help/html 206 | 207 | # Click-Once directory 208 | publish/ 209 | 210 | # Publish Web Output 211 | *.[Pp]ublish.xml 212 | *.azurePubxml 213 | # Note: Comment the next line if you want to checkin your web deploy settings, 214 | # but database connection strings (with potential passwords) will be unencrypted 215 | *.pubxml 216 | *.publishproj 217 | 218 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 219 | # checkin your Azure Web App publish settings, but sensitive information contained 220 | # in these scripts will be unencrypted 221 | PublishScripts/ 222 | 223 | # NuGet Packages 224 | *.nupkg 225 | # The packages folder can be ignored because of Package Restore 226 | **/[Pp]ackages/* 227 | # except build/, which is used as an MSBuild target. 228 | !**/[Pp]ackages/build/ 229 | # Uncomment if necessary however generally it will be regenerated when needed 230 | #!**/[Pp]ackages/repositories.config 231 | # NuGet v3's project.json files produces more ignorable files 232 | *.nuget.props 233 | *.nuget.targets 234 | 235 | # Microsoft Azure Build Output 236 | csx/ 237 | *.build.csdef 238 | 239 | # Microsoft Azure Emulator 240 | ecf/ 241 | rcf/ 242 | 243 | # Windows Store app package directories and files 244 | AppPackages/ 245 | BundleArtifacts/ 246 | Package.StoreAssociation.xml 247 | _pkginfo.txt 248 | *.appx 249 | 250 | # Visual Studio cache files 251 | # files ending in .cache can be ignored 252 | *.[Cc]ache 253 | # but keep track of directories ending in .cache 254 | !*.[Cc]ache/ 255 | 256 | # Others 257 | ClientBin/ 258 | ~$* 259 | *~ 260 | *.dbmdl 261 | *.dbproj.schemaview 262 | *.jfm 263 | *.pfx 264 | *.publishsettings 265 | orleans.codegen.cs 266 | 267 | # Since there are multiple workflows, uncomment next line to ignore bower_components 268 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 269 | #bower_components/ 270 | 271 | # RIA/Silverlight projects 272 | Generated_Code/ 273 | 274 | # Backup & report files from converting an old project file 275 | # to a newer Visual Studio version. Backup files are not needed, 276 | # because we have git ;-) 277 | _UpgradeReport_Files/ 278 | Backup*/ 279 | UpgradeLog*.XML 280 | UpgradeLog*.htm 281 | 282 | # SQL Server files 283 | *.mdf 284 | *.ldf 285 | *.ndf 286 | 287 | # Business Intelligence projects 288 | *.rdl.data 289 | *.bim.layout 290 | *.bim_*.settings 291 | 292 | # Microsoft Fakes 293 | FakesAssemblies/ 294 | 295 | # GhostDoc plugin setting file 296 | *.GhostDoc.xml 297 | 298 | # Node.js Tools for Visual Studio 299 | .ntvs_analysis.dat 300 | node_modules/ 301 | 302 | # Typescript v1 declaration files 303 | typings/ 304 | 305 | # Visual Studio 6 build log 306 | *.plg 307 | 308 | # Visual Studio 6 workspace options file 309 | *.opt 310 | 311 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 312 | *.vbw 313 | 314 | # Visual Studio LightSwitch build output 315 | **/*.HTMLClient/GeneratedArtifacts 316 | **/*.DesktopClient/GeneratedArtifacts 317 | **/*.DesktopClient/ModelManifest.xml 318 | **/*.Server/GeneratedArtifacts 319 | **/*.Server/ModelManifest.xml 320 | _Pvt_Extensions 321 | 322 | # Paket dependency manager 323 | .paket/paket.exe 324 | paket-files/ 325 | 326 | # FAKE - F# Make 327 | .fake/ 328 | 329 | # JetBrains Rider 330 | .idea/ 331 | *.sln.iml 332 | 333 | # CodeRush 334 | .cr/ 335 | 336 | # Python Tools for Visual Studio (PTVS) 337 | __pycache__/ 338 | *.pyc 339 | 340 | # Cake - Uncomment if you are using it 341 | # tools/** 342 | # !tools/packages.config 343 | 344 | # Tabs Studio 345 | *.tss 346 | 347 | # Telerik's JustMock configuration file 348 | *.jmconfig 349 | 350 | # BizTalk build output 351 | *.btp.cs 352 | *.btm.cs 353 | *.odx.cs 354 | *.xsd.cs 355 | 356 | # OpenCover UI analysis results 357 | OpenCover/ 358 | coverage/ 359 | 360 | ### macOS template 361 | # General 362 | .DS_Store 363 | .AppleDouble 364 | .LSOverride 365 | 366 | # Icon must end with two \r 367 | Icon 368 | 369 | # Thumbnails 370 | ._* 371 | 372 | # Files that might appear in the root of a volume 373 | .DocumentRevisions-V100 374 | .fseventsd 375 | .Spotlight-V100 376 | .TemporaryItems 377 | .Trashes 378 | .VolumeIcon.icns 379 | .com.apple.timemachine.donotpresent 380 | 381 | # Directories potentially created on remote AFP share 382 | .AppleDB 383 | .AppleDesktop 384 | Network Trash Folder 385 | Temporary Items 386 | .apdisk 387 | 388 | ======= 389 | # Local 390 | docker-compose.yml 391 | .env 392 | dist 393 | --------------------------------------------------------------------------------