Persisting Business Ratings
Tags: javascript, beginners, webdev
Published: 2022-04-22 00:45:59

When first learning to code, every day of practice brings one to what feels like a significant new milestone. Each new skill attained comes with a sense of accomplishment that is difficult to match elsewhere. However, the feelings of power and capability quickly fade as one realizes the neverending depth of skill that is still waiting to be achieved. And so it becomes a cycle of high highs and low lows.

So it goes at Flatiron school, although the day-in-day-out nature of a coding bootcamp helps to keep me in the highs of discovery. Most recently, that discovery is the full functionality of building a front end with vanilla Javascript, complete with dynamic rendering of HTML elements, event listeners, and API sourcing. This was best demonstrated by our Phase I project, in which myself and two classmates developed a brewery search and rating app. 


## App Functionality

The app utilizes the [Open Brewery DB](https://www.openbrewerydb.org/) dataset and API, which is a record of breweries across the United States. Breweries are searched by city, with up to 20 results displaying for each city search. Most importantly, the app allows the user to assign a rating to each brewery and, using npm's [JSON Server package](https://www.npmjs.com/package/json-server), persist those assigned ratings by saving them to a db.json file. The db.json file is used to update the ratings upon page refresh or upon a new city search being performed.

The app accomplishes this using Javascript's native `fetch` function in conjunction with three [http request methods](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods) - `GET`, `PATCH`, and `POST`.

**If you would like to reference the code for this project to get a better sense of the scope and operation of the final deliverable, it can be accessed on github [here](https://github.com/drayeleo/phase-1-project).**

## `GET`
First things first - the app must be able to respond to the user's input of a city by populating a list of breweries in that city! This utilizes the most common of the http request methods - `GET` - in conjunction with `fetch`. In fact, this combination is so common that it's not even necessary to specify that `GET` is the operation being performed - fetch defaults to this method.
```javascript
fetch(`https://api.openbrewerydb.org/breweries?by_city=${city}`)
.then(response => response.json())
.then(breweries => {
    console.log(`breweries data for ${city}: `, breweries);
    document.querySelector('#brewery-cards').innerHTML = "";
    breweries.forEach(brewery => renderCard(brewery));
});
```
The above code passes the user's input (`city`) into the fetch function to send a request to the API for a list of breweries in that city. It then converts the API's response to JSON format, console logs the converted response, and calls another function to render each of the brewery's information on the page. 

The `GET` functionality is used one more time in the initialization of the page - to retrieve the ratings information that was previously saved in the db.json file. 

```javascript
fetch(`http://localhost:3000/breweryRatings`)
.then(response => response.json())
.then(data => {
    ratingsJson = data;
    console.log("ratingsJson: ", ratingsJson);
});
```
From there, rendering the pre-existing ratings on the webpage is simply a matter of assigning formatting changes based on the data that is now saved locally in `ratingsJson`.

## `PATCH`
With the user's request completed, the list of breweries rendered on the page, and the previously assigned ratings displayed for the respective breweries, the only thing remaining to do to ensure that the ratings continue to persist correctly is to update db.json whenever a user assigns a new rating. To do this, first the script must assess whether a record for that particular brewery already exists in db.json. If it does, the http request method PATCH is used:

```javascript
const breweryCardElement = event.target.parentElement.parentElement
const matchIndex = ratingsJson.findIndex(element => element.apiId === breweryCardElement.id);

const obj = {
    rating : event.target.className.slice(-1),
} 

fetch(`http://localhost:3000/breweryRatings/${ratingsJson[matchIndex].id}`, {
    method: 'PATCH',
    headers: {
        'Content-Type': 'application/json',
    },
    body: JSON.stringify(obj),
})
.then(response => response.json())
.then(data => {
    console.log('Success:', data);
    ratingsJson[matchIndex] = data; //update ratingsJson
})
.catch((error) => {
    console.error('Error:', error);
});
```
Because a record already exists for the target brewery, a fully-formed JSON object is not needed. Rather, the url provided to `fetch` directly references the server-appointed ID of the target brewery, and the only additional information that needs to be provided is what to update. Thus, `obj` contains only a single key: "rating".

## `POST`
If a record for the target brewery does not already exist in db.json, then a `POST` request must be made. Rather than updating a specific record in db.json, `POST` adds an entirely new record to the JSON.

```javascript
const breweryCardElement = event.target.parentElement.parentElement;
    
const obj = {
    apiId : breweryCardElement.id,
    rating : event.target.className.slice(-1),
} 

fetch('http://localhost:3000/breweryRatings', {
    method: 'POST',
    headers: {
        'Content-Type': 'application/json',
    },
    body: JSON.stringify(obj),
})
.then(response => response.json())
.then(data => {
    console.log('Success:', data);
    ratingsJson.push(data); //update ratingsJson
})
.catch((error) => {
    console.error('Error:', error);
});
```
Because the record does not already exist, the URL provided for `POST` is the same as the URL provided for `GET`. A fully-populated object must be provided to the server so that it can create a complete record of the new brewery rating. 

## Conclusion
Using `GET`, `PATCH`, and `POST`, developers can persist ratings assigned to businesses in remote databases. Further development of this project might include the addition of a "Clear Rating" button, which would require the use of the `DELETE` HTTP request method to clear the target record from db.json.