---
title: '08 Integrating Front End with Back End'
disqus: hackmd
---
08 Integrating Front End with Back End
===
<style>
img{
/* border: 2px solid red; */
margin-left: auto;
margin-right: auto;
width: 90%;
display: block;
}
</style>
## Table of Contents
[TOC]
### Front End
- how it'll work
- user goes to valid url
- client server send template html w/o data from db
- js code bundled with html execute on user's browser
- browser requests for data from our restapi with axios
- once rest api responds with data, jquery used to append data to html
- jwt token will either be stored on localStorage or as a cookie
### CORS
- for security reasons browsers restrict cross-origin http reqs made by scripts
- since front end server services file from localhost:3031 and API server is on localhost:3000, we are making cross-origin reqs
- get around by adding `Access-Control-Allow-Origin` header in api resp with value `*` (hence allowing all)
- install cors express middleware too
- `npm install --save cors`
- [read more](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS)
Practical Example
---
### Initialise
```javascript=
// index.js in root dir
app.get("/", (req, res) => {
res.sendFile("/public/index.html", { root: __dirname });
});
app.get("/users/:id", (req, res) => {
res.sendFile("/public/user.html", { root: __dirname });
});
app.get("/users/", (req, res) => {
res.sendFile("/public/users.html", { root: __dirname });
});
const PORT = 3001;
app.listen(PORT, () => {
console.log(`Client server has started listening on port ${PORT}`);
});
```
### Homepage
```htmlmixed=
// index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Friendbook</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
</head>
<body>
<body>
<div class="container">
<nav class="nav">
<a class="nav-link" href="/">Home</a>
<a class="nav-link" href="/users/">All Users</a>
</nav>
<div style="margin-top: 2rem;">
<h1>Home</h1>
<form id="create-post-form" style="margin-top: 2rem;">
<div class="form-group">
<textarea class="form-control" id="create-post-form-body" rows="3" placeholder="What's on your mind?"></textarea>
</div>
<button type="submit" class="btn btn-primary">Create Post</button>
</form>
<div id="posts">
</div>
</div>
</div>
<script
src="https://code.jquery.com/jquery-3.3.1.min.js"
integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8="
crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script>
// your JS code goes here.
</script>
</body>
</html>
```

### Fetching Posts
```javascript=
// append this js code into the script tag in html code above
// FETCHING POSTS
// API url
const baseUrl = "http://localhost:3000";
// hardcoded because we have not added login yet.
const loggedInUserID = 1;
axios.get(`${baseUrl}/users/${loggedInUserID}/posts/`)
.then((response) => {
const posts = response.data;
posts.forEach((post) => {
const postHtml = `
<div class="card" style="margin-top: 2rem;">
<div class="card-body">
<p class="card-text">${post.text_body}</p>
</div>
<div class="card-footer text-muted">
${post.created_at}
</div>
</div>
`;
$("#posts").append(postHtml);
});
})
.catch((error) => {
console.log(error);
});
```
### Implementing CORS in Controller
```javascript=
const express = require("express");
const app = express();
const User = require("./models/User");
const Post = require("./models/Post");
const bodyParser = require("body-parser");
app.use(bodyParser.json());
const cors = require("cors");
app.use(cors());
...
```
- now has required header

