Skip to content

Web application with Vue 3, REST API and MongoDB to list code projects. (Mentoring project at Lucerne University of Applied Sciences and Arts HSLU)

Notifications You must be signed in to change notification settings

andre-lergier/hslu-code-project-collection

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

72 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Code Project Collection with Vue.js, MongoDB, REST API

This website helps me to keep an overview of git repositories on different platforms, dev-, stage- and production-deployments and their particular hosting.
The data is stored in a MongoDB and is accessed with a REST API. The frontend is based on Vue.js.

Personal mentoring project with Maria Husmann
Hochschule Luzern, Digital Ideation, HS2020

Technical Challenges πŸš€

The sense behind this project is to try out and learn new technologies, concepts and libraries I never used before or don't know yet very well.
These are the key technologies I wanted to learn:

Architecture

Based on these technologies, the architecture of the application can be split up in 3 parts. Project architecture

Run Project βš™οΈ

Setup

npm run setup

Development Frontend

Compiles and hosts server for development

npm run frontend

or

cd frontend
npm run serve

Build Frontend

npm run frontend-build

or

cd frontend
npm run build

Backend

Connects to MongoDB and starts API-Server

npm run backend

or

cd backend
npm run dev

Environment Variables

The backend server uses multiple enviroment variables, which are loaded by the library dotenv. Therefore create a .env file in the backend/ folder.

PORT=4433 # API Port

MONGO_USER=<>
MONGO_PASSWORD=<>
MONGO_URL=h<>
MONGO_DB=<>

JWT_PRIVATEKEY=<>

Public Website: code.lergier.ch
API HTTP: api.code.lergier.ch
API HTTPS: hslu-code-project-collection.herokuapp.com

Code to deploy to Heroku:
git subtree push --prefix backend heroku master


Documentation πŸ“”

Views

Project overview

The main view of the website is the project overview. Projects are grouped in categories and ordered by the date and their name.
If the user isn't logged in, the page shows less information. Main view not logged in

Projects

If the user is logged in, the application shows more information. Projects view

Login

If a user has an account he can login using his email and password. Login view

Create/Request an Account

Create Account view

Create Project

Logged in users can create new projects. New Project

Technologies πŸ’‘

Vue 3

View 3 was only a few weeks old when I started with this project.
I didn't experience big differences or improvements. For me the biggest change was using TypeScript instead of normal JavaScript.

To setup the project I used the newest version of Vue CLI with the following options: Vue CLI Settingns

Helpful Links:

MongoDB

In all my previous projects with a database I used a relational SQL-DB. So this is the very first time for me to try out a no SQL, file based database. Simply explained, in a noSQL Database the data isn’t stored in columns and rows but in files.

A lot of Tutorials use the Mongoose library to interact with the Database. After looking at the Node.js documentation from MongoDB I decided to use the native driver instead of this external library.

MongoDB vs SQL

m100-database-terminology

Documents are organized in Collections. In a SQL-DB, a collection would be a table and a row a document. Data is organized in field-value pairs, like key & value in JSON or a JS object. β†’ A document is stored in BSON format, which means Binary JSON. BSON for example allows additional data types like Integer, Long, Float, Date.

Clusters: Group of servers that store your data.
Replica Set: A few connected machines that store the same data to ensure that if something happens to one of the machines the data will remain intact.

Every document in MongoDB has a unique _id field: "_id": "..."

Important Commands

