Objectives |
---|
Explain parsing URL params and using query string params. |
Apply routing knowledge to build an Express application with dynamic routes. |
Explain the usefulness of middleware (e.g., body-parser ). |
- HTTP
- Resource path
- Query string
- HTTP verb
- Status code
- Middleware
- Intro (continued) to Express
- Routing
- HTTP GET
- Request Params
- Query Params
- Middleware
- Server-side JS
- Instead of DOM manipulation, we are interacting with the request / response cycle
- (B.Y.O.A.) Build your own API
Let's start with a simple Express application.
-
Make a directory and
server.js
mkdir quick_example cd quick_example/ touch server.js
-
Then create a
package.json
.npm init npm install --save express subl .
The folder structure will be as follows:
quick_example
├── node_modules/
└── express/
├── server.js
├── package.json
...
Now we need to write some code for our simple application.
server.js
// requirements
var express = require('express'),
app = express();
// a "GET" request to "/" will run the function below
// NOTE anyone know how we can better comment this code? *cough* jsdoc *cough*
app.get("/", function (req, res) {
// send back the response: 'Hello World'
res.send("Hello World");
});
// start the server
app.listen(3000, function () {
console.log("Go to localhost:3000/");
});
Now you can start the server:
node server.js
Building an application will require us to have a firm grasp of something we call routing. Each route is a combination of a Request Type and Path.
Request Type | Request Path | Response |
---|---|---|
GET |
/ |
Hello World |
GET |
/burgers |
Hamburger , Cheese Burger , Dble Cheese Burger |
GET |
/tacos |
Soft Taco , Crunchy Taco , Super Taco |
Let's build these into our application:
server.js
var express = require('express'),
app = express();
var burgers = [
"Hamburger",
"Cheese Burger",
"Dble Cheese Burger"
];
var tacos = [
"Soft Taco",
"Crunchy Taco",
"Super Taco"
];
app.get("/", function (req, res) {
res.send("Hello World");
});
app.get("/burgers", function (req, res) {
//send all the burgers
res.send(burgers.join(", "));
});
app.get("/tacos", function (req, res) {
//send all the tacos
res.send(tacos.join(", "));
});
app.listen(3000, function () {
console.log("Go to localhost:3000/");
});
What if we want to create an app that can dynamically say hello to anyone?
- Using url parameters add a dynamic route to the application, indicated by
:
and the variable name you want to use, we'll use:name
for the example below.
app.get("/greet/:name", function (req, res) {
res.send( "Hello, " + req.params.name );
});
Here we are seeing the first introduction to parameters that the application can identify. In the following route :name
is considered a route parameter. We can access it using req.params.name
.
Request Type | Request Path | Response |
---|---|---|
GET |
/greet/:name |
Hello, :name |
Generally, you don't want to cram everything into a route. Just imagine when there are multiple parameters in route. Or maybe we don't care about getting the order of the parameters correct. Luckily, there are query parameters you can include with each request.
Let's see query params in action. Go to https://google.com/search?q=kittens&tbm=isch
?
denotes the beginning of the query parameters.=
indicates an assignment; anything to the left is the key, while the right represents the value.&
allows for the input of multiple parameters, separating each.
Let's add our first route to practice query params.
app.get("/thank", function (req, res) {
var name = req.query.name;
res.send("Thank you, " + name);
});
Reset your server and go to localhost:3000/thank?name=jane. Note how we can now define parameters in the url after a ?
.
-
request params:
http://localhost:3000/icecream/flavors/:flavor
-
query params:
http://localhost:3000/icecream?flavor=SOMEFLAVOR
Generally if the parameter is identifying a specific entity or resource on it's own, you most likely want request params. If it is an optional param for this route, you generally should use query params.
Common cases for Request Params:
- database/item IDs - GET /contacts/348
- major components of the app - GET /posts/33
- resources!
- expressing hierarchies - GET /departments/44/employees/2
Request Params are not always IDs either; names can be used in some systems:
/departments/accounting/employees/LiuJanice
Common cases for Query Params:
- searches - GET /?q=kittens
- optional selections - GET /calculator?lang=en
- pagination - GET /posts?start=1&size=10
- other limits - GET /posts?since=2015-11-29
Finally you might use them both together in some cases: /posts/33/comments?limit=50
What is middleware? In terms of Express, middleware is a function with access to the request object (req), the response object (res), and the next middleware in the application’s request-response cycle, commonly denoted by a variable named next.
Middleware can:
- Execute any code.
- Make changes to the request and the response objects.
- End the request-response cycle.
- Call the next middleware in the stack.
You can create your own middleware, or use third-party modules. That's right, there are tons of useful middleware modules that are already out there which you can use to handle common challenges like authentication, validation, and parsing.
The body-parser
module is an example of some middleware that makes Express awesome. You can use it to parse out params from the POST'd form. This provides a different way to collect data instead of relying on URL or query params.
server.js
var express = require('express');
var bodyParser = require('body-parser');
var app = express();
// bodyParser.urlencoded() returns a function that will be called later in the app.post() route
var parseUrlencoded = bodyParser.urlencoded({extended: false});
// store for cities in memory (as long as server is running)
var cities = [];
app.get('/cities', function(req, res) {
res.json({cities: cities});
})
// passing multiple middleware functions to this route; they are executed sequentially.
// NOTE does it matter what we call the request and response parameter for our callback?
app.post('/cities', parseUrlencoded, function (request, response) {
// ^- middleware -^
var city;
var name = request.body.name;
var description = request.body.description;
city = { name: name, description: description}
cities.push(city);
// sending json
response.json({ cities: cities});
});
Another way to include middleware is via app.use
. This will include it on all routes.
var express = require('express');
var bodyParser = require('body-parser');
var app = express();
// store for cities in memory (as long as server is running)
var cities = [];
// body parser config for all routes
app.use(bodyParser.urlencoded({ extended: false }));
// ^ middleware ^
app.get('/cities', function(req, res) {
res.json({cities: cities});
})
app.post('/cities', function (request, response) {
var city;
var name = request.body.name;
var description = request.body.description;
city = { name: name, description: description}
cities.push(city);
// sending json
response.json({ cities: cities});
});
*Is there something missing from this code?
*We haven't installed the body-parser
package.
*What will the client see when it GETs /cities?
*How can we post to this?
- postman
- HTML form
<html>
<body>
<form method="POST" action="http://localhost:3000/cities">
<label for"cityName">city</label>
<input id="cityName" name="name" type="text" />
<label for"cityDesc">description</label>
<input id="cityDesc" name="description" type="text" />
<input type="submit" />
</form>
</body>
</html>
How can we write our own middleware? Let's say we want to make some alteration to the params so that further down the chain those alterations can be used.
// call this function on every route with the param of 'name'
app.param('name', function(request, response, next) {
// get name from params
var name = request.params.name;
// capitalize the name
var capitalizedName = name[0].toUpperCase() + name.slice(1).toLowerCase();
// set the value of the name to the capitalized version
request.params.name = capitalizedName;
// pass control to the next middleware function
next();
})
app.get("/greet/:name", function (req, res) {
res.send( "Hello, " + req.params.name );
});
Now every name is capitalized.
We learned about:
- Routing to different resources, i.e.
/burgers
and/tacos
. - Using dynamic parameters, i.e.
/burgers/:index
and/tacos/:index
to request specific data. - Using query parameters for dynamic requests to serve up dynamic responses.
- What middleware is and why it is helpful.
This will be essential knowledge for building and interacting with applications that contain multiple resources, such as users, posts, comments, etc.