Pset 1: JavaScript and HTML

The goal of this pset is to focus on plain old JavaScript and plain old HTML. Without extra frameworks, it will be tedious and unrewarding to make a beautiful site, so plan on producing something ugly for now.

You have two options: make a search interface for the Harvard University Art Museums, or make a campus shuttle and city bus tracker. We think the first one will be a little easier and it actually involves digital humanities. The second one will involve multiple external APIs, which may be of interest to some of you; it is also inherently practical.

Ground Rules

Whichever option you choose, please observe the following ground rules:

  • Your entire application should be contained a single HTML file, a single JavaScript source file, and optionally a CSS file and any necessary image files. We have no expectation that you will need any CSS or image files at all.
  • Your JavaScript code should be well commented so we can understand what it does and why. Please leave in any debugging code you add.
  • You must use ES6/”modern” JavaScript:
    • Use let instead of var to declare variables
    • Create at least one class using JavaScript’s class syntax
    • Use fetch() for all network requests. (Hint: you’ll make your life much easier if you put all calls to fetch() inside async functions so you can use await with it. And you’ll take care of the next requirement while you’re at it.)
    • Create at least one async function, and use await at least once
    • Create and use at least one arrow (=>) function
  • You may not use jQuery, React, node.js, or any other libraries or frameworks. The purpose of this pset is to focus on JavaScript syntax, including ES6 additions to the language. In return, we are only asking you to do things on this pset that don’t really need them. In particular, your web page can be both ugly and clunky to use for now.
  • You may use the pure CSS version of Bootstrap if you wish, but please link in the CDN version rather than submitting a local copy of it. However we don’t recommend this unless you are already very familiar with Boostrap; it is much easier to learn and use in conjunction with Vue.

Using fetch() for API requests

Most modern web APIs expect you to submit a dictionary of parameters encoded in the URL of a GET request. Rather than forcing you to construct the full URL with all the ?key1=value1&key2=value2 parameters (ensuring, of course, that everything is properly escaped for inclusion in URLs), virtually all javascript functions that have been cooked up over the years for making HTTP requests allow you to pass a parameter with a javascript dictionary of your parameters. The library then takes care of constructing the proper URL for you.

Oddly, even though it is the newest such function and the first since the antiquated XMLHttpRequest to be part of the javascript language, fetch() forces you to construct the URL yourself. The official way to do so–assuming you have a dictionary of parameters name params–according to the standards documents is:

let url = new URL('http://your.url.com');
Object.keys(params).forEach(key => url.searchParams.append(key, params[key]));

We recommend you use this approach to properly encode your parameters into the URL. And it even takes care of the requirement to use an arrow function. Note that url is a URL object, not a string. url.href will give you the URL with all the parameters you added, but fetch() happily accepts the URL object itself.

Remember that calls to fetch immediately return a Promise object from which you will be able to extract a Request object once the browser gets an initial response to the underlying network request. Many APIs return their results in JSON format, which you can access through the Request’s json() method once the server’s response is complete. In other words, you have to first wait for the response to start coming back, then wait for it to finish coming back. You’ll find await is your friend.

Option 1: Harvard Art Museums Search Interface

The Harvard Art Museums provide an API to access the entire collections database. Request an API key from https://www.harvardartmuseums.org/collections/api and skim the documentation there. You should get an API key by e-mail relatively quickly. Use the API to build a page that has at least the features listed below. Their presentation on the web page should be readable, but it can be very rudimentary and ugly.

  • List all galleries in a way that makes it possible to tell them apart
  • Select a gallery to get the list of objects it contains
  • Select an object to view all the details of the object, including any images
  • Clicking on an image should show the full-size version of the image
  • CPSC 376/CS 100 students: Use the IIIF presentation service to access images. Retrieve images in png format when available, with jpg as a fallback.
  • CPSC 276 students: You may retrieve images either via the “default service” for images, or via IIIF as you prefer. Using IIIF isn’t hard, but you’ll need to plow through some extra documentation.
  • Search for objects based on a minimum of 5 fields of your choice from the /object API. You can include support for additional fields if you want, but doing so will be largely busywork.
  • CPSC 376/CS 100 students: Support searches using at least 3 additional APIs (person, exhibition, etc.). It should be possible to click through any objects these return to see the details of the object itself.
  • All searches should return all results, not just the first 10 or 100. The API does not do this automatically: you must tell it how many results you want it to return at a time, and the maximum number is 100. For each search, you will need to produce a series of network requests to obtain all the objects. Look at the documentation and the JSON returned by your initial request to figure out how to do this. (It is also acceptable to display only the N results at a time, with pagination links to see the next/previous N, but this is likely to be more work to implement without any kind of client-side framework.)

You’ll need to format all the returned results as HTML, and update the current page with them. This is the sort of thing that frameworks like vue are designed to handle, but here are some suggestions for ways to minimize the pain of doing it by hand:

  • Use <div> tags for each section of the page you will need to dynamically show, hide, or update
  • Use document.getElementById() in your JavaScript to access the <div> sections. Manipulate the element.style.display property to show/hide and element, and the element.innerHTML to change its contents.
  • Group all the <input> elements for each type of search into a form, so you can access them easily via documents.forms. It’s still difficult to convert the form values into a JavaScript dictionary with using Vue, jQuery, or something similar, but the formToJSON function at https://code.lengstorf.com/get-form-values-as-json/ will do what you need. Read the page carefully and ask questions in class about the parts you don’t understand, because the function does a good job of showing off JavaScript’s functional nature and some of its quirks. Feel free to cut and paste formToJSON into your pset, but cite the source URL in a comment because you should always cite the source of code you copy.

Additional hints:

  • Use the curl tool to test API queries and see their results. If you have Linux or a Mac with the command-line developer tools installed, you probably already have curl. You can also use it from the terminal in the Cloud9 IDE.
  • Use console.log(...) liberally in your code to display query results in the browser’s javascript console for debugging. Keep in mind that the console displays the current value of any variables you log, and they will update in the console if their values change in your code. To avoid this, check out the json.stringify function.

Option 2: Real-Time Shuttle and City Bus Map

Create a real-time tracker for campus shuttles and city buses on the same map. Integrate with your choice of map providers (Google Maps, …). You’ll be dealing with multiple different APIs, which will likely make this option a little more difficult. But it should still be manageable, and very rewarding. You must support the following features at a minimum:

  • Provide a list of valid shuttle routes, and a way to select which ones to display. Consider using a multi-select list box, or just a text input field where the user enters the routes that should be displayed. Attractive interfaces will be tedious to implement.
  • Show the selected routes on the map, including the stops and the current shuttle positions.
  • Update the shuttle positions at least every 30 seconds.
  • The default map position and zoom level should be appropriate for your campus.
  • CPSC 376/CS 100 students: Also support all these features for city buses, except that you can limit the list of routes you display to a reasonable number of characters. Users should still be able to select any valid route.

Both Yale and Harvard shuttle data is available via the TransLoc API. You will need to create a free account with mashape in order to get a key. As always, consider using a disposable e-mail address for your account. Also feel free to share your key with other students as long as that doesn’t break anything (it shouldn’t).

New Haven city bus tracking is available through CT Transit’s API. Feel free to use the open development key rather than registering for your own key. Boston bus tracking is available through the MBTA v3 API.