본문 바로가기
TIL: Today I Learned

[TIL] 20201216 Express / Dynamic HTML with Templating / RESTful Routes

by 김알리 2020. 12. 16.

Express

  • An NPM package which comes with a bunch of methods and optional plugins that we can use to build web applications and APIs
  • Fast, unopinionated, minimalist web framework for Node.js
  • Start up a server to listen for requests
  • Parse income requrests
  • Match those requests to particular routes
  • Craft our http response and associated content

 

Library vs. Framework

  • Library: The user controls the flow of the application code, and decides when to use the library. More flexible
  • Framework : The framework controls the user's behavior. (i.e. tells the user where to plug in the code) Less flexible.

 

How to use Express to make a server

  • Terminal : download express
    • npm i express 
  • JS file 
const express = require('express');
const app = express();

//Runs whenever the server has an incoming request
app.use(callback); 


//Runs whenever the server starts (when it's 'listening')
app.listen(port, callback);
//port : number to identify server(localhost)


//Runs whenever the server has an incoming request with matching path.
//get, post : HTTP verbs
app.get(path, callback); 
app.post(path, callback);
  • HTTP request : gets only one response each time.

 

Request & Response Objects

  • Express makes them automatically for every incoming request for the server.
  • We have access to two different parameters in the callback function of app methods that are automatically passed in.
    • Example: app.use((req, res) => { code })
  • Express creates JS request object automatically by passing the incoming HTTP request information and then it passes it in as the first argument of the callback function of app methods.
  • Response object has methods on it.
    • res.send(param) : Sends the HTTP response. Parameter can be a String, Array, JS Object, etc.

 

