CS 312 - Software Development

CS 312 - Assignment Four

Goals

  • Learn how to incorporate REST server interaction into your app
  • Experience refactoring to fit changing requirements

Prerequisites

  1. Click the GitHub classroom link and then clone the repository GitHub classroom creates to your local computer as you did in previous assignments.

  2. Update the author information in the package.json file

  3. Install the package dependencies with npm install

  4. Copy your components over from assignment 3. In the interest of letting you resubmit assignment 3, the assignment 4 skeleton does not include the work you did in assignment 3, so you need to manually copy it over. Make sure to just copy the .js (and possibly .css) files.

    Once you have the dependencies installed you can start the development server with npm run dev. Employ good Git practices by creating a working branch for your features.

Background

This assignment mirrors the REST practical in which you converted FilmExplorer to use a server for data persistence. You will be transitioning Simplepedia over to server-maintained data management. You will also add functionality to the client to allow articles to be deleted.

The server

The main REST interface can be found at /api/articles, which can be optionally followed by an id. There are two secondary routes which can be found at /api/titles/:section and /api/sections.

The server API looks like this (:id indicates a parameter that should be replaced with a valid article id -- The colon should not actually be part of the URL):

EndpointCommandAction
/api/articlesGETFetch the entire article collection as an array
/api/articlesPOSTAdd a new article to the collection (the new article should be provided as the JSON-encoded request body)
/api/articles/:idGETFetch the article with id of :id
/api/articles/:idPUTUpdate the article with id of :id (entire updated article should be provided as the JSON-encoded request body)
/api/articles/:idDELETERemove the article with id of :id
/api/titles/:sectionGETGet a list of titles from section section (returned values are objects with properties title and id)
/api/sectionsGETGet a list of all sections as an array of section names

In the case of POST, the server will send back the new article. On PUT and DELETE the server will not send back anything, just the response status.

Note that you will now all be sharing one central data store! By all means test thoroughly, but be mindful of others (i.e. don't delete all the articles). The server will refresh hourly with the seed data, but try not to corrupt it in between refreshes (and post on Piazza if it becomes too much of a mess). If you break the server, you break it for everyone...

The server implements server-side validations and will respond with an error (HTTP status code 400 or 500) if your request or data is ill-formed or otherwise invalid. An example of the latter is creating an article with a duplicate title. We suggest keeping the browser developer tools open while working on the assignment to monitor your requests and the corresponding responses.

Server location

You will be communicating with a server running on basin at http://basin.cs.middlebury.edu:4042. We do not, however, want to pollute our code with a lot of references to basin -- it smacks of magic numbers, a distinct anti-pattern.

So, what we are going to do is use environment variables to set the server location. You will find a file called .env has been included in the skeleton. This file allows us to add in environment variables. Next.js allows us to mix these variables into client side code when we prefix them with NEXT_PUBLIC_ (normally, environment variables are not available in client-side code because, well, it is running on the client).

As a result, you will need to preface your fetch calls with the contents of process.env.NEXT_PUBLIC_HOSTNAME, e.g.,

const results = await fetch(`${process.env.NEXT_PUBLIC_HOSTNAME}api/articles`);

Notice that the slash at the end of the hostname is included in the environment variable, so we don't include it here.

Assignment

Part 1: Load the data from the server

Just as we did with the Film Explorer, switch from getting the data from the local copy and instead fetch it from the server. Note that the articles your receive from the server will have a new id property. You should use these as a more reliable unique identifier in your code (e.g. for the key property in your component that displays the titles).

Part 2: Handle edits and additions

Rewrite the callback you are sending to Editor so that it handles edits and additions. This may require a little bit of restructuring of the code. As with the Film Explorer example, you will tell the server about the new or updated article, and the server should return a copy of the article back to you. You then want to add the article into the collection, removing the old one if it exists. As the collection is now a state object, you should replace, not modify, the collection for the state change.

Part 3: Handle delete

If you don't already have a 'Delete' button, add one to the ButtonBar. It should not change the viewing mode like the other two buttons, it should just send a request down to server requesting the current article be deleted. If the server reports success, delete the article from the collection.

Exceeding expectations

You will (hopefully) notice that you do not need all of the API routes to accomplish the above.

To exceed expectations for this assignment you are going to redo the fetch logic to be a little more realistic. As we discussed previously, loading in the entire collection at once isn't scalable. While we have moved away importing the giant file, we have replaced it with a network call that essentially does the same thing. A more scalable solution is to only fetch the data we need, when we need it. This will require some restructuring.

  • Remove the collection state from the Home component.
  • Add a useEffect in IndexBar that fetches the sections from the server. You will need new state to hold the sections
  • If there is a current section, you should also fetch the titles associated with the current section. You will need new state for the titles
  • The data you get from titles will give you a title to display and the article id associated with it, so the select function will need to make a call to fetch the body of the article for display.
  • In your function that handles the new and edited articles, not much will change. You will not patch the new articles into the collection (or remove deleted ones), because you are no longer in charge of the collection. You should, however, update the currentArticle with the data received from the server.

Some of this is pretty straightforward, but watch out for tricky state changes in IndexBar when articles are added, updated, and removed.

Finishing up

Your submission should not have ESLint warnings or errors when run with npm run lint (or npx eslint .). Remember than you can fix many errors automatically with npm run lint -- --fix (although since ESLint can sometimes introduce errors during this process, we suggest committing your code before running "fix" so you can rollback any changes). As described in the README, the assignment skeleton includes the Prettier package and associated hooks to automatically reformat your code to a consistent standard when you commit. Thus do not be surprised if your code looks slightly different after a commit.

Submit your assignment by pushing your changes to the GitHub classroom via git push --all origin and then submitting your repository to Gradescope. You can submit (push to GitHub and submit to Gradescope) multiple times. The last submission before I do my assessment will be the one I look at.

Portions of your assignment will undergo automated grading. Make sure to follow the specifications exactly, otherwise the tests will fail (even if your code generally works as intended). Use the provided test suite (run with npm test) to get immediate feedback on whether your code follows the specification (remember that the provided tests are not exhaustive, and an application that passes all of these tests is not guaranteed to be correct). Because of the increased complexity of a React application, Gradescope can take minutes to run all of the tests. Thus you will be more efficient testing locally and only submitting to Gradescope when you are confident your application meets the specification.

Important Because the two versions are so different, there will be two different assignments on Gradescope. You only need to submit to one of them.

FAQ

Do I need to implement unit testing?

No. As with previous assignments, the skeleton includes some unit tests to assist you in your development and to ensure that the grading scripts can automatically test your submission.

What if the tests and assignment specification appear to be in conflict?

Please post to Piazza so that we can resolve any conflict or confusion ASAP.