Summer Homework #3 đ» đ„„
New stuff we learned this week: đ€
ES Module Syntax
- The long-term replacement for CommonJS (
require()
/module.exports
) is something called ES Modules. (The âESâ stands for âEcmascriptâ, which is technically the name of Javascript). - ES Modules are already supported in TypeScript, most modern browsers, but sorta only halfway in Nodejs (full node support will eventually be here).
- to create a NAMED Export, you just put the keyword
export
in front of whatever identifier you want to export, like this:
// in file: beaver.js
export function sayBeaver() {
console.log("Beaver");
}
export const BEAVER_NAME = "Walter";
- to consume a NAMED import you almost always destructure while using the
import
keyword, like so:
// in file: main.js
import { sayBeaver, BEAVER_NAME } from "./beaver";
- if you donât like the name provided by the NAMED export, you can alias it when importing:
import { sayBeaver as logBeaver } from "./beaver";
- if you want to import all the NAMED exports from a file as a single object, you can use this syntax:
import * as beaverUtils from "./beaver";
beaverUtils.sayBeaver();
console.log(beaverUtils.BEAVER_NAME);
- if a module has one primary, main export itâs customary to make it the default export using the
default
keywordt:
// file: beaver-class.js
export default class Beaver {
speak() {
console.log("I am a beaver");
}
}
- to consume a default export, you just import it without destructuring or using the
*
symbol:
// file: main.js
import Beaver from "./beaver-class";
- a file with a default export can also have NAMED exports:
// file: harriet.js
export default function() {
return "Harriet Henderson";
}
export const nickname = "Ritty";
- if you want to import both a default export and a NAMED export, you do it like this:
import harriet, { nickname } from "./harriet";
- when using Typescript, you can import/export Types as well:
// file person.ts
export type Person = {
name: string;
hasBeard: boolean;
};
export function makeJared(): Person {
return { name: "jared", hasBeard: true };
}
// main.ts
import { makeJared, Person } from "./person";
Promises đ
- Promises are a programming language concept or abstraction that allows easier handling of asynchronous tasks.
- to make your own promise you create a new instance of the
Promise
class, and pass it an executor function:
const promise = new Promise(myExecutorFunction);
- inside the Promiseâs constructor, your executor function is invoked, and is passed two arguments â a
resolve
function, and areject
function:
const promise = new Promise((resolve, reject) => {
// do something async here, then, based on the outcome
// call either `resolve` (success), or `reject` (failure)
});
- once youâve got a promise, you can start then-ing:
promise.then(val => {
// do something with the value resolved from promise
// `val` is what the `resolve()` function was called with
});
- there are two ways to handle error conditions with promises. The first (and less common) way is to pass a second function to the
.then()
method, like so:
promise.then((val) => {
console.log('it worked, got val:`, val);
}, (err) => {
console.error('something went wrong!');
});
- but a much more common (and ergonomic) way of handling errors is to chain a
.catch()
:
promise
.then(val => {
console.log('it worked, got val:`, val);
}).catch(err => {
console.error('something went wrong!');
});
- anything returned from a function passed to
.then()
will be converted into a promise (unless it already is a promise), which means you can chain thenâs together:
promise
.then(val => {
return val.toUpperCase();
})
.then(val => {
return `${val} #goatbanjorodeo`;
})
.then(val => {
return [val, val];
});
- a
.catch()
will catch any errors from any promise before it in the chain.
promise
.then(val => {
if (Math.random() > 0.5) {
throw new Error("Horrible problem!");
}
return val.toUpperCase();
})
.then(val => {
return `${val} #goatbanjorodeo`;
})
.then(val => {
return [val, val];
})
.catch(err => {
// this will catch any error from anywhere in the chain
});
- the
window.fetch()
api is a browser API for making HTTP requests from javascript. It returns aPromise<Response>
, and many of the methods of theResponse
object it returns, also return promises (like the useful.json()
method):
fetch("https://api.coolservice.com")
.then(response => {
// response.json() returns a promise,
// so we KEEP CHAINING â
return response.json();
})
.then(json => {
console.log(json);
});
- the npm package
node-fetch
allows you to make http requests from node using the exact same api as the browserâswindow.fetch()
:
import fetch from 'node-fetch';
fetch("https://api.coolservice.com)
.then(res => res.json())
.then(json => console.log(json));
Useful Links:
Homework Plan (next class in 3 weeks)
- 1 day (per week) review all flashcards
- 1 day (per week) touch typing practice
- 1 day setting up SSH access to new HTC VM
- 1 day Import/Export/RegExp homework
- 1 day Node Promise Homework
- 1 day Web Fetch/Promise Homework
Homework (week 1)
Homework (week 2)
Homework (week 3)
SSH Assignment
- modify your computers
~/.ssh/config
file so that it connects to the new HTC VM through port 555. - make a nice alias by changing the
Host
to something short likehtc
, which requires that you also set theHostName
tohowtocomputer.link
- test your SSH connection to the new VM, you should see the cool HTC ascii-art that I showed you in class
- once you are able to SSH in, Slack me that you got in successfully, once I hear back from all of you, Iâll nuke the old VM đ«
Import/Export/RegExp Homework
- slowly and carefully review the âES Module Syntaxâ section of âNew Stuffâ ^
- go to this url and create a FORK of the repo
- connect to the HTC machine with vscode and clone the repo into a folder called
~/node/summer-3/
- create a new branch to work on
- take a look at the
package.json
file⊠This repo has some dependencies, so youâll need to install those. Type a command to install the dependencies. - open up the
src/mm.spec.ts
file and thesrc/mm.ts
files - make an empty function called
mm
in thesrc/mm.ts
file, and export it as a named export. - to start running the tests, check the
package.json
file again, and see that I created two scripts for you. Run thetest
script by typingnpm run test
into the integrated terminal. - figure out what the other script does, and try it as well
- slowly work through the tests (except the lastâtill you read the next step) in
mm.spec.ts
, changing eachxit()
into ait()
function, and get them to pass one by one. (Hint: after the first one or two tests, you should realize this requires a regular expression to solve. See here for a brush-up on regular expressions in javascript). - to make the last test pass, youâll need to change your
mm.ts
file so that the regular expression you created to make all of the tests pass is captured in itâs own variable and ALSO EXPORTED. Themm()
function should use this variable, but themm.ts
file should also export the variable. - make sure that you have added type annotations to the argument and return of the
mm()
function. - commit your work.
- now, change the
mm.ts
file so that themm()
function is a default export. Youâll have to modify yourmm.spec.ts
file as well, to import both a default and a named import. - make another commit.
- push up a Merge Request to Gitlab, and post it in Slack.
Node Promises Homework đ
- make sure youâve watched both videos I recorded about Promises: video 1, and video 2
- very carefuly and slowly review the Promises portion of âNew Stuffâ above ^^.
- go to https://gitlab.howtocomputer.link/htc/promises, fork it, then clone it into
~/node/summer-3
throughssh
, then connect to the dir through vscode. - create a new branch
- Note: this whole homework is essentially the same as the
nodeback
homework from earlier this summer, but this time with Promises đ. - Note: for this whole homework, you need to use the promise-ified versions of the
fs.*
module functions. No directly usingfs.readFile
orfs.readFileSync
, etc. - write some code in
file.ts
such that you can pass it the lowercase last name of one of the four quakers who have files in the./quakers
file. When you do, it shouldconsole.log
the contents of the file. - test your script by using
tsnode
(since this is a typescript file), it should work like this:
$ tsnode file.ts ellwood
> To begin, therefore, with mine own beginning.
> I was born in the year of our Lord 1639,
> ETC...
- be sure your script works by just passing
ellwood
andwebb
etc, NOTquakers/ellwood.adoc
. - use template literals for any string concatenation (no more
+
for strings, forever!) - if you have any typescript errors
vscode
should tell you, and thentsnode
will bark at you, so fix all of those. đ - commit your work.
- next, handle the error case, where you pass the name of a file that does not exist. Start by just console.logging an error message and returning early.
- commit your work.
- next, instead of logging the error case, make it so that your script writes the error message (including the non-existent filename) to a file called
./errors.txt
. Youâll need to promisify another one of thefs
functions, like I did for you withreadFilePromise
. The error file should read something likeNo file for "goatbanjorodeo" found
if I trytsnode file.ts goatbanjorodeo
. - commit your work when youâve got it working.
- Extra Credit: âš Instead of overwriting the
errors.txt
file with a message about a file not existing, figure out how to append a new line to theerrors.txt
file, so that it keeps a running log of all of the errors that you could view later. Commit your work when done. - Kiah Credit: âš Modify the script so that it can take any number of filenames passed as cli/shell arguments, like
tsnode file.ts ellwood webb gratton
. The logging of file contents and writing of lines to the error file should work the same, just supporting a variable number of arguments from the user. - push up a MR, slack me the URL so I can leave you comments.
Web Promises Homework đ
- make sure youâve watched both videos I recorded about Promises: video 1, and video 2
- very carefuly and slowly review the Promises portion of âNew Stuffâ above ^^.
- read all these steps before starting out
- for this homework youâre going to build a web page by loading data from an external API that you access using the
fetch()
api supplied by the browser. - make the website in a new folder (which should also be a git repository) in your
~/www
dir - you can choose from using one (or more, if youâre ambitious) of these API endpoints:
https://api.howtocomputer.link/friends-library/friends
â a list (array) of all of the Quaker authors available on Friends Library.https://api.howtocomputer.link/friends-library/documents
â a list (array) of all the books available on Friends Library, includes a usable cover-image for each edition too (note, the/friends
url above contains references to these books)https://api.howtocomputer.link/friends-library/documents/<document-id>
â a single record for a single book (an object) for one of the books on Friends Libraryhttps://api.howtocomputer.link/friends-library/downloads
â a list (array) of the 500 most recent downloads from the Friends Library site (including location data)https://api.friendslibrary.com/app-audios
â a list (array) of all of the audio books available on Friends library, including links to MP3s, and âalbum artworkâ image (this is actually a real API endpoing that Iâm using for the native apps Iâm developing currently, but you guys can use it too!)
- the basic idea is that you will use
fetch()
to request one of these endpoints, then turn the response into a JSON object (see example in âNew Stuffâ above), and then once you have JSON (which will be an ARRAY of things), you will probably.forEach()
over the array and use your DOM-scripting skills to insert dynamically generated HTML for each item in the list. - here are some example ideas:
- Create a nicely-styled list of all the Quaker authors, including a description of each. Maybe format the women authors in pink, and have the men authors be blue. Link each author to their page on the Friends Library site. Or maybe filter out all of the men-friends and make a page showcasing all of the female authors. Or use the
residence
field to make a page showing off only the Quakers who lived in Ireland. - Create a list of all books available on the Friends Library website. Show images for each edition available for each book, and link each book to itâs page on the Friends Library site.
- Create a dashboard displaying information about the 500 most recent downloads. Consider grouping them into countries, or counting them and giving statistics. The download resources donât have human-readable information about what BOOK was downloaded, but they DO have the document ID and edition type â you could use these facts to make additional requests to get more information about the items downloaded.
- Create a nicely-styled list of all the Quaker authors, including a description of each. Maybe format the women authors in pink, and have the men authors be blue. Link each author to their page on the Friends Library site. Or maybe filter out all of the men-friends and make a page showcasing all of the female authors. Or use the
- you might want to start by just creating an HTML page with a link to a javascript file, and in that javascript file, start playing around with fetching one of these endpoints, and turning the response into JSON. Once you have the JSON, try
console.log()
-ing it out. Or maybe just log the first one. Then you can start brainstorming some interesting ways to present these resources in a website, in some sort of a list of repeating HTML elements. - youâll probably want to end up making a javascript function that takes in ONE of the resources, and builds up the HTML you want from it. Then you can MAP over the resources, calling this function, and then inserting it into the DOM.
- if you are feeling rusty on your DOM-scripting, review the new stuff from week 18.
- donât go CRAZY, but try to make your page look sort of nice, using CSS. Try to use Flexbox, and some of your other CSS skills.
- make sure to make a lot of git commits.
- push your code to a new repository on GitLab so itâs safe.
- Kiah Credit: âš make sure your web-page uses at least TWO of the endpoints listed above, cross-referencing them. This will involve more usages of Fetch, and more promises. Example: list recent downloads, but for each download, look up information like the name of the document using another endpoint, and merge that data together to make something more interesting and useful. Or, show a list of Quaker authors, but for each of them also give detailed information about each book they wrote, only availabe from a different API endpoint.
- slack us the URL of your web-page when youâre done!