Command Description
show dbs Show list of databases in the cluster
use [databaseName] Go to a database inside Cluster
show collections Show all collections (tables) inside the selected database
db.[collectionName].find( {"state":"NY", "city":"ALBANY"} ) Search content in a table, shows matching documents. The query are the same as when used on data explorer (If step 2 is done, db is an alias for the selected database)
[find(...)].count() Number of elements
[find(...)].pretty() Prettify text to be easy readable
db.[collectionName].findOne() Show random document
db.[collectionName].insert({...}) db.[collectionName].insert([{ ... }, { ... }]) db.[collectionName].insert([{ ... }, { ... }], { "ordered": false }) Insert new document Without "ordered": false inserting will stop if there is an error
db.[collectionName].updateMany({ "city": "HUDSON" }, { "$inc": { "pop": 10 } })
db.grades.updateOne({ "student_id": 250, "class_id": 339 }
{ "$push": { "scores": { "type": "extra credit", "score": 100 } } })
$inc: increment
$set: new value
$push: add new object to array
db.[collectionName].deleteMany({ "test": 1 }) db.[collectionName].deleteOne({ "_id": 3 }) Delete document
db.[collectionName].drop() Delete collection When all collections are dropped from a database, the database no longer appears in the list of databases when you run show dbs.

Tutorials

To get startet with MongoDB I used MongoDB University. I made parts of the following tutorials:

More Links

Typescript

For the Vue 3 frontend of my application I used Typescript.
I'm very used to write JS and it was somehow strange to change the way you write your normal code. Because I already wrote code in typed languages like Java or Swift it wasn't really hard to understand how it works.

Datatypes

These are the most important dataypes in Typescript.

// Basic
let boolean: boolean = false;
let number: number = 8;
let string: string = "blue";
let notSure: unknown = 4;

noReturn = (): void => {}

// Array
let list: number[] = [1, 2, 3];
let list: Array<number> = [1, 2, 3];

// Tuple
let x: [string, number] = ["hello", 10];

Tutorials:

More Links:

API 🎯

To access and manage the database I wanted to write an API. This brings the benefits of an independent backend, so you can access the data from every client.

HTTP Status Codes

Code Status
200 OK
404 Not found
500 Internal Server Error
201 Created
204 No Content
304 Modified
400 Bad Request
401 Unauthorized
403 Forbidden
409 Conflict
501 Not Implemented

API Routes

πŸ”‘: Valid authentication header required
🧹: Parameters are sanitized by the server
⭐️: Returns more information if authenticated

GET /projects ⭐️

Returns all projects stored in the database. If valid authentication header is sent, the response contains more information.

Response 200: OK:

{
  "success": true,
  "message": "projects",
  "projects": [
    {
      "_id": "MongoDB ID",
      "title": "string",
      "category": "string",
      "year": "number",
      "private": "boolean",
      "publicLink": {
        "url": "string"
      },
      "repository": {
        "platform": "string",
        "name": "string",
        "url": "string"
      }
    }
  ]
}

GET /projects/:url ⭐️

Returns the details of the project where the the provided :url is equal to publicLink.url. If valid authentication header is sent, the response contains more information.

Response 200: OK:

{
  "success": true,
  "message": "project",
  "projects": {
    "_id": "MongoDB ID",
    "title": "string",
    "category": "string",
    "year": "number",
    "private": "boolean",
    "publicLink": {
      "url": "string"
    },
    "repository": {
      "platform": "string",
      "name": "string",
      "url": "string"
    }
  }
}

POST /projects πŸ”‘ 🧹

Endpoint to create a new project. The request body must contain at least the values title, category, year and private.

Request:

{
  "title": "string",
  "category": "string",
  "year": "number",
  "private": "boolean",
  "publicLink": { "url": "string", "tags": [ "string" ] },
  "devLink": { "url": "string", "tags": [ "string" ] },
  "repository": { "platform": "string", "url": "string", "tags": [ "string" ] },
  "database": { "title": "string", "url": "string", "tags": [ "string" ] }
}

Response: 201: Created

{
  "success": true,
  "message": "project added successfully",
  "project": {
    "title": "string",
    "category": "string",
    "year": "number",
    "private": "boolean",
    "_id": "MongoDB Id"
  },
  "projectId": "MongoDB Id"
}

PATCH /projects/:id πŸ”‘

Endpoint to update a project. In the current version not implemented yet.

