NUS Hackers Wiki
NUS Hackers Wiki
  • NUS Hackers Wiki
  • Hackerschool
    • Virtual Machines and Linux
    • Beginners' Guide to the Terminal
      • Introduction to the Terminal
      • Modern Shell Tools
      • Shell Scripting
      • Real World Scripting
      • Resources
    • Self-Hosting: Three Easy Pieces
      • 1. Setting up your server
      • 2. Running Services
      • 3. Monitoring your server
    • Vim
    • Introduction to Zig
      • Language Basics
      • Error Handling
      • Memory Management
      • Working with C
      • Exploring comptime
    • CI/CD with Github Actions
      • Background
      • Basics of Github Actions
        • Target workflow
        • Running unit tests
        • Linting code
        • Deploying to Github Pages
      • Advanced use cases
        • Pollers
        • Github script
        • Executing third-party scripts
        • Reusable workflows
      • Cookbook
    • Lightning Git
      • Git Concepts
      • Getting Started with Git
      • Making your first commit
      • Branching
      • Merge Conflicts
      • Integrating remote repositories
      • Collaborative Workflows
      • Commit Manipulation and Reflog
      • Interactive rebasing
      • filter-repo
  • Orbital
    • JavaScript
      • Browser Developer Tools
      • Getting Started
      • Datatypes
      • Operators and Operations
      • Loops and Conditions
      • Functions
      • Strings
      • Arrays
      • HTML
        • Getting Started
        • Tag Attributes
        • HTML Forms
        • Browser Inspector
      • CSS
        • Selectors
        • Colors in CSS
        • Measurements in CSS
        • The Box Model
        • Adding Styles - Part 1
        • Adding Styles - Part 2
      • Working with the DOM
        • Querying the DOM - Selectors
        • Querying the DOM - Element Attributes
        • Querying the DOM - Element Styles
        • Events with JS and HTML
        • Exercise: Click Counter
        • Editing the DOM
        • Fetch Requests
        • Exercise: The NUSMods API
    • React
      • Setup
      • State
    • React Native
      • Setup
      • Intro to JSX
      • Basic Syntax
      • Handling UI
      • Props
      • State Management
    • Git
      • Setup
      • Command Glossary
      • Fundamental Concepts
        • Getting Started
        • Integrating Remote Repositories
        • Branching
        • Merge Conflicts
      • Collaborative Workflows
        • Fork and PR Workflow
        • Branch and PR Workflow
      • Advanced Concepts
        • Ignoring Files
        • Commit Message Conventions
        • Github Collaborators
        • CI/CD with Github Actions
        • Advanced Git Commands
      • FAQ
    • Telegram Bot
      • Creating a TeleBot
      • API Calls
      • Telebot Basics
      • Integrating API's
    • Relational Database
      • Database Overview
      • Database Design
      • Entity Relationship Diagram
      • SQL Basics & PostgreSQL
    • TypeScript
      • Types and Interfaces
      • Utility Types
      • Typing Component Props, Events, and Hooks
      • Why You Should Avoid Using any (and What to Do Instead)
      • TypeScript Tricks You’ll Use All the Time in React
Powered by GitBook
On this page
  • The task
  • Some info
  • Step 1 - Get the form set up
  • Step 2 - Ready a container
  • Step 3 - Add an event listener to the form
  • Step 3.5 - Prepping the data for the fetch request
  • Step 4 - The fetch request
  • Step 5 - Display the course details
  • Approach 1 - The builder method
  • Approach 2 - The select-and-change method
  • Approach 3 - The lazy method
  • The end result
  • Next steps
Edit on GitHub
Export as PDF
  1. Orbital
  2. JavaScript
  3. Working with the DOM

Exercise: The NUSMods API

PreviousFetch RequestsNextReact

Last updated 12 months ago

I'm sure you know what is, its a website that has details about every course offered at NUS, as well as a degree planner, a timetable builder and a map of the campus. It also has its own API () which we are going to use.

