Een veel voorkomende vorm van web applicatie is een CRUD applicatie. CRUD staat voor Create, Read, Update en Delete. Dit zijn de vier basis operaties die je kan uitvoeren op een database. Eigenlijk is elke eenvoudige admin dashboard een CRUD applicatie. In dit artikel gaan we een eenvoudige CRUD applicatie maken met MongoDB en Express. De initiele data is afkomstig van https://jsonplaceholder.typicode.com/users wat een lijst van gebruikers bevat. We willen dus een applicatie maken waar we gebruikers kunnen toevoegen, verwijderen, updaten en bekijken.
We gaan geen rekening houden met error afhandeling in dit deel van de cursus. We gaan er vanuit dat alles goed gaat. In een productie omgeving is het belangrijk om error afhandeling te voorzien.
Inladen van de JSON data
We gaan eerst de JSON data vanuit de API inladen in onze MongoDB database. We plaatsen de volgende code in een nieuw bestand database.ts.
import { Collection, MongoClient } from"mongodb";import dotenv from"dotenv";import { User } from"./types";dotenv.config();exportconstclient=newMongoClient(process.env.MONGODB_URI||"mongodb://localhost:27017");exportconstcollection:Collection<User> =client.db("exercises").collection<User>("users");exportasyncfunctiongetUsers() {returnawaitcollection.find({}).toArray();}asyncfunctionexit() {try {awaitclient.close();console.log("Disconnected from database"); } catch (error) {console.error(error); }process.exit(0);}exportasyncfunctionloadUsersFromApi() {constusers:User[] =awaitgetUsers();if (users.length==0) {console.log("Database is empty, loading users from API")constresponse=awaitfetch("https://jsonplaceholder.typicode.com/users");constusers:User[] =awaitresponse.json();awaitcollection.insertMany(users); }}exportasyncfunctionconnect() {try {awaitclient.connect();awaitloadUsersFromApi(); console.log("Connected to database");process.on("SIGINT", exit); } catch (error) {console.error(error); }}
En we roepen de connect functie aan in ons index.ts bestand.
import { connect } from"./database";app.listen(3000,async () => {awaitconnect();console.log("Server is running on port 3000");});
Bij het opstarten van de server gaan we de connectie maken met de database en de data inladen vanuit de API. We gaan de data enkel inladen als de database leeg is. We gaan de data inladen in de users collectie van de exercises database.
Lezen van de data (READ)
We gaan nu de data lezen vanuit de database en tonen op de webpagina. We gaan de volgende code toevoegen aan ons index.ts bestand. Eerst importeren we de getUser functie vanuit de database.ts bestand.
en maken we een index.ejs bestand aan in de views/users map. We zorgen ook voor een partials map in de views map en maken een header.ejs en footer.ejs bestand aan.
We tonen de gebruikers in een lijst op de webpagina. We tonen de naam, gebruikersnaam, email, adres, telefoonnummer, website en bedrijfsnaam van de gebruiker.
Toevoegen van data (CREATE)
We maken nu een nieuw formulier aan om een gebruiker toe te voegen en plaatsen deze code in een nieuw bestand views/users/create.ejs.
We voorzien hier voor elk veld een input veld. We gebruiken een fieldset element om de adres en bedrijfsgegevens te groeperen. Door de naam van de input velden te voorzien van address[street] en company[name] kunnen we deze gegevens later makkelijk groeperen in een object. Als je dan de body van de request bekijkt in de Express server, dan zie je dat de address en company gegevens in een object komen te staan. We gaan nu twee routes aanmaken om de data te verwerken: een GET route om het formulier te tonen en een POST route om de data te verwerken.
app.get("/users/create",async(req, res) => {res.render("users/create");});app.post("/users/create",async(req, res) => {let user :User=req.body;awaitcreateUser(user);res.redirect("/users");});
We doen op het einde van de POST route een redirect naar de gebruikerslijst. Dit zorgt ervoor dat de gebruiker na het toevoegen van een gebruiker terug naar de gebruikerslijst gaat. We voorzien hier nog geen error afhandeling.
We gaan nu de createUser functie toevoegen aan ons database.ts bestand.
We voorzien hier ook een getNextId functie die het volgende id ophaalt uit de database. We sorteren de gebruikers op id in aflopende volgorde en nemen de eerste gebruiker. Als er geen gebruikers zijn dan geven we 1 terug. We voegen dan 1 toe aan het id en geven dit terug. We gaan nu de gebruiker toevoegen aan de database. Vergeet de createUser functie niet te importeren in het index.ts bestand.
We gaan nu een button toevoegen aan de gebruikerslijst om een gebruiker te verwijderen. We voegen de volgende code toe aan het index.ejs bestand.
<% for (let user of users) { %>...<formaction="/users/<%= user.id %>/delete"method="POST"> <buttontype="submit">Delete</button></form>...<% } %>
Er wordt dus voor elke gebruiker in de lijst een formulier aangemaakt met een button om de gebruiker te verwijderen. Dit doen we omdat we geen POST requets kunnen doen vanuit een anchor tag. Merk ook op dat we hier een POST gebruiken en geen DELETE. Dit is omdat we geen DELETE requests kunnen doen vanuit een formulier. We gaan nu de route aanmaken om de gebruiker te verwijderen.
We voorzien een nieuwe route in het index.ts bestand.
app.post("/users/:id/delete",async(req, res) => {let id :number=parseInt(req.params.id);awaitdeleteUser(id);res.redirect("/users");});
We gaan nu de deleteUser functie toevoegen aan ons database.ts bestand.
We zorgen ervoor dat de input velden gevuld zijn met de huidige waarden van de gebruiker en dat we als action de update route gebruiken. We gaan nu de route aanmaken om de gebruiker te updaten.
We voorzien weer twee routes in het index.ts bestand. Een GET route om het formulier te tonen en een POST route om de data te verwerken.
app.get("/users/:id/update",async(req, res) => {let id :number=parseInt(req.params.id);let user :User|null=awaitgetUserById(id);res.render("users/update", { user: user });});app.post("/users/:id/update",async(req, res) => {let id :number=parseInt(req.params.id);let user :User=req.body;awaitupdateUser(id, user);res.redirect("/users");});
We redirecten ook hier op het einde van de POST route naar de gebruikerslijst. We gaan nu de getUserById en updateUser functies toevoegen aan ons database.ts bestand.
exportasyncfunctiongetUserById(id:number) {returnawaitcollection.findOne({ id: id });}exportasyncfunctionupdateUser(id:number, user:User) {returnawaitcollection.updateOne({ id : id }, { $set: user });}
Vergeet de getUserById en updateUser functies niet te importeren in het index.ts bestand.