### Building Profile Page
#### HTML file
```htmlembedded=
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Friendbook</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
</head>
<body>
<div class="container">
<nav class="nav">
<a class="nav-link" href="/">Home</a>
<a class="nav-link" href="/users/">All Users</a>
</nav>
<div class="row" style="margin-top: 2rem;">
<div class="col-md-8 col-xs-12">
<div id="user-profile">
</div>
<div id="posts">
</div>
</div>
<div class="col-md-4 col-xs-12">
<h2>Friends</h2>
<ul id="friends-list" class="item-group" style="list-style: none; padding-left: 0;">
</ul>
</div>
</div>
</div>
<script
src="https://code.jquery.com/jquery-3.3.1.min.js"
integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8="
crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script>
// JSCODE goes here
</script>
</body>
</html>
```
#### JS Code
```javascript=
// js code
const baseUrl = "http://localhost:3000";
const loggedInUserID = 1;
const url = window.location.toString();
const userID = parseInt(url.split("/").slice(-1)[0]);
let posts;
axios.get(`${baseUrl}/users/${userID}`)
.then((response) => {
// append user profile
const user = response.data;
$("#user-profile").append(`
<h1>${user.full_name}</h1>
<p style="margin-top: 1rem;">${user.bio}</p>
`);
});
// fetch and append user posts
axios.get(`${baseUrl}/users/${userID}/posts/`)
.then((response) => {
posts = response.data;
posts.forEach((post, index) => {
const likeHtml = `
<button class="btn btn-primary like-button" data-index=${index}>Like</button>
`;
const unlikeHtml = `
<button class="btn btn-danger unlike-button" data-index=${index}>Unlike</button>
`;
const hasLiked = post.likers.map(liker => liker.id).includes(loggedInUserID);
const postHtml = `
<div class="card" style="margin-top: 2rem;">
<div class="card-body">
<p class="card-text">${post.text_body}</p>
${ hasLiked ? unlikeHtml : likeHtml }
<h5 style="margin-top: 1rem;">Likers</h5>
<ul class="list-group">
${
post.likers
.map(liker => `
<li class="list-group-item">
<a href="/users/${liker.id}">${liker.full_name}</a>
</li>
`)
.join("")
}
</ul>
</div>
<div class="card-footer text-muted">
${post.created_at}
</div>
</div>
`;
$("#posts").append(postHtml);
});
});
// fetch user's friends
axios.get(`${baseUrl}/users/${userID}/friends/`)
.then((response) => {
const friends = response.data;
friends.forEach((friend) => {
$("#friends-list").append(`
<li class="list-group-item">
<a href="/users/${friend.id}">${friend.full_name}<a/>
</li>
`);
});
});
// listens for like button clicks
// we have to use the .on method instead of $(".like-button").click because this
// supports listening to dynamically added like/unlike buttons.
// IMPORTANT: DO NOT USE arrow functions because then `this` will not refer to the button!
$(document).on("click", ".like-button", function() {
const index = parseInt($(this).attr("data-index"));
const post = posts[index];
axios.post(`${baseUrl}/posts/${post.id}/likers/${loggedInUserID}`)
.then((res) => {
// change button to unlike on success
const unlikeHtml = `
<button class="btn btn-danger unlike-button" data-index=${index}>Unlike</button>
`;
$(this).replaceWith(unlikeHtml);
});
});
// listens for unlike button clicks
$(document).on("click", ".unlike-button", function() {
const index = parseInt($(this).attr("data-index"));
const post = posts[index];
axios.delete(`${baseUrl}/posts/${post.id}/likers/${loggedInUserID}`)
.then((res) => {
// change button to like on success
const likeHtml = `
<button class="btn btn-primary like-button" data-index=${index}>Like</button>
`;
$(this).replaceWith(likeHtml);
});
});
```
### Login Page
#### HTML
```htmlembedded=
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Friendbook</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
</head>
<body>
<div class="container">
<nav class="nav">
<a class="nav-link" href="/">Home</a>
<a class="nav-link" href="/users/">All Users</a>
</nav>
<h1>Login</h1>
<p>Don't have an account?</p>
<a href="/register/" class="btn btn-primary">Register</a>
<form id="login-form">
<div class="form-group">
<label for="username">Username</label>
<input type="text" class="form-control" id="username">
</div>
<div class="form-group">
<label for="password">Password</label>
<input type="password" class="form-control" id="password">
</div>
<button type="submit" class="btn btn-primary">Login</button>
</form>
</div>
<script
src="https://code.jquery.com/jquery-3.3.1.min.js"
integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8="
crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script>
// js code goes here
</script>
</body>
</html>
```
#### JS Code
```javascript=
const baseUrl = "http://localhost:3000";
$("#login-form").submit((event) => {
// prevent page reload
event.preventDefault();
const username = $("#username").val();
const password = $("#password").val();
const requestBody = {
username: username,
password: password
};
axios.post(`${baseUrl}/login/`, requestBody)
.then((response) => {
const token = response.data.token;
const loggedInUserID = response.data.user_id;
localStorage.setItem("token", token);
localStorage.setItem("loggedInUserID", loggedInUserID);
window.location.href = "/";
})
.catch((error) => {
console.log(error);
});
});
```
### Redirect if not logged in
- redirect if no token in localStorage
#### JS Code
```javascript=
// edit in script tag of index and user.html
const baseUrl = "http://localhost:3000";
const token = localStorage.getItem("token");
const loggedInUserID = parseInt(localStorage.getItem("loggedInUserID"));
if (token === null || isNaN(loggedInUserID)) {
window.location.href = "/login/";
} else {
// put your original code in the script tag here
}
```
###### tags: `BED` `DISM` `School` `Notes`