...
 
Commits (36)
/*
* Hints:
*
* Arrays are sets of data. They're defined using bracket-syntax, like this:
*
* var array = [1, 2, 3];
*
* An object is a data structure with key and value. A simple object looks like this:
*
* var instructor = {
* name: "Kristian"
* };
*
* Object values can be referenced by their key. Using the above object, we can get `name`:
*
* console.log(instructor.name)
*
* An array can contain objects. A simple example (formatted across multiple lines for ease
* of reading) might look like:
*
* var array = [
* {
* value: 1
* },
* {
* value: 2
* }
* ]
*
*/
// No changes are needed above this line.
/*
* Exercise goals:
* 1. Define an array (`cities`) of city objects.
* 2. A city object has a single key `name`, with a string value.
* 3. The tests will look at the `cities` variable for the presence of at least two objects, and
* log the `name` value of each.
*/
var cities = [
{ name: "Seattle" },
{ name: "Portland" },
{ name: "Los Angeles" },
{ name: "San Francisco" }
];
// No changes are needed below this line.
const assert = require("assert");
assert.notEqual(cities.length, 0, "The cities variable should have at least one object inside of it");
assert.notEqual(cities.length, 1, "Try defining more than one city object inside of the cities array");
assert.notEqual(
cities.length,
0,
"The cities variable should have at least one object inside of it"
);
assert.notEqual(
cities.length,
1,
"Try defining more than one city object inside of the cities array"
);
cities.forEach(function(city) {
assert.notEqual(city.name, undefined, "A city object inside of cities must have a name value")
assert.notEqual(
city.name,
undefined,
"A city object inside of cities must have a name value"
);
console.log(city.name);
});
......
const assert = require("assert");
// No changes are needed above this line.
// Define a cities array that contains the cities
// Phoenix, Los Angeles, and Seattle.
var cities;
var cities = ["Phoenix", "Los Angeles", "Seattle"];
var citiesString = cities.map(function(city) {
// What should map return here to allow the
// below "assert" check to be true?
return // ???
}).join(", ");
var citiesString = cities
.map(function(city) {
return city;
})
.join(", ");
assert.equal(citiesString, "Phoenix, Los Angeles, Seattle")
assert.equal(citiesString, "Phoenix, Los Angeles, Seattle");
// No changes are needed below this line.
assert.notEqual(cities.length, 0, "The cities variable should have at least one object inside of it");
assert.notEqual(cities.length, 1, "Try defining more than one city object inside of the cities array");
assert.equal(cities.find(c => c === "Phoenix"), "Phoenix", "The cities array should include Phoenix");
assert.notEqual(
cities.length,
0,
"The cities variable should have at least one object inside of it"
);
assert.notEqual(
cities.length,
1,
"Try defining more than one city object inside of the cities array"
);
assert.equal(
cities.find(c => c === "Phoenix"),
"Phoenix",
"The cities array should include Phoenix"
);
console.log("Passed! :)");
class Car {
constructor() {
/*
* Add the following attributes and their default values:
* - peopleInCar, which stores the number of people in the
* car. This should default to 0.
* - seats, which stores the number of available seats in the
* car. This should default to 4.
* - gas, which stores the percentage of gas available. This
* defaults to 100.
* - mileage, which stores the number of miles driven. This
* defaults to 0.
*/
this.peopleInCar = 0;
this.seats = 4;
this.gas = 100;
this.mileage = 0;
}
/*
* Define the drive function, which subtracts 1 from gas, and
* adds 1 to mileage.
*/
drive() {
this.gas -= 1;
this.mileage += 1;
}
addPerson() {
......@@ -41,59 +32,29 @@ class Car {
class SportsCar extends Car {
constructor() {
super()
/*
* Define gas to 50.
* Define seats to 2.
*/
super();
this.gas = 50;
this.seats = 2;
}
/*
* Consider the following functions, addPerson and removePerson.
* If they simply call the "super" function, do they need to be
* defined?
*
* Try removing them and re-running the tests to see if it makes
* a difference.
*/
addPerson() {
super.addPerson();
}
removePerson() {
super.removePerson();
}
/*
* A sports car uses more gas than a normal car.
* Define this function so that it subtracts 5 gas units instead
* of 1.
*
* For a bonus assignment, consider adding additional logic, so that if
* the amount of gas available is 0, the car is unable to drive
* (return false).
*/
drive() {
super.drive();
super.drive();
super.drive();
super.drive();
super.drive();
}
}
class ElectricCar extends Car {
constructor() {
super()
/*
* An electric car uses a battery instead of gas.
* Define this.battery and default to 100.
*/
super();
this.battery = 100;
}
/*
* An electric car uses a battery instead of gas.
* Define this function so that it subtracts 1 battery unit instead
* of a gas unit.
*/
drive() {
super.drive();
this.battery -= 1;
this.mileage += 1;
}
}
......@@ -107,38 +68,77 @@ assert.equal(standard.seats, 4, "A Car should have 4 seats.");
assert.equal(standard.gas, 100, "A Car should start with 0 gas.");
assert.equal(standard.mileage, 0, "A Car should start with 0 mileage.");
standard.addPerson()
assert.equal(standard.peopleInCar, 1, "Calling addPerson() should add 1 to peopleInCar.");
standard.addPerson()
assert.equal(standard.peopleInCar, 2, "Calling addPerson() should add 1 to peopleInCar.");
standard.addPerson()
standard.addPerson()
assert.equal(standard.peopleInCar, 4, "Calling addPerson() should add 1 to peopleInCar.");
standard.addPerson()
assert.equal(standard.peopleInCar, 4, "Calling addPerson() should add 1 to peopleInCar.");
standard.removePerson()
standard.removePerson()
standard.removePerson()
assert.equal(standard.peopleInCar, 1, "Calling removePerson() should subtract 1 from peopleInCar.");
standard.removePerson()
assert.equal(standard.peopleInCar, 0, "Calling removePerson() should subtract 1 from peopleInCar.");
standard.removePerson()
assert.equal(standard.peopleInCar, 0, "Calling removePerson() when no one is the car should do nothing.");
standard.drive()
standard.addPerson();
assert.equal(
standard.peopleInCar,
1,
"Calling addPerson() should add 1 to peopleInCar."
);
standard.addPerson();
assert.equal(
standard.peopleInCar,
2,
"Calling addPerson() should add 1 to peopleInCar."
);
standard.addPerson();
standard.addPerson();
assert.equal(
standard.peopleInCar,
4,
"Calling addPerson() should add 1 to peopleInCar."
);
standard.addPerson();
assert.equal(
standard.peopleInCar,
4,
"Calling addPerson() should add 1 to peopleInCar."
);
standard.removePerson();
standard.removePerson();
standard.removePerson();
assert.equal(
standard.peopleInCar,
1,
"Calling removePerson() should subtract 1 from peopleInCar."
);
standard.removePerson();
assert.equal(
standard.peopleInCar,
0,
"Calling removePerson() should subtract 1 from peopleInCar."
);
standard.removePerson();
assert.equal(
standard.peopleInCar,
0,
"Calling removePerson() when no one is the car should do nothing."
);
standard.drive();
assert.equal(standard.gas, 99, "Calling drive() should remove 1 from gas.");
assert.equal(standard.mileage, 1, "Calling drive() should add 1 to mileage.");
var sports = new SportsCar();
assert.equal(sports.gas, 50, "The SportsCar class should start with 50 gas.");
sports.drive()
assert.notEqual(sports.gas, 44,
"The method drive() for SportsCar removed 6 gas, instead of 5. Note that since the parent class Car removes 1 gas during the drive() method, you should subtract 4 gas instead of 5.");
assert.equal(sports.gas, 45, "Calling drive() on SportsCar should remove 5 gas.");
sports.drive();
assert.notEqual(
sports.gas,
44,
"The method drive() for SportsCar removed 6 gas, instead of 5. Note that since the parent class Car removes 1 gas during the drive() method, you should subtract 4 gas instead of 5."
);
assert.equal(
sports.gas,
45,
"Calling drive() on SportsCar should remove 5 gas."
);
var electric = new ElectricCar();
electric.drive()
assert.equal(electric.battery, 99, "Calling drive() on ElectricCar should remove 1 battery unit.");
electric.drive();
assert.equal(
electric.battery,
99,
"Calling drive() on ElectricCar should remove 1 battery unit."
);
// assert.notEqual(electric.gas, 99, "The electric car still has a gas value that is being used by `.drive`.");
......
......@@ -2,60 +2,38 @@ const assert = require("assert");
var integers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
// No changes are needed above this line.
/*
* Progressively filtering an array simply means
* calling `.filter` on a succession of arrays.
*
* For instance, we might define an array as:
* var array = [1, 2, 3];
*
* Filtering on that array and capturing the value would mean:
* var newArray = array.filter(function(num) {
* return num != 1;
* });
*
* To "progressively" filter down our sets, we might filter on
* newArray, thus "combining" filters:
*
* var newerArray = newArray.filter(function(num) {
* return num != 2;
* });
*/
var notZero;
var lessThanFive;
/*
* As with many programming languages, determing whether a number
* is even or odd in JavaScript can be done with the % operator.
* This operator calculates the "remainder" of a division:
*
* 2 % 2 == 0, because there is no left over values from 2 / 2.
* 3 % 2 == 1, because there is a 1 left over values from 3 / 2.
*
* Therefore, an odd number can be checked using `x % 2 == 1`
*/
var oddNumbers;
var greaterThanOne;
/*
* What do you expect the final value to be? Can you define it as a
* number below? If you aren't sure, try running the tests while
* logging (console.log) `greaterThanOne`.
*/
var finalValue;
// No changes are needed below this line.
assert.equal(integers.length, 10, "The integers array shouldn't be changed from its original implementation");
assert.equal(notZero.length, 9, "The notZero array should include every number that isn't equal to zero");
assert.equal(lessThanFive.length, 4, "The lessThanFive array should include every number less than five, and should also be filtered from notZero");
assert.equal(oddNumbers.length, 2, "The oddNumbers array should include every odd number in the set, and should be filtered from lessThanFive");
assert.equal(greaterThanOne.length, 1, "The greaterThanOne array should include every number greater than one, and should be filtered from oddNumbers");
var notZero = integers.filter(num => num !== 0);
var lessThanFive = notZero.filter(num => num < 5);
var oddNumbers = lessThanFive.filter(num => num % 2 === 1);
var greaterThanOne = oddNumbers.filter(num => num > 1);
var finalValue = 3;
assert.equal(
integers.length,
10,
"The integers array shouldn't be changed from its original implementation"
);
assert.equal(
notZero.length,
9,
"The notZero array should include every number that isn't equal to zero"
);
assert.equal(
lessThanFive.length,
4,
"The lessThanFive array should include every number less than five, and should also be filtered from notZero"
);
assert.equal(
oddNumbers.length,
2,
"The oddNumbers array should include every odd number in the set, and should be filtered from lessThanFive"
);
assert.equal(
greaterThanOne.length,
1,
"The greaterThanOne array should include every number greater than one, and should be filtered from oddNumbers"
);
assert.equal(finalValue, 3, "The final value should just be 3");
console.log("Passed! :)");
var didSomethingElse = false;
var doSomethingElse = () => { didSomethingElse = true };
var doSomethingElse = () => {
didSomethingElse = true;
};
var ateFood = false;
var eatFood = () => { ateFood = true };
// No changes are needed above this line.
/*
* If/else allows multiple "paths" to be taken in code.
*
* var thirsty = false;
* if (thirsty) {
* console.log("I am thirsty");
* } else {
* console.log("I am not thirsty");
* }
*
* In the below example, the variable `hungry` is set to true.
* Using an if/else statement, ensure the following things happen:
* 1. If hungry, call the function eatFood: `eatFood()`
* 2. If hungry, set the value `hungry` to `false`.
* 3. If not hungry, call the function doSomethingElse: `doSomethingElse()`.
*/
var eatFood = () => {
ateFood = true;
};
var hungry = true;
/*
* What value should replace `false` in the `if` section of this code?
*/
if (false) {
// What TWO things should happen if the `if` expression is true?
if (hungry) {
eatFood();
hungry = false;
} else {
// What ONE thing should happen if the `if` expression is false?
doSomethingElse();
}
// No changes are needed below this line.
const assert = require("assert");
assert.equal(ateFood, true, "The function `eatFood` should have been called in the if block of the code.");
assert.equal(
ateFood,
true,
"The function `eatFood` should have been called in the if block of the code."
);
assert.equal(hungry, false, "hungry should be false.");
assert.equal(didSomethingElse, false, "The function `didSomethingElse` shouldn't be called: make sure that it exists in the else block of the code.");
assert.equal(
didSomethingElse,
false,
"The function `didSomethingElse` shouldn't be called: make sure that it exists in the else block of the code."
);
console.log("Passed! :)");
......@@ -2,27 +2,16 @@ var helloFunction = function(name) {
return "Hello " + name;
};
// No changes are needed above this line.
/*
* Variables can be set using the "var" keyword in JavaScript.
* Variables can be simply declared, such as `var me`, which initializes
* the variable `me` with no value.
*
* Variables can also be set to a value using the `=` syntax, such as:
*
* var age = 99;
*
* In doing so, the `age` variable now has a value of 99.
*
*/
var me;
var me = "Kristian";
// No changes are needed below this line.
const assert = require("assert");
assert.notEqual(me, undefined, "The me variable should be set to a string of your name, such as:\n\nvar me = 'NAME';\n");
assert.notEqual(
me,
undefined,
"The me variable should be set to a string of your name, such as:\n\nvar me = 'NAME';\n"
);
console.log(helloFunction(me));
console.log("Passed! :)");
/*
* Hints:
*
* Functions are pieces of JavaScript code that can be defined and later executed.
* Functions are defined as such:
*
* function() {
* }
*
* Functions can accept arguments, which can be used inside the function body:
*
* function(anArg) {
* console.log(anArg);
* }
*
* Functions can be named and referred to later by that name:
*
* function namedFunc() {
* }
*
* A function can be executed using the () syntax:
*
* namedFunc();
*
* If a function has arguments, they can be provided in the () syntax:
*
* function namedFunc(arg) {
* }
*
* namedFunc(1);
*
* Functions often "return" values, in many cases based on the arguments they receive:
*
* function double(number) {
* return number * 2;
* }
*
* double(3); // 6
*
*/
// No changes are needed above this line.
/*
* Exercise goals:
* 1. Define a `me` variable with your first name.
* 2. Define a named function called `printMe` with a `name` argument.
* 3. In the function body of `printMe`, return the string "I am <name argument>".
*/
var me;
var me = "Kristian";
function printMe(name) {
return "I am " + name;
}
// No changes are needed below this line.
const assert = require("assert");
assert.notEqual(me, undefined, "The me variable should be set to a string of your first name, such as:\n\nvar me = 'NAME';\n");
assert.notEqual(
me,
undefined,
"The me variable should be set to a string of your first name, such as:\n\nvar me = 'NAME';\n"
);
assert.notEqual(printMe, undefined, "The function printMe should be defined");
var funcResponse = printMe(me);
assert.notEqual(funcResponse, "I am" + me,
assert.notEqual(
funcResponse,
"I am" + me,
"Adding strings together often requires a space: your function returns 'I am<name> instead of 'I am <name>'. Try adding a space at the end of 'I am'."
);
assert.equal(funcResponse, "I am " + me, "The function printMe should return a string in the format 'I am <me>'");
assert.equal(
funcResponse,
"I am " + me,
"The function printMe should return a string in the format 'I am <me>'"
);
console.log(printMe(me));
console.log("Passed! :)");
/*
* Hints:
*
* JavaScript "scope" is the "view" that the function or currently executing code has.
* This includes what other variables and functions are available to be referenced in the code.
* We often refer to the current context as `this` -- the actual value of `this` can be a source
* of confusion for many JavaScript developers.
*
* For instance, in the below example, calling the `findName` function, which looks for the `name`
* value on the context `this`, can either refer to a top-level (global) variable, _or_ the key on
* an object, depending on what context the function is called in.
*
* var name = "JavaScript";
* var me = { name: "Kristian" };
*
* function findName() {
* console.log(this.name);
* }
*
* findName(); // "JavaScript"
* findName.call(me); // "Kristian"
*
* The `.bind` function can permanently change the scope of a function to a specific context.
* Below, `.bind` sets the context of `findName` to always refer to the `me` object:
* Note that we re-assign the value of `findName` to the response of `findName.bind`.
*
* var name = "JavaScript";
* var me = { name: "Kristian" };
*
* function findName() {
* console.log(this.name);
* }
*
* findName = findName.bind(me);
* findName() // "Kristian"
*
*/
// This line can be ignored! It's used to set up a context inside of the Node/JS intepreter.
(function() {
this.name = "JavaScript";
this.age = 22;
this.name = "JavaScript";
this.age = 22;
function printNameAndAge() {
return this.name + " is " + this.age;
}
// No changes are needed above this line.
// Exercise goals have been in-lined throughout the code:
function printNameAndAge() {
return this.name + " is " + this.age;
}
// Goal #1: Define a `me` object that contains the keys `name` and `age`.
var me;
var me = { name: "Mary", age: 35 };
/*
* Goal #2:
*
* Update correctlyBound to the *value* of the function printNameAndAge.
* The result should be the result of the function _after_ it is bound
* to the context me. There are two ways to do this:
*
* 1. Calling `printNameAndAge` with the context `me`
* 2. Binding `printNameAndAge` to the context `me`.
* Note that if you bind the function, you'll need to also call it _after_
* binding it, by adding an additional set of parentheses `()` at the end.
* For instance:
* myFunc = myFunc.bind(this);
* var newValue = myFunc();
*
* (bonus: get the tests to pass with both!)
*/
var correctlyBound = printNameAndAge();
var correctlyBound = printNameAndAge.bind(me)();
// OR var correctlyBound = printNameAndAge.call(me);
// No changes are needed below this line.
// No changes are needed below this line.
const assert = require("assert");
assert.notEqual(typeof correctlyBound, 'function', "correctlyBound is currently a function -- this means that you haven't correctly bound it to a context. Ensure that the variable definition ends with open and closed parentheses in some format.");
assert.notEqual(correctlyBound, "JavaScript is 22", "The context of function `printNameAndAge` is currently top-level, and returning the string 'JavaScript is 22'. Instead, either call the function with the context of your 'me' object, or permanently bind it to 'me'.");
const assert = require("assert");
assert.notEqual(
typeof correctlyBound,
"function",
"correctlyBound is currently a function -- this means that you haven't correctly bound it to a context. Ensure that the variable definition ends with open and closed parentheses in some format."
);
assert.notEqual(
correctlyBound,
"JavaScript is 22",
"The context of function `printNameAndAge` is currently top-level, and returning the string 'JavaScript is 22'. Instead, either call the function with the context of your 'me' object, or permanently bind it to 'me'."
);
console.log(correctlyBound);
console.log("Passed! :)");
console.log(correctlyBound);
console.log("Passed! :)");
// This line can also be ignored.
})()
// This line can also be ignored.
})();
var aNumber = 15;
var myFunc = function() {
aNumber = 10;
var aNumber = 10;
return aNumber;
}
......
const assert = require("assert");
// No changes are needed above this line.
var a = 10;
var b = function(a) {
return 100;
}
};
function sillyScope(b) {
// !b: if there is no b set
if (!b) {
this.b = function(a) {
return a + 5;
}
};
}
// If b is set, use it, otherwise,
// use this.b.
a = (b || this.b)(0);
var a = (b || this.b)(0);
return a;
};
}
sillyScope();
/*
* Consider the fifth line of this file, where
* a is set to 10. The below test, which ensures
* that a is equal to 10, fails.
*
* Can you identify the piece of code that causes this to fail?
* If so, try fixing that code and making this test pass.
*/
assert.equal(a, 10);
/*
* The below code passes `null` to the function sillyScope.
* sillyScope looks for a function argument `b`, which it
* calls as `c` with an argument of 0.
*
* Since there is no argument `b` provided, sillyScope will
* make its own function `c`. Can you find that function,
* and change the below equality test from -1 to the actual
* value that it returns?
*/
var c = sillyScope(null)
assert.equal(c, -1);
/*
* The below code passes the function `b` to sillyScope.
*
* Can you find function `b` and determine what it returns?
* Does that value depend on the passed in argument?
*
* Change the equality test below to what the value of `d`
* will be.
*/
var d = sillyScope(b)
assert.equal(d, -1);
var c = sillyScope(null);
assert.equal(c, 5);
// No changes are needed below this line.
var d = sillyScope(b);
assert.equal(d, 100);
console.log("Passed! :)");
const assert = require("assert");
var countVowels = function(str) {
/*
* Implement a function to count the number of vowels
* in the argument str.
*
* Replace this return call with the correct number of
* vowels.
*/
return -1;
}
// No changes are needed below this line.
let count = 0;
str.split("").forEach(function(letter) {
if (["a", "e", "i", "o", "u"].includes(letter)) {
count += 1;
}
});
return count;
};
var checkCount = (str, expected) => {
var check = countVowels(str);
assert.equal(check, expected,
`Expected countVowels to return ${expected} for '${str}', got ${check}`);
}
assert.equal(
check,
expected,
`Expected countVowels to return ${expected} for '${str}', got ${check}`
);
};
checkCount("the", 1);
checkCount("too", 2);
......
......@@ -20,58 +20,14 @@ const parseResponse = resp => console.log("Response is: ", resp.data);
// No changes are needed above this line
/*
* This exercise, dealing with Node async behavior, shows off a couple
* different things that can happen when writing Node applications.
*
* To begin, we have a request to a website (defined w/ the variable url above)
* that takes ten seconds to load. Because of this, doing a "synchronous" request
* will block the rest of our application. This is more common than you'd think!
*
* Things like databases and APIs can take a long time to load, and even with just a
* few synchronous calls in your application, it's very likely your application can
* dramatically slow down.
*
* To demo this, we're using the "sync-request" library, which makes completely blocking
* and synchronous requests to the URL.
*
* Populate the empty work function with two lines:
* 1. First, call the makeRequest function and set it to the variable response
* 2. Call the parseResponse with the argument response.
*
* Try running this file, and notice the 10s lock on the application. Once it finishes,
* the response is logged, and two other lines
* are logged to the console.
*
* It's slow! We can do better. Next, replace requestLibrary with a promise-enabled library, "axios".
*
* Now we can use promises inside of the work function. Replace the content of the work function with:
* 1. Calling the makeRequest function...
* 2. Chaining .then to the end of the function, passing the function argument parseResponse
*
* Execute this file again, and notice that the two console.logs AFTER the work() function call
* are immediately executed. This application is now non-blocking! You can test this by adding more
* console.log lines after these two, to confirm that the rest of this file is being executed sequentially,
* WHILE the work function resolves this request.
*
* Finally, instead of using .then, let's try using an async function. Before "function work()", add the prefix
* "async". Now rewrite the content of work with:
* 1. Define the variable response, and set it to "await makeRequest()". This means that we'll
* "wait" (using promises underneath) for this request to finish.
* 2. Call parseResponse with the argument response.
*
* Run the file again. You shouldn't notice any difference from the promise version, but noticably, the way
* that the function is WRITTEN is a lot like our original solution, which was blocking. This indicates a
* pretty consistent trend of async functions: they read a lot _clearer_ than promise _or_ callback
* implementations, but underneath, they're still non-blocking. Neat!
*
*/
const requestLibrary = syncrequest;
const requestLibrary = axios;
console.log("Beginning request...");
async function work() {}
async function work() {
const response = await makeRequest();
parseResponse(response);
}
work();
......
const url = "https://byteconf-training-chirp.herokuapp.com";
const axios = require("axios");
const url = "https://bytesized-training-chirp.herokuapp.com";
/*
* This is the base API layer for interfacing with
* the chirp API. A couple things to be done here:
*
* 1. Import the axios package. If you're unsure how to
* do that, try finding axios on GitHub and looking
* at the first line of the "Example" section.
* 2. Use axios.create to create a custom API function
* that we can re-use in other files. To do this,
* call axios.create and pass in an object as the
* argument to this function. Set "baseURL" to the
* variable url. Set this to the variable api.
* 3. Make api the export for this module, by setting
* module.exports to api.
*/
const api = axios.create({
baseURL: url
});
module.exports = api;
/*
* In this file, we'll define a few specific methods for requesting
* and updating content from our API.
*
* 1. Import the api file. It's _relative_ to this file, so
* you can require it with a path like ./myFile. What's the filename
* for the API module?
* 2. Define the first API method: getPosts. It should call
* (and return) the value of calling the get function on api, passing in
* the argument "/posts", which specifies the "path" we want to call on the API.
* 3. Define the createPost method, which takes two function arguments: text, and user.
* Call (and return) the post method on API, passing two arguments into it: the string
* "/posts", and an object with the key and value pairs of text and user.
* 4. Finally, export these two functions using module.exports. module.exports should be
* an object: for instance, if I wanted to export the function myFunc, I might do:
*
* module.exports = { myFunc: myFunc }
*
* Note that in ES6, you can simplify this to:
*
* module.exports = { myFunc }
*
* Export both getPosts and createPost.
*/
const api = require("./api");
const getPosts = () => api.get("/posts");
const createPost = (text, user) => api.post("/posts", { text, user });
module.exports = { getPosts, createPost };
/*
* In this exercise, we'll focus on creating a basic Express server.
*
* The server will serve one route - "/", * and will accept a "name"
* param which it will render back in the response, if it's provided.
*
* To begin, require the "express" package and set it to the variable
* "express" (remember to run `npm install`, if you haven't already).
*
* With the express package set up, call the express function (with no
* arguments) and assign it to the value "app".
*
* Let's begin by actually setting up the server to handle requests.
* Our new "app" has a function * "listen", which accepts two arguments:
*
* 1. A port to "listen" on. Try 8080, which means that your server will
* be accessible at localhost:8080 (running locally on your machine).
*
* 2. A callback function, which will be called once the server is ready
* for requests. Try console.logging something like "Express is now
* listening on port 8080".
*
* Bonus points if you set "port" to its own variable, passing it in
* as the first argument to listen, _and_ log it out in the callback
* function.
*
* Extra bonus points if you can figure out how to use a PORT environment
* variable passed in when you run the application. I'll give you a hint:
* environment variables are accessible in Node via `process.env`.
*
* 3. Now it's time to set up our first route. An express route is set up by
* doing the following:
*
* - Choosing an HTTP method. In our case, let's use GET.
* - Choosing a route to "handle". As mentioned in the beginning of the docs,
* we'll use "/".
* - Defining a callback function, which has two arguments: request, and response.
*
* Call app.get, passing in the "route" as the first argument, and defining
* a callback function as the second argument. Again, this function has
* two arguments, request, and response (but you can name them whatever you'd like)!
*
* In the callback function for this route, we want to do two different things:
*
* - First, check for the presence of a "name" parameter. This can be done by referencing the
* object req.query and looking up the key "name" inside of it. Assign this to the variable "name".
* - Now we should send something back in the response. Use res.send to send plaintext
* back from the server. Let's do something _slightly_ dynamic: if a name param is present,
* return the string `Hello, ${name}!`, otherwise, just return "Hello, world!"
*
* When you've completed all these tasks, try running the server with `node index.js`. You can test
* the server by going to localhost:PORT, where PORT is the first argument in app.listen.
*
* Try first visiting the root page on its own (localhost:8080/, for instance) and then again with
* a name parameter (localhost:8080/?name=Kristian). If everything is working, you should see
* the name param returned on-screen. Congrats!
*
*/
const express = require("express");
const app = express();
app.get("/", (request, response) => {
const name = request.query["name"];
if (name) {
response.send(`Hello, ${name}!`);
} else {
response.send(`Hello, world!`);
}
});
app.listen(8080, () => "Express is now listening on port 8080");
const users = require("./users");
/*
* In this exercise, we'll create an almost fully-featured
* Express server, which handles all the basic CRUD routes for a "user" resource.
* Here's what it will look like when done:
*
* GET /users
* GET /users/:id
* POST /users
* PUT /users/:id
* DELETE /users/:id
*
* To start, we need to set up our express application. Do the following - looking
* at our previous exercise if you don't recall how to do something specifically:
*
* 1. Import express, and create an "app" variable that is the result of calling express().
* 2. Set up the application to listen on port 8080.
* 3. Set module.exports to app.
*
* Now we can set up the routes for our application.
*
* First, define GET "/users". It should use `res.json` to send back JSON - pass in the results
* of calling the function users.getUsers.
*
* Next, define GET "/users/:id". It should use `res.json` to send back JSON, with the result of
* calling users.getUser with the "id" param from the URL. Remember that params can be used with
* "req.params" - experiment with booting the application (`node index.js`) and console.log'ing
* req.params on this route, if you aren't sure how req.params is formatted.
*
* Now, define PUT "/users/:id". Remember that app.get is one of many methods - app.put is available as
* well. In the function body, set the variable user to the result of the function users.updateUser, passing
* in the argument "req.body". This is the request "body" that is sent from the client.
*
* Your application needs to "opt-in" to parsing request bodies. To do this, require the "body-parser" package,
* setting it to a variable of your choice (I like "bodyParser"). After you set up the "app" variable, call
* app.use, passing in the argument bodyParser.json(). This is an express "middleware" function, which
* adds additional functionality to your application.
*
* With that enabled, the PUT "/users/:id" route should be able to correctly parse and use req.body. Use res.json
* to return this "created" user back in the response.
*
* Next, define POST "/users". Set the variable user to the result of users.createUser, passing in req.body as the
* function argument. Use res.json to send this back to the user.
*
* Finally, define DELETE "/users/:id". Call users.deleteUser, passing in the "id" param (look at the previous routes
* for a reminder on how to do this). This doesn't need to be assigned to a variable - since we're deleting the user,
* there's nothing to return here. Instead, call res.sendStatus, passing in the argument 204 (a number). This is an
* HTTP "status code", in this case, indicating "No Content". If you're unfamiliar with HTTP status codes,
* https://httpstatuses.com is a good resource.
*
* To test your work, run `npm test`. This will call `tests.js`, and test each route separately. If you're comfortable
* with cURL or similar HTTP request tools, you can also test your application by setting up requests to localhost:8080.
* Our tests do something similar to this.
*
* If your tests pass, congrats! You did it :)
*
*/
const PORT = process.env.PORT || 8080;
const express = require("express");
const app = express();
const bodyParser = require("body-parser");
app.use(bodyParser);
app.get("/users", (req, res) => {
res.json(users.getUsers());
});
app.get("/users/:id", (req, res) => {
res.json(users.getUser(req.params.id));
});
app.put("/users/:id", (req, res) => {
const user = users.updateUser(req.body);
res.json(user);
});
app.post("/users", (req, res) => {
const user = users.createUser(req.body);
res.json(user);
});
app.delete("/users/:id", (req, res) => {
users.deleteUser(req.params.id);
res.sendStatus(204);
});
app.listen(PORT, () => `Express is listening on port ${PORT}`);
module.exports = app;
const PORT = process.env.port || 8080;
const express = require("express");
const chalk = require("chalk");
const PORT = process.env.port || 8080;
const app = express();
/*
* In this exercise, we'll enhance our express application by adding
* "middleware". Middleware is, like it says, a "middle" layer of code
* that is run by Express as a request is being handled. There's a _ton_
* of different things that middleware is used for:
*
* - Logging
* - Authentication
* - Redirecting
* - Other functionality (parsing)
*
* Generally, you can think of middleware as a good solution if you want to
* do something for _every_ route in your application.
*
* Logging is a great use-case! While there's a number of great open-source
* logging solutions (for instance, the express team maintains their own called
* "morgan": https://github.com/expressjs/morgan), we'll write our own as a good
* exercise in understanding how middleware works.
*
* A piece of middleware is just a function, at its simplest form. A middleware
* function looks _very_ similar to a callback function for a route handler
* (like the app.get("/") call below):
*
* app.use(function (req, res, next) {
* console.log('URL requested at: ', Date.now())
* next()
* })
*
* Notice the function called - app.use. This specifies that we're adding a piece
* of middleware, directly on the Express app itself. This will be called every
* time a route is handled by our application. In this simplest form, we'll
* just console.log the current date and time when the URL is requested. The last
* line in this, "next()", just tells Express to continue with the request. We'll
* leave it as-is and add it in all our middleware.
*
* Let's add our own middleware. We want to log a number of things - I'm going
* to give a list of what we want, and encourage you to experiment with looking
* at the Express documentation to figure out how to log each piece. Specifically,
* every time a route is requested, we should console.log the following:
*
* - HTTP method
* - Request URL (_with_ parameters is okay, too - for instance, either "/about" or "/about?param=Test")
* - Date (use Date.now() as seen above)
*
* Log it in the following format:
*
* [METHOD] URL - DATE
*
* Try requesting "/" or "/about" in-browser to see the new log format (restart your app in case it
* doesn't show up, too).
*
* Now, let's add some more interesting data. Middleware allows you to "hook" into events as the
* request/response flow happens in your Express application. If we wanted to know, for instance,
* what the response sent back to the client was (i.e. was it a successful request?), we can hook
* on to the "finish" event for the response, like so:
*
* app.use((req, res, next) => {
* res.on("finish", () => {
* // Do something here, like log
* });
*
* next();
* });
*
* Let's update the format of our logging middleware to include the response "status", defined
* at res.statusCode. Because we need to wait for the response to "finish", move the console.log
* call inside of the callback function for the "finish" event and reformat the log like:
*
* [METHOD] URL STATUS - DATE
*
* Finally, we can make this log a bit more interesting by adding some colors! Import the "chalk"
* package using require at the beginning of this file, and then use some of the chalk methods
* to give the text some color. For instance, you can define the variable method with the following:
*
* const method = chalk.magenta(`[${req.method}]`);
*
* In this case, we're wrapping [${req.method}] in the color magenta. There's lots of colors supported:
* check out the chalk docs for more.
*
* As the final part of this exercise, we should look at the status code and return a particular color
* depending on whether the request was successful or not. For instance, if we request a URL that
* the application doesn't know how to handle, Express will return a status code of 404. Let's define
* a variable "status", which calls the function chalk.red if the response status code equals 404,
* or chalk.green if it's equal to anything else. Pass the response status code into both of these functions -
* if you're unsure where this is set, check out the documentation for the response class for express:
*
* https://expressjs.com/en/4x/api.html#res
*
* If you get stuck, no worries! We'll look at the final solution together. Mine looks something like
* this:
*
* https://imgur.com/a/i8XXgf1
*
*/
app.use((req, res, next) => {
res.on("finish", () => {
const method = chalk.magenta(`[${req.method}]`);
const status =
res.statusCode > 399
? chalk.red(res.statusCode)
: chalk.green(res.statusCode);
console.log(`${method} ${req.originalUrl} - ${Date.now()} ${status}`);
});
next();
});
app.get("/", (req, res) => res.sendStatus(200));
app.get("/about", (req, res) => res.sendStatus(200));
......
......@@ -2,51 +2,16 @@ const PORT = process.env.port || 8080;
const express = require("express");
const app = express();
/*
* In this exercise, we'll make use of some of the additional
* behavior that express can use for handling routing. In particular, we'll
* look at "redirect" functionality.
*
* In web development, a "redirect" refers to taking a request from a user,
* and sending them to a different location. Redirects happen _a lot_ online:
* for instance, when you visit links on a service like Twitter or Facebook,
* these services have "link shortener" services that redirect you from a
* short URL like https://t.co/rQNeZKNSIX to a longer link, like
* https://byteconf.com.
*
* We're going to build a similar service, but for your "personal links".
* For instance, I'll build something with the following routes and redirects:
*
* /github -> https://github.com/signalnerve
* /medium -> https://medium.com/signalnerve
* /twitter -> https://twitter.com/signalnerve
* /soundcloud -> https://soundcloud.com/signalnerve
* /website -> https://signalnerve.com
*
* Because everyone uses different services (or none at all!), this exercise
* is designed for you to implement whatever kind of links you want! For instance,
* you may define things like "/favorites/movie" and link to an IMDB page, or
* "/friends/john" to link to a friend's website or Facebook.
*
* Pick 2-3 links to set up (or more, if you prefer) and define them as GET requests.
* Inside the callback function for this route, call the res.redirect function, passing
* the argument of the URL you want to redirect to.
*
* For instance:
*
* app.get('/twitter', (req, res) => {
* res.redirect("https://twitter.com/signalnerve")
* })
*
* Test the behavior by starting the application and visiting your route. Define 2-3 of these
* and you'll be done!
*
* By the way, bonus points if you want to take this application and actually deploy it
* somewhere, using something like Heroku or now.sh! I use something similar for the
* Byteconf website (via URLs like byteconf.com/s/twitter, byteconf.com/s/youtube, etc)
* to track how many people are visiting those URLs from the website. It's a great way
* to eliminate the need for remembering URLs, and it looks cool on a business card :)
*
*/
app.get("/github", (req, res) => {
res.redirect("https://github.com/signalnerve");
});
app.get("/twitter", (req, res) => {
res.redirect("https://twitter.com/signalnerve");
});
app.get("/website", (req, res) => {
res.redirect("https://signalnerve.com");
});
app.listen(PORT, () => console.log(`Express app listening on ${PORT}`));
......@@ -4,42 +4,7 @@ const app = express();
app.set("view engine", "pug");
/*
* In this example, we've set up a basic express application
* with a single route: "/". This route renders the template
* at views/index.pug.
*
* The view is _mostly_ set up, but we need to do two things in
* order to see the rendered page as we'd expect.
*
* First, we need to enable "static file" support for our
* express application. Call the app.use function, passing in
* the function express.static as the argument. express.static
* takes one argument, the path where your static files will be
* stored. Use the string "public" to indicate that our static
* files will live in the "public" folder (go ahead and create
* that folder in the exercise directory, too!)
*
* Now we'll download a CSS framework and add it to our application.
* Go to https://getbootstrap.com/docs/4.1/getting-started/download
* and click the "Download" button under the "Compiled CSS and JS"
* section. The downloaded ZIP should have two folders inside of it,
* "css" and "js". Extract those files (let me know if you need help)
* and drag both folders into your "public" folder. It should end up
* looking like this:
*
* public/
* ├── css
* │   └── bootstrap.css
* │   └── // more files...
* └── js
* └── bootstrap.js
*    └── // more files...
*
* Restart your application, and then go to view/index.pug to finish
* the exercise!
*
*/
app.use(express.static("public"));
app.get("/", (req, res) => res.render("index"));
......
html
head
//- We need to add two CSS links here.
//- A CSS link is defined in pug with the following syntax:
//-
//- link(href="/<css_path>" rel="stylesheet")
//-
//- Import two CSS files from the following CSS paths:
//- 1. /css/bootstrap.css
//- 2. /css/product.css
//-
//- Once you've added both CSS link tags, go to the root
//- path of your application in-browser to see the finished result!
link(href="/css/bootstrap.css" rel="stylesheet")
link(href="/css/product.css" rel="stylesheet")
body
nav.site-header.sticky-top.py-1
......@@ -142,4 +133,4 @@ html
li
a.text-muted(href='#') Privacy
li
a.text-muted(href='#') Terms
\ No newline at end of file
a.text-muted(href='#') Terms
/*
* Fizzbuzz command line exercise
*
* Define a `numberArgument` variable that is the value of a number
* passed in to the `node` command line binary. For instance, if you run
* this file with `node fizzbuzz.js 1`, capture the `1` value as
* `numberArgument`. Recall that arguments are available inside the Node process
* as an array, set as `process.argv`. Try console.log(process.argv) if you aren't<