Routing

  • Taking incoming requests and a path that it requested and match them to some code in some response.
  • app.get(path, callback)
    • Runs the callback whenever a request comes in matching the path.
    • Example : app.get('/cats', (req, res) => {res.send('<h1>MEOW</h1>')};
  • To include every possible paths, use '*' (Remember to put this code as the last app.get function, so that other get functions can run if there's matching path)

 

  • Matches any path  that follows the pattern
  • Example
//matches any path that starts with '/r/', but with no additional '/'
//the path after ':' is stored in 'req.params' as an object.
app.get('/r/:subreddit', (req, res) => {
    const {subreddit} = req.params;
    res.send(`Browsing the ${subreddit} subreddit`);
})


//can match more than one parameter
app.get('/r/:subreddit/:postId', callback);

 

Query String

  • A portion of the RUL that comes after a '?'
  • We can include information in key-value pairs as part of the query string.
  • Example
    • http://mdn.org/search?q=colors
    • req.query = {q: 'colors'}

 

Nodemon

  • Watches for changes of the files and restarts the server whenever necessary.
  • Install globally through terminal : npm i -g nodemon
  • Instead of 'node index.js', use 'nodemon index.js'

 

 

 

HTML with Templating (EJS)

Templating

  • Allows us to define a preset "pattern" for a webpage, that we can dynamically modify.
  • For example, we could define a single "search" template that displays all the results for a given search term. We don't know twhat the term is or how many results there are ahead of time. The webpage is created on the fly.
  • EJS : Embedded JavaScript (one of templating tools)

 

How to use EJS

  • Terminal
    • npm i ejs
    • mkdir views
    • touch views/home.ejs
  • index.js
const express = require('express');
const app = express();

app.set('view engine', 'ejs');
app.listen(port, callback);

app.get(path, (req, res) => {
    res.render('home');
})
  • What EJS Does
    • When it's tiem to render the template, EJS takes it and evaluate it in any places where it sees JS
    • EJS basically runs the JS and spit out HTML
  • Why use EJS
    • To add logic in and interpolate data; to fill in the blank.

 

Setting The Views Directory

  • When I'm in another directory,
    1. Take out current directory name where this file is located(index.js).
    2. Join the full path to get there, with '/views'
  • Instead of the current directory where the file was executed from , the JS file uses the directory name where the 'index.js' file is located.
//index.js
const path = require('path');
app.set('views', path.join(__dirname, '/views'));
// __dirname : take out current directory name
// '/views' : join the full path to get there

 

EJS tags

  • <%=  %> :  HTML escaped
    • Outputs the value into the template
    • Anything inside of this tag is considered as JS
    • Example
//index.js

app.get('/rand', (req, res) => {
    const num = Math.loor(Math.random() * 10) +1;
    res.render('random', {rand: num})
})
//random.ejs

<h1> Random Number: <%= rand %> </h1>

 

  • <%  %> : Scriptlet for control flow, no output
    • It allows to embed JS without the result actually being added to the template. (Embed logic into a template)
    • Write JS and surround every line with <%  %> tag
    • Example
//random.ejs
//prints <h2> only when num is even

<% if(num%2 === 0){ %>
    <h2> That is an even number! </h2>
<% } %>

 

Serving Static Assets in Express

  • Serves CSS and JavaScript files that we want to include in the response back to the client side.
  • Syntax : need a folder called 'public' and app.css file inside.

 

//index.js

app.use(express.static('public')); //gets executed every single request
<!-- ejs.file -->
<head>
    <link rel="stylesheet" href="/app.css">
</head>
  • To make 'public' folder accessable from everywhere
//index.js
app.use(express.static(path.join(__dirname, 'public')));

 

How to include Bootstrap 

  1. Download 'compiled CSS and JS' file from Bootstrap website.
  2. Make directories: public, public/css, public/js (& include the path in index.js)
  3. Put bootstrap.min.css file in public/css, bootstrap.min.js file in public/js.
  4. Include CSS & JS files in the EJS files
  5. Make sure to get jQuery before <script> for js, inside of js floder.
  • Example
<!--ejs-->
<link rel="stylesheet" href="/css/bootstrap.min.css">
<script src="/js/jquery.js"></script>
<script src="/js/bootstrap.min.js"></script>

 

Partials

  • Includes
  • Used by all of the templates (EJS files)
  • Syntax : <%- include('path to the template') %>
  • Create another ejs file that will be included by other ejs files (template for templates)
  • Example
<%- include('partials/head') %>
<!-- partials: folder, head: ejs file -->
  • Why use <%- %>
    • If <%= %> is used, contents inside of the tag are considered as string, even if it has HTML.

 

 

RESTful Routes

Get Request

  • Used to retrieve information
  • Data is sent via query string
  • Information is plainly visible in the URL
  • Limited amount of data can be sent. (2048 characters)

 

Post Request

  • Used to post data to the server
  • Used to write/create/update
  • Data is sent via request body, not a query string.
  • Can send any sort of data (JSON, text, HTML, etc)
  • Syntax : app.post('url ', (req, res) => { code })

 

req.body

  • Contains key-value pairs of data submitted in the request body.
  • By default, undefined
  • Populated when you use body-parsing middleware such as express.json() or express.urlencoded(). (Can have multiple middlewares at once)
    • Middleware : parse the req.body as this format
  • It needs to be explicitly told how it should parse requrest body.
  • Example : app.use(express.urlencoded({extended: true}))

 

REST

  • REpresentational State Transfer
  • A set of guidelines for how a client + server should communicate and perform CRUD operations on a given resource.
  • Treating data on the server-side as resources that can be CRUDed.
  • The most common way of approaching REST is in formatting the URLs and HTTP verbs in your application.
  • Example: Using comments as a resource.
Name Path HTTP Verb Purpose
index /comments GET Display all comments
new  /comments/new GET Form to create new comment
create /comments POST Creates new comment on server
show /comments/:id GET Details for one specific comment
edit /comments/:id/edit GET Form to edit specific comment
update /comments/:id PATCH Updates specific comment on server
destroy /comments/:id DELETE Deletes specific item on server

 

Index

views/comments/index.ejs : Displays all the comments here.

//index.js

app.get('/comments', (req, res) => {
    res.render('comments/index', {comments})
})

 

New 

  • Creates a form so that the user can give the input.
  • views/comments/new.ejs
<!-- new.ejs -->

<form action="/comment" method="POST">
    <button>Submit</button>
</form>
// index.js

app.get('/comments/new', (req, res) => {
    res.render('commentsnew');
})

 

Create

Creates new comment with the user input

// index.js

app.post('/comments', (req, res) => {
    const {username, comment} = req.body;
    comments.push({username, comment});
})

 

res.redirect([status], path)

  • Use this to prevent submitting the same content repeatedly.
  • By redirecting, res will include a redirect status code(302) and the path('/comments') under the location header. The browser automatically makes a request to the path. (Therefore, there are two requests being made.)
//index.js

app.post('/comments', (req, res) => {
    const {username, comment} = req.body;
    comments.push({username, comment});
    res.redirect('/comments');
})

 

Show

Needs an unique identifier

//index.js

app.get('/comments/:id', (req, res) => {
    const {id} = req.params;
    const comment = comments.find(c => c.id === id);
    res.render('comments/show', {comment});
})

 

UUID

  • Universally Unique IDentifier
  • install: npm i uuid
  • require: const {v4: uuidv4} = require('uuid'); uuidv4(); //gives an unique id

 

Update

//index.js

app.patch( '/comments/:id' , (req, res) => {
     const {id} = req.params;
     const newCommentText = req.body.comment;
     const foundComment = comments.find( c => c. id===id);
    foundComment.comment = newCommentText;
    res.redirect( '/comments' );
})

 

Edit

//index.js

app.get( '/comments/:id/edit' , (req, res) => {.
    const {id} req.params;
    const comment = comments.find( c => c.id === id);
    res.render( 'comments/edit' , {comment});
})
<!-- edit.ejs -->

< form  method = "POST"  action = "/comments
     / < 
% = comment.id% > ? _ method = PATCH" > <!-- code --> </ form >

 

Method Override

  • Since HTML form can't have other methods than GET and POST, we use method override for other methods.
  • install : npm i method-override
  • Example
// Javascript

let methodOverride = require('method-override');
app.use(methodOverride('_method'));
<!-- HTML/EJS -->

<form method="POST" action="/resource?_method=DELETE">
    <!-- code -->
</form>

<!-- Even though the method is POST, Express will treat it as DELETE -->

 

Delete

//index.js

app.delete('/comments/:id', (req, res) => {
    const {id} = req.params;
    comments = comments.filter(c => c.id !== id);
    res.redirect('/comments');
})
<!-- show.ejs -->

<form method="POST" action="/comments/<%=comment.id%>?_method=DELETE">
    <!-- code -->
</form>

 

 

 

 

 

 

* This post is a summary  of Udemy  Course  "The  Web Developer  Bootcamp" by Colt Steele.