The task

The task is to build a simple page that will have a form. The form will allow a user to type in a course code, and once submitted the form will submit a fetch request to the NUSMods API, request the course data, and then display it to the user. If the course code they enter is invalid, then show them an error message.

It is recommended to try the first steps on your own, until you get to the fetch request, to practice writing HTML and JS.

Some info

The API we will use is the one to get the course info given a course code and year. The general URL format is below:

https://api.nusmods.com/v2/{acadYear}/modules/{courseCode}.json

Example:

https://api.nusmods.com/v2/2023-2024/modules/CS2030S.json

Copy paste the above URL into your browser address bar to see the response. You'll see the response body in JSON format, like below.

Note: The course code needs to be in all capital letters for the request to succeed.

For this exercise, we'll stick to the year 2023-2024.

Step 1 - Get the form set up

So the first step is to ready the form. It will have the following:

  • A text input field that must have a value before the form is submitted

  • A submit button

Both of these, along with the form, must be uniquely identifiable as well.

Here's how that will look:

<form id="nusmods-form">
    <input id="course-code" placeholder="Course code (ex: MA1301)" required>
    <button type="submit">Find course</button>
</form>

Note that we do not define an action or method attribute because we do not want the form to actually submit, we just want it to trigger a fetch request.

Step 2 - Ready a container

Once the request completes, we'll need to put the course details somewhere, so it's a good idea to have a container element ready to accomodate the data. You could also directly place the details in the body, but a container helps to structure the page better. The container should not initially be visible to the user.

<div id="course-container" hidden></div>

(Optional) You may also want to have a separate element ready to show an error message to the user, unless you intend to display an alert instead.

Step 3 - Add an event listener to the form

Now we need to add a listener to the form that will wait till it is submitted. Then it should trigger a fetch request.

document.addEventListener("DOMContentLoaded", function() {
    document.getElementById("nusmods-form").addEventListener(
        "submit",
        () => {
            event.preventDefault(); // prevent the form from submitting to the default path "/" using this line
            // note: event is deprecated, but still works
            // try instead to look at form validation functions
            // or try using this: arguments[0].preventDefault();
            getCourseData(); // this function will have the fetch request
        }
    )
})

When a form is submitted, it automatically submits data to its action URL. In this case since there is no action URL defined, the form attempts to submit the input to the page itself, which reloads the page and prevents the rest of the code from being executed. To prevent this, we have the line event.preventDefault() in the listener function.

event is a deprecated global variable that refers to the event in question. It is better to use form validation functions to prevent forms from submitting. In this case I am using event because it is easier, and form validation is out of the scope of this guide.

Step 3.5 - Prepping the data for the fetch request

In our getCourseData function from above (or whatever you decided to name the function), we need to ready the course code. This is nothing much, just get the input field value and make it all caps:

function getCourseData() {
    let inputField = document.getElementById("course-code");
    let courseCode = inputField.value.toUpperCase();
    // fetch request here
}

Note that the value attribute of an input field returns the value of the field, which in this case is whatever the user has typed into the text field.

Step 4 - The fetch request

Now comes the fetch request. Recall that to get course details based on course code, we submit a request to this URL:

https://api.nusmods.com/v2/2023-2024/modules/{courseCode}.json

So the resource parameter for the fetch request will be the above URL with the user's input plugged in. As for the options parameter, luckily we do not need to specify any because the default options suffice!

So the fetch request looks like this:

fetch(`https://api.nusmods.com/v2/2023-2024/modules/${courseCode}.json`, {});

Next, we need to check the response status. The API will return 200 if the course code was valid, 404 if it wasn't, and other codes indicate other unforeseen errors. You can decide how you want to process it, but in this case since we don't care what the response code is, we can return null if there is an error.

fetch(`https://api.nusmods.com/v2/2023-2024/modules/${courseCode}.json`, {})
.then(response => response.status === 200 ? response.json() : null);

