1 of 53

All About APIs feat. Express & MongoDB

7:05pm PST: SETUP HELP

7:30pm PST: WORKSHOP STARTS

2 of 53

Disclaimer:

The following workshop will be recorded and shared. We will not be recording anyone’s video except the presenters’ screens, but sound (any questions you ask or answer) will be a part of the recording.

3 of 53

Disclaimer:

This workshop will cover a lot of material relatively quickly. If you are behind at any point, ask for help in the Slack channel (#all-about-apis) or reference the Workshop Companion Guide.

4 of 53

Workshop Handbook & Resources

  • Join the nwPlus Slack Organization and the appropriate channel
  • Ask questions in the nwPlus Slack channel
  • Ask a TA in the Slack channel to get placed into a breakout room if behind.
  • Have the following Notion pages easily accessible:

Workshop Info: See Page

Pre-workshop: See Page

Workshop Companion Notes: See Page

nwPlus Workshop Slack: Join Slack

5 of 53

Timeline (~2 hours)

  • Introduction / Objectives /nwPlus
  • Prerequisites
  • Overview
    • What is a backend?
    • Backend Fundamentals
    • Node / Express / APIs
    • Databases
  • Setting up the Backend with Express
  • Connecting to MongoDB
  • Creating Server Endpoints for CRUD operations
  • Endpoint Testing with Insomnia
  • Resources

6 of 53

Introduction

7 of 53

hello world! 👋

Ben Cheung

  • 4th year CS @ UBC (BCS)
  • Sponsorship @ nwPlus
  • He/Him
  • Former Biochemist

8 of 53

Workshop TAs

Daniel Ryu

HackCamp Logistics, He/Him

3rd Year Business & CS

Jill Bao

Sponsorship, She/Her

3rd Year Business & CS

Jenny Pan

Internal Dev, She/Her

4th Year Business & CS

9 of 53

Workshop TAs

Allison Chiang

Co-president, She/Her

4th Year CS

Anne Guo

Co-president, She/Her

4th Year Business & CS

10 of 53

Objectives

By the end of the workshop, you would be able to:

    • Set up an Express.js server.
    • Connect your backend to a MongoDB database.
    • Perform CRUD operations to database.
    • Create a simple API.
    • Test your API with Insomnia.

11 of 53

Our Hackathons

We're the community behind some of the largest hackathons in the Pacific Northwest, empowering thousands of hackers worldwide every year!

HackCamp

nwHacks

cmd-f

12 of 53

Our Hackathons

HackCamp is a weekend-long hackathon bootcamp on Dec 5-6th designed for beginners and tech lovers worldwide, featuring 9+ hours of workshops and our annual 12-hour-long beginner-friendly hackathon - the largest in North America!

Registration is live.�hackcamp.nwplus.io

13 of 53

Prerequisites

14 of 53

Prereqs

  • JavaScript Experience
  • Node.js installed.
  • IDE installed (VSCode recommended)
  • Basic understanding of CLI commands. (cd, cd .., npm install, etc.)
  • Set up Github Account
  • Install Git
  • Clone/ Download the Starter Code from: Repo
    • git clone https://github.com/MrBenC88/All-About-APIs-Workshop.git
  • Rest Client Installed
    • Insomnia (https://insomnia.rest/)
  • MongoDB server setup (Follow instructions here: Notion Notes)

15 of 53

Workshop Handbook & Resources

  • Join the nwPlus Slack Organization and the appropriate channel
  • Ask questions in the nwPlus Slack channel
  • Ask a TA in the Slack channel to get placed into a breakout room if behind.
  • Have the following Notion pages easily accessible:

Workshop Info: See Page

Pre-workshop: See Page

Workshop Companion Notes: See Page

nwPlus Workshop Slack: Join Slack

16 of 53

Overview

17 of 53

What is a backend?

  • “Server-side”
  • the portion of the website you don’t see.
  • Focus on functionality and logic powering the app.
  • “Data-access” layer *
  • Backend could also be abstract (ie. Firebase, BaaS [Backend as a Service])

18 of 53

Backend Fundamentals

  • Front-end (client-side) programming, is what happens in the browser—everything the end users see and interact with. “Presentation Layer”

  • Back-end happens on the server (on site, or in the cloud) and communicates with databases.

“Data-access” layer

  • Components:
    • Server
    • Database
    • Middleware (ie. CORS - Cross-origin resource sharing)
    • Programming language and frameworks
    • APIs (application programming interface)

19 of 53

Client vs Server

  • Server-side
    • Refers to everything happening on the server instead of client.
    • Business logic, interaction with databases, identity authentication, push notifications.

  • Client-side
    • Refers to everything in a web app that is displayed or takes place on the client (end user’s device)
    • UI / actions that the app performs within the user’s browser

20 of 53

NodeJS / Express / APIs

NodeJS

  • Open source server environment.
  • Uses Javascript on the server.
  • Runs single-threaded, non-blocking, asynchronous programming, which is very memory efficient.

Express

  • “Fast, unopinionated, minimalist web framework for Node.js”
  • Express takes repetitive low level code (eg. parsing the request or formatting the response) and gives you a higher level API to use

APIs (Application Programming Interface)

  • An API is a set of rules that allows programs to communicate.
  • REST (Representational state transfer) determines how the API looks like. A set of rules that developers follow when they create their API.
  • One of the rules:
    • Obtain data (resource) when you link to a specific URL.
    • Each URL called a request.
    • Data sent back is called a response.

21 of 53

Components of a Network Request

A request consists of 4 components:

  • Endpoint
    • Also known as the request URL. It is the address of the resource you are requesting.
    • Route: the “name” you use to access endpoints, used in the URL.
    • Also can have multiple endpoints associated with it, and which is used depends on the HTTP verb.
  • Method
    • GET/POST/PUT/DELETE/etc.
  • Header
    • Unrelated to the message content. Usually used to provide context to request.
  • Data (the body)
    • The message for PUT/POST/PATCH requests; commonly JSON object or array

22 of 53

HTTP Methods

HTTP defines a set of request methods to indicate the desired action to be performed for a given resource.

GET: used to request data from a specified resource.

POST: used to send data to a server to create/update a resource.

PUT: used to send data to a server to create/update a resource.

HEAD: almost identical to GET, but without the response body.

DELETE: deletes the specified resource.

OPTIONS: describes the communication options for the target resource.

*The two most common HTTP methods are: GET and POST.

We will use these methods for building our CRUD (Create, Read, Update, Delete) functionality. So, focus on GET, POST, PUT, DELETE

23 of 53

Database

We will be using MongoDB for our database. Alternative databases would be MySQL, PostgreSQL, SQLite etc.

Why MongoDB?

  • document database built on a scale-out architecture that has become popular with developers of all kinds who are building scalable applications using agile methodologies.
  • NoSQL = Not only SQL (differs from SQL which stands for Structured Query Language)
  • Non-relational database; database not modeled with tabular relations
  • Less structure, more flexibility
  • ODM (Object Document Mapping)

Mongoose

  • Is an ODM library for MongoDB and Node.js
  • Manages relationships between data, provides schema validation and is used to translate between objects in code and representation of those objects in MongoDB

I’m still not convinced to use MongoDB!

24 of 53

Setting up the Backend

25 of 53

Let’s get started with the Backend

First steps:

  • Download / Clone the starter code from the following Github: https://github.com/MrBenC88/All-About-APIs-Workshop.git
  • Install the dependencies.
    • In step 1, you must (in your command terminal) navigate into the backend folder. � cd backend
  • Next, do: npm install
  • Finally, to run the server, simply type nodemon server in the backend folder.

How to run the server:

1. cd backend

2. npm install

3. nodemon server

26 of 53

  • Dependencies
  • Creating Express App
  • Define port
  • Setup middleware
  • Test by running server.
    • 1. Comment out users.js in .\backend\routes\users.js
    • 2. cd backend
    • 3. nodemon server (to stop server, click on terminal and ctrl-c)

Quick look at our Express Server

27 of 53

Quick Look at our Express Server

Quick Look at our Express Server

  • Dependencies
  • Creating Express App
  • Define port
  • Setup middleware
  • Test by running server.
    • 1. cd backend
    • 2. nodemon server (to stop server, click on terminal and ctrl-c)

28 of 53

Connecting to MongoDB

29 of 53

  • Creating a .env file for storing credentials
  • In your .env file, enter your credentials.
  • Within your MongoDB server, click on Connect -> Connect your application. Copy paste your credentials into your .env file.

Note:

Replace <password> with nwPlus

Replace <dbname> with the name of the database, BackEndWorkshop

If you do not have a MongoDB server setup, you can use our temporary dummy server by copy pasting the following.

  • ATLAS_URI=mongodb+srv://nwPlusUser:nwPlus@backendworkshop.woyus.gcp.mongodb.net/BackendWorkshop?retryWrites=true&w=majority

Connecting your MongoDB database

30 of 53

  • Create a variable called uri to store it. (// TODO #2 - Create a variable to access that information in the .env variable)
    • const uri = process.env.ATLAS_URI;
  • Add to gitignore if you are using git.
    • node_modules/
    • .DS_Store
    • .env
  • Fix deprecation warnings and connect url to mongoose (// TODO #3 Connect to your MongoDB Database).

mongoose.connect(uri, {

useUnifiedTopology: true,

useNewUrlParser: true,

useCreateIndex: true,

});

const connection = mongoose.connection;

  • Confirm the connection and output a success message (TODO #4). Re-run server to check.

connection.once("open", () => {

console.log("MongoDB database connection established successfully");

});

  • Mount the middleware for the routes served by the userRouter (TODO #5)
    • app.use("/users", userRouter);
    • We define the /users route so when we access routes related to the userRouter, we will need to access via:
    • localhost:5000/users/

Connecting your MongoDB database

31 of 53

  • We will create a user schema that will represent a single user. The single user object will have two attributes: a username and age
  • Navigate to \nwPlus Backend Workshop\backend\models\user.model.js
  • Add an additional attribute representing the user age. (TODO #6)
  • Set the appropriate data type for the age. (TODO #7)
  • Define user model and export.

�const userSchema = new Schema({

username: {

type: String,

required: true,

unique: true,

trim: true,

minlength: 3,

}, //add age here with appropriate datatype

},

{

timestamps: true,

}

);

Defining your User model.

const userSchema = new Schema( {

username: {

type: String,

required: true,

unique: true,

trim: true,

minlength: 3,

},

age: Number,

},

{

timestamps: true,

}

);

32 of 53

Break

10 mins

33 of 53

Workshop Handbook & Resources

  • Join the nwPlus Slack Organization and the appropriate channel
  • Ask questions in the nwPlus Slack channel
  • Ask a TA in the Slack channel to get placed into a breakout room if behind.
  • Have the following Notion pages easily accessible:

Workshop Info: See Page

Pre-workshop: See Page

Workshop Companion Notes: See Page

nwPlus Workshop Slack: Join Slack

34 of 53

Creating Server Endpoints

35 of 53

We now navigate to \nwPlus Backend Workshop\backend\routes\users.js

  • Each route we define will be using a HTTP request so that we can perform our desired action to our MongoDB database.
  • We will focus on CRUD (Create, Read, Update. Delete) operations.
    • Add a user to database
    • Delete user from database
    • Update user in database
    • Read user from database

Steps:

  • Define router variable from express. Define User variable making use of our schema we created in the previous step.
  • Create routes.
  • Export the router.
  • We have provided two examples that we will go through.

Create Routes for User Object

36 of 53

/** GET ALL (GET REQUEST)

* Access via: http://localhost:5000/users/

* Example route utilizing a get request to get all the users in the database.

* This route handles incoming HTTP get requests from the /users path

* User.find() is a mongoose method that gets all the users from mongoose atlas database.

* For the .then line, after it finds all the users it returns the users in json format that we got from database

* if there's error - return a error 400 with the message */

router.route("/").get((req, res) => {

User.find() //

.then((users) => res.json(users)) //

.catch((err) => res.status(400).json("Error: " + err));

});

// GET ALL ALTERNATIVE; Access: http://localhost:5000/users/all

router.get("/all", (req, res) => {

//endpoint for accessing all users in database

User.find()

.then((users) => res.send(users)) //Note here.

.catch((err) => console.log(err));

});

GET ALL (GET Request Example)

37 of 53

/* GET ONE (GET REQUEST)

* Access via: http://localhost:5000/users/:id

* xample: http://localhost:5000/users/5f4c647904dcad4a242735e8

* A route for getting a single user's information based on the user's MongoDB id.

* The :id is like a variable. This is object id that is created automatically by mongoDB.

*/

// TODO #8 Fill in the missing pieces of code in order to complete the following Route.

router.get("/:id", (req, res) => {

//endpoint for accessing single user by id in database

User.findById(req.params.id) // find it by id

.then((user) => /*Add missing code here*/)

.catch((err) => /*Add missing code here*/);

});

GET ONE (GET Request Exercise)

38 of 53

/* GET ONE (GET REQUEST)

* Access via: http://localhost:5000/users/:id

* xample: http://localhost:5000/users/5f4c647904dcad4a242735e8

* A route for getting a single user's information based on the user's MongoDB id.

* The :id is like a variable. This is object id that is created automatically by mongoDB.

*/

// TODO #8 Fill in the missing pieces of code in order to complete the following Route.

router.get("/:id", (req, res) => {

//endpoint for accessing single user by id in database

User.findById(req.params.id) // find it by id

.then((user) => res.send(user)) //then return as json ; else return error

.catch((err) => res.status(400).json("Error: " + err));

});

GET ONE (GET Request Solution)

39 of 53

/** POST ONE (POST REQUEST) | Access via: http://localhost:5000/users/add

* This route is for adding a user to the database. It requires the user schema in JSON format to be filled in and the request set to POST. */

// TODO #9 Fill in the missing pieces of code in order to complete the following Route.

// Note: The function .save() saves the new user to the database.

router.post("/add", (req, res) => {

const username = req.body.username; //we assign the username to variable, and create new instance of username

const age = req.body.age || 0;

const newUser = new User({

/**

* add missing code here

*/

});

newUser

.save() // save the new user to the database

.then(() => res.json("User added!")) // return prompt that user is added; else return error message

.catch((err) => res.status(400).json("Error: " + err));

});

POST ONE (POST Request Exercise)

40 of 53

/** POST ONE (POST REQUEST) | Access via: http://localhost:5000/users/add

* This route is for adding a user to the database. It requires the user schema in JSON format to be filled in and the request set to POST. */

// TODO #9 Fill in the missing pieces of code in order to complete the following Route.

// Note: The function .save() saves the new user to the database.

router.post("/add", (req, res) => {

const username = req.body.username; //we assign the username to variable, and create new instance of username

const age = req.body.age || 0;

const newUser = new User({

username,

age,

});

newUser

.save() // save the new user to the database

.then(() => res.json("User added!")) // return prompt that user is added; else return error message

.catch((err) => res.status(400).json("Error: " + err));

});

POST ONE (POST Request Solution)

41 of 53

/* DELETE ONE (DELETE REQUEST)

* Access via: http://localhost:5000/users/:id

* Delete a user based on their MongoDB id.*/

// TODO #10 Fill in the missing pieces of code in order to complete the following Route.

// Note: The function User.findByIdAndDelete(req.params.id) finds a specific id from the MongoDB database.

router./*adding missing code here*/("/:id", (req, res) => {

User./*add missing code here*/(req.params.id)

.then(() => /*adding missing code here*/)

.catch((err) => /*adding missing code here*/);

});

DELETE ONE (Delete Req Exercise)

42 of 53

/* DELETE ONE (DELETE REQUEST)

* Access via: http://localhost:5000/users/:id

* Delete a user based on their MongoDB id.*/

// TODO #10 Fill in the missing pieces of code in order to complete the following Route.

// Note: The function User.findByIdAndDelete(req.params.id) finds a specific id from the MongoDB database.

router.delete("/:id", (req, res) => {

User.findByIdAndDelete(req.params.id)

.then(() => res.json(`User with id ${req.params.id} deleted!`))

.catch((err) => res.status(404).json("Error: " + err));

});

DELETE ONE (Delete Solution)

43 of 53

/** UPDATE ONE (PUT REQUEST) | Access via: http://localhost:5000/users/:id

*/

// TODO #11 Fill in the missing pieces of code in order to complete the following Route.

// Note: The function User.findByIdAndUpdate() finds a specific id from the MongoDB database and updates it

// If you set new: true, findOneAndUpdate() will instead give you the object after update was applied.

router./*adding missing code here*/("/:id", (req, res) => {

const body = /*adding missing code here*/;

const user = {

/*adding missing code here*/

};

User./*adding missing code here*/(req.params.id, user, { new: true })

.then((updatedUser) => res.json(updatedUser))

.catch((err) => res.status(400).json("Error: " + err));

});

Update ONE (PUT Request)

44 of 53

/** UPDATE ONE (PUT REQUEST) | Access via: http://localhost:5000/users/:id

*/

// TODO #11 Fill in the missing pieces of code in order to complete the following Route.

// Note: The function User.findByIdAndUpdate() finds a specific id from the MongoDB database and updates it

// If you set new: true, findOneAndUpdate() will instead give you the object after update was applied.

router.put("/:id", (req, res) => {

const body = req.body;

const user = {

username: body.username,

age: body.age,

};

User.findByIdAndUpdate(req.params.id, user, { new: true })

.then((updatedUser) => res.json(updatedUser))

.catch((err) => res.status(400).json("Error: " + err));

});

Note: TODO #12 is optional and a recommended exercise when you have time. Create another route that updates an existing user in the database using POST REQUEST.

Update ONE (PUT Request Solution)

45 of 53

API Testing with Insomnia

46 of 53

Workshop Handbook & Resources

  • Join the nwPlus Slack Organization and the appropriate channel
  • Ask questions in the nwPlus Slack channel
  • Ask a TA in the Slack channel to get placed into a breakout room if behind.
  • Have the following Notion pages easily accessible:

Workshop Info: See Page

Pre-workshop: See Page

Workshop Companion Notes: See Page

nwPlus Workshop Slack: Join Slack

47 of 53

We now navigate to \nwPlus Backend Workshop\backend\ in our terminal. Run the server.

  1. cd backend
  2. nodemon server

Once we see our success message, then we can start testing. For any conflicting routes, comment them out.

We can use test using a REST client like Insomnia or Postman.

For the purposes of this workshop, we will be using Insomnia.

  1. After installing, create a new POST REQUEST using JSON
    1. New Request (Ctrl N)
    2. Enter name (anything)
    3. Select POST in dropdown and JSON for body.
    4. Create
  2. Enter the url http://localhost:5000/users/add
  3. Enter the following. Change the username to make it more unique.

{

"username": "Test User 1003",

"age":4

}

  • Click Send and you will see a response.

Testing our Routes with Insomnia

48 of 53

If a success response is obtained, You have added the user via a POST Request through the POST One Route.

If an error is returned, you should be able to view what type of error it is.

Testing our Routes with Insomnia

49 of 53

Check if your user was added by using the GET ALL request.

Steps:

  1. Set the request type from POST to GET.
  2. Change the url to http://localhost:5000/users/
  3. Click Send.
  4. If successful, you will have received a JSON response of all the users in the database.

Next test your routes for

  • DELETE ONE (DELETE REQUEST)
  • UPDATE ONE (PUT REQUEST)
  • GET ONE (GET REQUEST)

Note: For /:id

* Access via: http://localhost:5000/users/:id

* Example: http://localhost:5000/users/5f4c647904dcad4a242735e8

Check that your user was added.

50 of 53

Resources & Conclusion

51 of 53

Resources for additional learning:

Feel free to reach out and connect.

Additional Resources

52 of 53

53 of 53

Please fill out the feedback form!