DELETE /projects/:id πŸ”‘

Endpoint to delete a project. The provided :id needs to be the MongoDB ID from the specific project.

Response 200: OK:

{
  "success": true,
  "message": "1 project successfully deleted"
}

GET /user πŸ”‘

Returns current user based on provided token.

Response 200: OK:

{
  "success": true,
  "message": "User",
  "token": "JWT",
  "user": {
    "_id": "MongoDB ID",
    "name": {
      "firstname": "string",
      "familyname": "string"
    },
    "email": "string",
    "authorizedByAdmin": "boolean"
  }
}

GET /user/:email πŸ”‘

Returns current user information based on :email parameter. It's only possible to get the information of the logged in user.

Response 200: OK:

{
  "success": true,
  "message": "user",
  "user": {
    "_id": "MongoDB ID",
    "name": {
      "firstname": "string",
      "familyname": "string"
    },
    "email": "string",
    "authorizedByAdmin": "boolean"
  }
}

POST /user 🧹⭐️

Endpoint to create a new user. If valid authentication header is provided, the option authorizedByAdmin is set to true, otherwise it's false.

POST /user/login πŸ”‘ 🧹

Endpoint to perform the login.

Request:

{
  "email": "string",
  "password": "string"
}

Response 200: OK:

{
  "success": true,
  "message": "Login successfully",
  "token": "JWT",
  "user": {
    "_id": "MongoDB ID",
    "name": {
      "firstname": "string",
      "familyname": "string"
    },
    "email": "string",
    "authorizedByAdmin": "boolean"
  }
}

DELETE /user/:id πŸ”‘

Endpoint to delete the user where the the provided :id is equal to it's MongoDB Id.

Response 200: OK:

{
  "success": true,
  "message": "1 user successfully deleted"
}

Express

Axios

Security

For the Login authorization I use the great technology of JSON Web Tokens. A JSON Web Token consists of 3 parts sperated by dots: Header, Payload and Signature: xxxxx.yyyyy.zzzzz
Each part then is Base64Url encoded.

When a users logs in successfully the API Server responds a JWT.

HTTP Request:

{
    "email": "admin@lergier.ch",
    "password": "myPassword"
}

Server Response:

{
    "success": true,
    "message": "Login successfully",
    "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiI1ZmY3MmY4Y2MwYzg3ZTQ4MTA2NzAyYzYiLCJlbWFpbCI6ImFkbWluQGxlcmdpZXIuY2giLCJpYXQiOjE2MTAwNDk0MjcsImV4cCI6MTYxMDQ4MTQyN30.kwAqGeT9IFvX40QoST0T1r7JyPJ4XPKv_p_5nsfZXF4",
    ...
}

Analyzing the token using the debugger, it becomes clear what's stored inside it. JWT Debugger

The important payload data in this response is the user information.

{
  "userId": "5ff72f8cc0c87e48106702c6",
  "email": "admin@lergier.ch",
  "iat": 1610049427,
  "exp": 1610481427
}

Using the right private key ``lets you verify the signature. This ensures that the data in the payload section wasn't changed.

Links:

Password Handling

To hash the password before saving it to the database I use bcrypt. This makes the handling with passwords easy and safe. bcrypt then offers nice functinos to compare the password of the user with the hashed one in the database.

Documentation bcrypt

Sanitization

To sanitize the user requests I use express-validator as a middleware on the server.

Tutorials

If using Typescript:

Simple Approaches:

Tutorial Series from Robin Wieruch:

Prototype πŸ“

For concept and design purposes I created a simple prototype using Figma.
Launch the prototype with this link: https://www.figma.com/file/5cJqJfXD5euCykWQKnMR2E/Home?node-id=0%3A1

About

Web application with Vue 3, REST API and MongoDB to list code projects. (Mentoring project at Lucerne University of Applied Sciences and Arts HSLU)

Topics

Resources

Stars

Watchers

Forks