Contents
Workflow & Submission
Helpful Concepts
Bitly Clone Spec
Deliverables
Getting Started
HINTS
Hint 1: Responding with a file
Hint 2: Adding a form
Hint 3: Saving URLS
Bonus
- Fork this repo onto your GitHub account.
- Clone the repo from your GitHub account onto your computer.
- Do your work in your local repo.
git add . -Aandgit commit -m "solution"git push origin masterto update your repo on GitHub.- Submit a link to the
bitly_clonereop on your GitHub account.
- A user can go to
localhost:3000or the root route and see aformto submit a url. - A user can submit a link to server using the form.
- A user should receive back a response with the url they can use to be redirected to the their submited url, i.e. something of the form
localhost:3000/urls/:id. - A user should be able to to use the url they receive back from your server as a redirect url.

User story: Program requirements written in terms of what a user should be able to do with the final product.
You'll need the following routes:
-
GET /to view a form -
POST /urlsto submit a url to shorten -
GET /urls/:idto be redirected to a url -
When your Express server receives a url from the client, you should push it into an array.
-
When your Express server responds, it should use the index of the url from the
urlsarray as theid. For example, if I submit the first url, I should get back the following:View your url at localhost:3000/urls/0 -
When your user goes to the
/urls/:idroute, you should look up the:idparam in theurlsarray to find the associated url and then redirect to it.
Wondering how to get started? This section will guide you through creating and setting up a simple example project. You can use the example project as a starting point for your app.
-
Make the required files and directories.
touch index.js mkdir views touch views/home.html echo "node_modules" >> .gitignore npm init npm install --save express
- The
index.jsfile holds all of our main application logic. It is the main file you'll work in for the rest of the lab. - We'll use the
views/home.htmlfile later by sending it as one of our responses. - The
npm initcommand asks some questions about your project, then automatically makes apackage.jsonfor you. - We're appending "node_modules" to our .gitignore file so that we don't upload that directory to our Github repository.
-
Make sure to setup your application to require Express.
var express = require("express"); var app = express();
-
Add your first simple route.
app.get("/", function (req, res) { res.send("Hello World"); });
-
Make sure your application server is listening.
app.listen(3000, function (req, res) { console.log("working!!") });
-
By this point, you should have an
index.jslike the following:var express = require("express"); var app = express(); app.get("/", function (req, res) { res.send("Hello World"); }); app.listen(3000, function (req, res) { console.log("working!!") });
Feeling stuck? Each hint below should help you get one step closer to completing the lab. Hint 0 has a few simple tips, and the other hints have more detailed instructions (with spoilers!).
- If you use
nodemon index.jsto start your sever, changes will be automatically updated. Otherwise, each time you change your server code, you'll have to stop the server (CTRL-C) and restart it (node index.js). - Make sure you check that each submited url starts with either
https://orhttp://. - To read form data, try using the Node package
body-parser(docs here). After you requirebody-parserin your code, set it up with the following line:app.use(bodyParser.urlencoded({extended: true}) // <-- add this
We want to send our ./views/home.html file as our response when someone goes to localhost:3000/.
```
./views/home.html
/|\
|
the dot means
current
working
directory
or cwd
```
-
We need to add some text to the
home.htmlfile<!DOCTYPE html> <html> <head> <title>Bitly Clone</title> </head> <body> Hello World </body> </html>
-
Let's send that file back as a response. Modify your
app.get("/", ...)route.app.get("/", function (req, res) { // note we are using `res.sendFile` res.sendFile(process.cwd() + "/views/home.html"); });
-
Test your app is running at
localhost:3000. Do you see hello world?
Quick Refactor
Just concatenating strings that represent file paths is dangerous. Just imagine adding up:
```javascript
"/views/" + "/home.html"
=> "/views//home.html"
```
Because it would be tough for you to go in and properly remove all the extra / marks (or add them when missing), we will use a built in Node utility to do this for us: path. Add the following to the top of your application.
var express = require("express");
var path = require("path"); // <-- add this
var app = express();Then define a variable that is your ./views/ directory path.
var express = require("express");
var path = require("path");
var app = express();
// a variable that represents "./views"
var views = path.join(process.cwd(), "views"); Now refactor your root app.get route to use the views variable.
app.get("/", function (req, res) {
var homePath = path.join(views, "home.html");
res.sendFile(homePath);
});We want to add a form to take in users' urls.
<form action="/urls" method="POST">
<input type="text" name="url" placeholder="New Url">
<button>Shorten URL</button>
</form>A Note About Forms
Note that in the form above we have both an action and a method.
| form attribute | role |
|---|---|
action="/urls" |
tells it where to send the request on the server |
method="POST" |
tells the server what type of request is being made |
Remember there are some conventions for certain types of requests.
If we submit the form from above, we will be making a POST /urls request, and we will also be sending form data in our request.
-
First we need to make sure our application can handle the form data being submitted.
npm install --save body-parser
-
Then we need to add
body-parserto our require statements.var express = require("express"); var path = require("path"); var bodyParser = require("body-parser"); // <-- add this var app = express(); app.use(bodyParser.urlencoded({extended: true}) // <-- add this // a variable that represents "./views" var views = path.join(process.cwd(), "views");
-
Now we need to set up our
app.postroute.app.post("/urls", function (req, res) { var newUrl = req.body.newUrl; res.send("Received " + newUrl); });
We want to keep track of our redirect urls.
-
In order to save a url, we need to add an array to store our
urls.var express = require("express"); var path = require("path"); var bodyParser = require("body-parser"); var app = express(); app.use(bodyParser.urlencoded({extended: true}); // a variable that represents "./views" var views = path.join(process.cwd(), "views"); var urls = [];// <--- Add this variable for urls
-
Now update your
app.postto push thenewUrlfrom the form into theurlsarray.app.post("/urls", function (req, res) { var newUrl = req.body.newUrl; urls.push(newUrl); var index = urls.length - 1; res.send("View your url at localhost:3000/urls/" + index)); });
-
We need to add a route so that
/urls/:indextakes us to our requested url.app.get("/urls/:index", function (req, res) { var url = urls[req.params.index]; res.redirect(url); });
Because using an array index doesn't obscure how we are looking up the submitted links, our site is vulnerable. Nothing is stopping someone from going through every index to see what links have been submitted.
localhost:3000/urls/0
localhost:3000/urls/1
localhost:3000/urls/2
...
localhost:3000/urls/99
-
Use
npmto installsecure-random-
npm install --save randomstring -
In the node repl verify the following behavior.
var RString = require("randomstring"); RString.generate() // => "XwPp9xazJ0ku5CZnlmgAx2Dld8SHkAeT"
-
-
Get rid of your array and use an Object to store a new random string key for each submitted url value.
-
Your server should now respond with the following:
``` Visit your url at localhost:3000/urls/XwPp9xazJ0ku5CZnlmgAx2Dld8SHkAeT ```


