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

This assignment builds on the work of assignment 3. As such, you should not start it until you have passed all of the Gradescope tests for assignment 3. While this doesn't assure you that you will have "met expectations", it is enough to proceed.

  1. Visit the Assignment 4 page on Replit (or click the 'Start Project' link for Assignment 4 on our team page).
  2. Click the GitHub classroom link to accept the assignment.
  3. Return to the assignment on Replit and go to the Version Control panel.
  4. Click the button to create a new git repository (not the one for connecting to an existing repo).
  5. Open the shell and follow the instructions on your GitHub repository for connecting an existing repository:
    1. git remote add origin repo-name where repo-name is the name of your repository (e.g., https://github.com/csci312-s21/assignment04-ChristopherPAndrews.git)
    2. git branch -m main
    3. git push -u origin main
  6. Update the author information in the package.json file
  7. 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 of the components you worked on.

Once you have the dependencies installed you can start the development server with the Run button.

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. I 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 Heroku at https://simplepedia-server-v2.herokuapp.com. We do not, however, want to pollute our code with a lot of references to Heroku -- it smacks of magic numbers, a distinct anti-pattern.

Instead, I have added a new file (lib/constants.js), and you will import the location of the server from there. This is basically the same thing as you did in practical 4, except that I have moved the variable. As a result, you will need to preface your fetch calls with `${server}, e.g.,

const results = await fetch(`${server}/api/articles`);

Assignment

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).

We could approach this assignment the way we approached FilmExplorer in the practical. All we did there is remove the data import and replace it with a fetch call to ask the server for the data. Then, when we updated the rating, we told the server about it, but then updated our local collection and didn't check in with the server about any other changes. As we mentioned in class, there are a number of issues with this approach. One, it doesn't scale (we don't download the entirety of Wikipedia onto our computer every time we consult it). Two, it leaves us completely blind to changes on the server. We are going to redesign this to be a little more scalable and reduce some of the change blindness. We are going to do this by doing a bit of refactoring (Agile development!).

Part 1: Prepare to refactor

Practice good software development and start a feature branch for your work.

To get ready, remove the collection state from the Simplepedia component. You will also need to remove the collection prop from Indexbar, and comment out the code in the Editor handler that updates the collection state until you can replace it with something new. You should also comment out most of IndexBar.

Part 2: Load the data from the server

Rather than grabbing all of the articles at once and storing them locally in a collection, we are going to selectively ask for three things from the server.

The first thing to worry about is populating the sections. Add a useEffect in IndexBar that fetches the sections from the server. You will need new state to hold the sections.

Once you have a current section, you will need to be able to display the titles. If you look at the API, there is a way to fetch the titles for a particular section. You will also 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 to get the body of the article for display.

Make sure that this all works before you tackle making modifications to the collection.

Part 3: Handle edits and additions

Rewrite the callback you are sending to Editor so that it handles edits and additions. You don't have to handle updating the collection any more so this should be pretty straightforward. Use the appropriate route to communicate the addition or the update to the server. Make sure to update the current article state when you do.

Look out for gotchas. Most of this is pretty straightforward, but the state changes required for IndexBar when you add or edit can be a little tricky (think about changes that change the sections...).

Part 4: Handle delete

Add a third button to the ButtonBar that deletes the current article. In handleClick you just need to send a request to the server to delete the article and then clear out the currentArticle. Again, watch out for how this affects IndexBar.

Reflection

In the README.md file, I would like you to write a brief reflection about your assignment.

If it meets the requirements (passes all of the automated checks), write how comfortable with your solution. Did you use good development practices, or is it a hacky, last minute solution. Do you understand your own solution? How much effort did you put into it? Do you feel like you could do a similar assignment with more ease?

If it doesn't yet meet the requirements, what are you struggling with? What does it not do correctly? What have you done to try to correct it? How hard have you tried to correct it? How much effort have you put into the entire assignment?

Put a date on the reflection and if you do any revisions, add another dated reflection below it.

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.

Don't forget to merge your changes back into the main branch (this is an instance where self merging into main is permitted).

Submit your repository to Gradescope. You can submit (push to GitHub and submit to Gradescope) multiple times. Portions of your assignment will undergo automated assessment. 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. 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.

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 Slack so that we can resolve any conflict or confusion ASAP.


Last updated 03/31/2021