VDOM Stack (Vue Deno Oak MongoDB) CRUD example
In the VDOM Stack series, we already create basic Vue application in last article. Now in this article, we’ll use Deno and Oak framework for create API with database MongoDB.

Now create backend directory after frontend and make file like below image:

Well, I already told you that I’ll share GitHub repo with you. So, don’t worry about the structure.
Install Deno in Window 10
If you’re new to Deno.js then you have to install Deno firstly using PowerShell:
1 |
iwr https://deno.land/x/install/install.ps1 -useb | iex |
Notable error comes
May be, you can get these types of error:
Could not find module “https://deno.land/x/cors/mod.ts” locally
Solution: Run below code.
1 |
deno run backend/app.ts |
Re-open your Vscode. If error not resolved. Now your app.ts code will be
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
import { Application } from "https://deno.land/x/oak/mod.ts"; import router from "./routers/contact.ts"; import { oakCors } from "https://deno.land/x/cors/mod.ts"; const env = Deno.env.toObject(); const PORT = env.PORT || 4000; const HOST = env.HOST || "localhost"; const app = new Application(); app.use(async (ctx, next) => { await next(); const rt = ctx.response.headers.get("X-Response-Time"); console.log(`${ctx.request.method} ${ctx.request.url} - ${rt}`); }); app.use(async (ctx, next) => { const start = Date.now(); await next(); const ms = Date.now(); ctx.response.headers.set("X-Response-Time", `${ms} ms`); }); app.use(oakCors()); app.use(router.routers()); app.use(router.allowedMethods()); console.log(`Application is listing on port: ${PORT} or open ${HOST}:${PORT}`); await app.listen(`${HOST}:${PORT}`); |
contact.ts in model of backend
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
import DB from "./db.ts"; interface Contact { firstName: string; lastName: string; email: string; phone: string; } class ContactClass { constructor() {} contactCollection = DB.collection("contacts"); getContact = async () => { return await this.contactCollection.find({}); }; createContact = async (inputContactDetails: Contact) => { const firstName = inputContactDetails.firstName; const lastName = inputContactDetails.lastName; const email = inputContactDetails.email; const phone = inputContactDetails.phone; const createContact = await this.contactCollection.insertOne({ firstName: firstName, lastName: lastName, email: email, phone: phone, }); return console.log("Contact has been created"); }; } export default ContactClass; |
Here we call mongodb function to insert for create contact. Now write code for controller.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
import Contact from '../models/contact.ts'; const ContactClass = new Contact; export const getContacts = async({response}: {response: any})=>{ response.body = ContactClass.getContact; } export const createContact = async ({request, response}: {request: any, response: any})=>{ const requestBody = await request.body({ contentTypes: { text: ["application/ld+json"] } }); const contacts = requestBody.value; const firstname = contacts.firstname; const lastname = contacts.lastname; const email = contacts.email; const phone = contacts.phone; ContactClass.createContact({ firstName: firstname, lastName: lastname, email: email, phone: phone }); request.body = "Contact has been created."; }; |
Hey, what is the mean of application/ld+json at line 12?
The snippet you got is a script containing JSON-LD data format, a method of encoding Linked Data using JSON. Schema.org vocabulary is used to markup web contents so that they can be understood by major’s search engines (Google, Microsoft, Yandex and Yahoo!). Search engines use this information to display to display relevant contents to users. So, nothing much to worry about it.
Now create a routes for the Deno API with Mongodb.
1 2 3 4 5 6 7 8 9 10 11 12 |
import { Router } from "https://deno.land/x/oak/mod.ts"; import { getContacts, createContact } from "../controllers/contacts.ts"; const router = new Router({ prefix: "/api", }); router .get("/contacts", getContacts) .post("/create", createContact); export default router; |
Now configure the database inside db.ts inside models’ folder.
1 2 3 4 5 6 7 8 |
const client = new MongoClient(); client.connectWithUri("mondodb://localhost:27017"); const db = client.database("dasjs"); export default db; |
Before moving next, download denon and give access the read and write access to Deno by running below code:
1 |
deno install --allow-read --allow-run --allow-write --allow-net -f --unstable https://deno.land/x/[email protected]/denon.ts |
Then run the code:
1 |
denon run --allow-env --allow-net --allow-plugin --allow-read --allow-write --unstable app.ts |
Output should be like:
Deno server is now running. Let add our created API in our components.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
<script> import axios from "axios"; export default { data() { return { contact: { firstname: "", lastname: "", email: "", phone: "", }, }; }, methods: { submit() { let apiUrl = "http://localhost:4000/api/create"; axios .post(apiUrl, this.contact) .then(() => { this.$router.push("/contacts"); this.contact = { firstname: "", lastname: "", email: "", phone: "", }; }) .catch((error) => { console.log(error); }); }, }, }; </script> |
Update ContactComponent.vue to fetch all contacts in table
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
<template> <div class="row justify-content-center"> <div class="col-md-6"> <table class="table table-striped"> <thead class="thead-dark"> <tr> <th>First Name</th> <th>Last Name</th> <th>Email</th> <th>Phone</th> <th>Action</th> </tr> </thead> <tbody> <tr v-for="contact in contacts" :key="contact._id.$oid"> <td>{{cotact.firstname}}</td> <td>{{cotact.lastname}}</td> <td>{{cotact.email}}</td> <td>{{cotact.phone}}</td> <td> <router-link :to="{name: 'edit', params: {id: contact._id.$oid}}" class="btn btn-success" >Edit</router-link> <button class="btn btn-danger">Delete</button> </td> </tr> </tbody> </table> </div> </div> </template> <script> import axios from "axios"; export default { data() { return { contacts: [], }; }, created() { let apiUrl = "http://localhost:4000/api/contacts"; axios .get(apiUrl) .then((res) => { this.contacts = res.data; }) .catch((error) => { console.log(error); }); }, }; </script> |
For now, we are able to insert and fetch the contact details from MongoDb using Deno with Vue. In the next article we’ll implement the edit and delete functionality.

