No description, website, or topics provided.
JavaScript
Switch branches/tags
Nothing to show
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Failed to load latest commit information.
lab
quotes-begin
quotes-end
README.md

README.md

Express Routes!!!

Learning Objectives:

  • Start building a REST-ful structure for our app
  • Separate routes from server logic
  • Access user-specified parameters
  • Handle errors for routes that don't exist

App setup!!!

Let's rebuild an app that looks just like the one we built in the morning.

By the end, we'll have an app that says "Hello World!" and runs on port 3000.

Another look at our first route

In server.js:

// index route
app.get('/', (req, res) => {
    res.send('Hello world!');
});

This is another method on the app object. It describes a GET request to the root route of the app.

  • It takes a string and a callback
  • The callback takes two arguments, req and res.
    • req stands for the request object received from the browser
    • res stands for the response object that will be sent back to the browser.
  • Within the callback, we access a method on the response object in order to send 'Hello world!'.

Now, when we run npm run dev and visit localhost:3000, we see 'Hello world!' rendered in the browser.

FROM THE EXPRESS DOCS:

Route definitions always take the same basic structure:

app.METHOD(PATH, HANDLER);

Where:

  • app is an instance of express
  • METHOD is an HTTP request method, in lowercase
  • PATH is is a path on the server
  • HANDLER is the function executed when the path matches.

More Routes!

Of course, we want to do more with our app than just saying "hello world". We can do this by adding more routes to our app.

Add an error handler

// get anything that hasn't already been matched
app.use('*', (req, res) => {
    // send a response with status 404
    res.status(404).send(err);
});

Now, instead of saying "CANNOT /GET" on all the routes we haven't set up, it'll send back an error instead.

Order matters here. If we put our error handler above our root route, we won't ever be able to get to it, since the '*' catches the request before it gets to the '/'.

Add our first additional route

Since this is a quotes app, we need to have a route that gives information about quotes!

app.get('/quotes', (req, res) => {
  res.send('Info about quotes!');
});

But let's say we wanted to send back JSON data, for example, instead of just plain text. We can change res.send to res.json:

app.get('/quotes', (req, res) => {
  res.json({
    message: 'ok',
    quotes: [
      {
        id: 1,
        content: 'Sometimes you win, sometimes you learn!',
        author: 'unknown',
        genre_type: 'motivational',
      },
      {
        id: 2,
        content: 'Do or do not, there is no try.',
        author: 'Yoda',
        genre_type: 'motivational',
      },
      {
        id: 3,
        content: 'A simple \'Hello\' could lead to a million things.',
        author: 'unknown',
        genre_type: 'motivational',
      },
    ]
  });
});

We can also put our data into a separate file and import it, using module.exports:

const quotes = require('./db/quotes-data');
app.get('/quotes', (req, res) => {
  res.json({
    message: 'ok',
    data: quotes,
  });
});

🚀 LAB!

Catch up in quotes-begin.

  • Within quotes-begin, run npm install to install the dependencies.
  • In server.js, add a route for GETting /quotes that sends back the data in ./db/quotes-data.js.
  • Also, what file we included to ignore node_modules and not push it to gitHub? Don't forget to include it ;)

Params

What if we only want information about one quote, though? We can do that using parameters, or params.

A route with params looks like this: /quotes/:id. The id stands for the variable parameter, which we can access on the request object, like so: req.params.id.

So if I was to say something like:

app.get('/:id', (req, res) => {
  res.send(`${req.params.id} is awesome!!!!!`);
});

I could go to any endpoint on localhost and get the text "[whatever thing I put in the address bar] is awesome!!!!" Once again, order matters -- my route with params has to be after my explicitly defined routes.

I can also use the params to programmatically get information from my database, like so:

app.get('/quotes/:id', (req, res) => {
  const requestedQuote = quotes.filter((quote) => {
    return quote.id == req.params.id;
  });
  res.json({
    message: 'ok',
    data: requestedQuote[0],
  });
});

This returns the quote object from my quotes array where the id of the object matches the ID that's been passed in the params.

🚀 Lab!

Catch up in quotes-begin.

  • In server.js, add a route for GETting quotes/:id, where :id is a number passed in from the server. The app should send back data about one quote with that particular ID.

Separating Concerns

Now, leaving all our routes in our server.js may seem like a good idea, but once our app starts to scale, we need to start separating our concerns. The MVC pattern itself places a lot of emphasis on modularity, as does node as a whole.

One way we can improve the modularity of our apps is by taking the routes out of server.js and putting them in their own routes directory.

  • mkdir routes & cd into it
  • touch quote-routes.js

Initializing Express Router

In routes/quote-routes.js:

const express = require('express');
const quoteRoutes = express.Router();

What this does is it initializes a new instance of express's router. Instead of having to say app.get(whatever) for all our different endpoints, we can create multiple instances of express router and use them for individual endpoints.

HERE is the docs for Express Router. Check them out!

So, we know we're using /quotes as an endpoint. Our quoteRoutes will control all the endpoints for /quotes. So, in quote-routes, we can say:

// still have to import the quote data
const quoteInfo = require('../db/quotes-data');

// the root route, `/quotes`
quoteRoutes.get('/', (req, res) => {
  res.json({
    message: 'ok',
    data: quotes,
  });
});

// need to export the files
module.exports = quoteRoutes;

We can move over the /quotes/:id route as well.

Telling our app to use the new route

Now, in server.js, we can import the new route, like so:

// below the index route
const quoteRoutes = require('./routes/quote-routes');
app.use('/quotes', quoteRoutes);

We can create and import as many routes as we want.

🚀 LAB!

Catch up in quotes-begin.

  • Create a routes folder.
  • Within that routes folder, create a file quote-routes.js.
  • Write the routes for the quotes.
  • In server.js, require the new route file.
  • Tell the app to use the quotes endpoint and pass all actions relating to that endpoint to our new route.

Serving an index page (if time permits)

Instead of just sending back json data, or "Hello World", it would be kind of nice if our app sent back an actual index page. Here's how we can set that up:

We first add a new directory called public and create an index.html.

Then, we need to tell our server.js where to look for static files.

// directly beneath where we set up the logger
app.use(express.static('public'));

Finally, we tell our root route to send the index.html file

app.get('/', (req, res) => {
  res.sendFile(path.join(__dirname, 'public', 'index.html'));
});

Now we can add JavaScript to that HTML file to make requests to our backend.

🚀 Lab!

Check out HERE and follow the instructions you find there!

Recap!

  • Express is a web application framework for Node.
  • It allows us to build RESTful APIs and web apps in JavaScript all the way down.
  • We control what data is sent back at which endpoint using routes.
  • Following the MVC pattern allows us to create our apps in a modular way.