Lastly, we need to process the data and present it to the user. For starters, try displaying the course code, course title, description, and how many units it is.

Here's the basic skeleton:

fetch(`https://api.nusmods.com/v2/2023-2024/modules/${courseCode}.json`, {})
.then(response => response.status === 200 ? response.json() : null)
.then(data => {
    if (data === null) {
        // course code was invalid, display an error
    } else {
        // data contains the course details in a JSON format
        // read the documentation to see what properties are relevant to your needs
        // OR copy paste the example URL from the start of this section into your browser
        // to see the JSON for yourself
    }
});

That's the fetch request completed, now in the body of then we need to display the course details

Step 5 - Display the course details

There are 3 main ways to do this, and it's up to you to choose which one. The implementation is left to you as an exercise.

Approach 1 - The builder method

This approach involves creating elements and adding the text inside of them, then appending them inside the course-container element we made earlier. Make use of the document.createElement method, the element.appendChild method and (optionally) the document.createTextNode method.

The advantage of this is that it is quite flexible to changes in specification. For instance, if I decide to also show the prerequisites and corequisites of every course, its easier to just edit the JS file to create a couple new elements.

The disadvantages of this approach is that every time the fetch request is run, the elements are re-created and re-added to the page.

This approach is fine for instances where requests are not very often (or happen only once or at most twice after the page loads), but in our case it is slower than the other approaches.

Approach 2 - The select-and-change method

For this approach, you'll need to edit the html to add elements for the course details to be contained within, and give them all ids. An example is below:

<div id="course-container" hidden>
    <h1 id="cc"></h1>
    <h2 id="course-title"></h2>
    <p id="course-description"></p>
    <p id="credits"></p>
</div>

You'll then need to query for these elements and edit their innerText properties to contain the data needed.

The advantage of this approach is that the elements are only created once, and you just need to change their values.

The disadvantage of this approach is that the code is not that flexible to changes in specification, since you need to edit both the HTML AND the JS script to implement any changes.

This approach is useful for instances where multiple fetch requests could be performed by the user, like this one.

Approach 3 - The lazy method

This approach is the quickest way to do it. Remember the innerHTML property? It holds everything inside the element in question, including nested elements. This means that it is possible to add elements inside of another one by way of the innerHTML attribute:

let element = document.querySelector("div");
element.innerHTML = "<h1>Heading</h1>";

The above code will insert an <h1> into the div that was selected.

This means we can just format the entire contents of the course-container div into a string, and set the element's innerHTML to that string.

The advantage of this approach is that it is fast and easy to write, and it is easy to implement changes to the specification.

let element = document.querySelector("div");
element.innerHTML = "<script>alert('HTML Injection Successful 😈');</script>";

This adds a <script> tag inside the div, which causes the code inside it to be executed. Here, the code is just showing a simple alert, but it is possible to write code which behaves much more maliciously, such as creating and submitting invisible forms, reading cookies set by the page, messing with the page content, or worse.

This method, due to the vulnerability it creates, is not recommended for use at all, except in cases where the developer has complete control over the content being added to the innerHTML or it is extremely certain that the content being read in is safe, and when the contents are not very long.

The end result

Next steps

The next guide will be on React, a framework of JavaScript that allows to combine HTML, CSS and JS into a single abstraction to make frontend development slightly easier.

The disadvantage is that this approach allows for something called . This is when malicious code can be injected into a webpage, and one of the ways to do this is to use the innerHTML property. Look at the code below:

The code for this exercise can be found . Approach 1 has been used because we have not yet done a real example of creating+adding elements. Approach 2 has been left as an exercise, and approach 3 has been demonstrated just to show how it works.

This is the end of the JavaScript guide! If you would like to practice more fetch requests, I suggest testing out some of the API endpoints of . There is also an example that shows a couple of the endpoints, and a two fetch request examples (one of them using a PUT request, so take a look at the options JSON for that request).

HTML Injection
here
Reqres
here
NUSMods
documentation here