EDM Concert API - Creating a full stack application with Ruby's Sinatra and ReactJS
Published: 2023-05-16 07:50:30

Hello! Today, I am going to present my most recent boot camp project; a full stack application of various EDM shows/concerts. I am using ReactJS to write my frontend, and for my backend I am using Ruby Sinatra. My objective for this project is to focus on my backend in order to familiarize myself with the workflow and mastering the fundamentals of Ruby. So in this blog, I will provide detail on how I made the API itself and briefly explain how I setup my frontend to make network requests to my servers endpoints.

Here is a link to the repositories:
- Frontend : https://github.com/fusion407/sinatra-react-project-frontend
- Backend : https://github.com/fusion407/sinatra-react-project-backend

Go ahead and take a quick look at it and see how it works.

Let me start by showing a diagram of the structure of my database, discussing the associations, and how I setup my routes.

Here is my SQL diagram:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/v4d68dfuv244yh5y92xm.png)


As you can see, I have 4 models in my schema. 
My ‘fullsets’ model has a “has many to one” relationship to “artists, events, and locations.”
Artists, events, and locations have “has many to has many '' relationships to each other through ‘fullsets’. 
So each “fullset” belongs to an artist, event, and location.
In order to write my associations, I am using Active Record, an extension of Sinatra.

Models:
 
- fullset.rb:
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lxmpwiktzm3w7n80re15.png)
- artist.rb: 
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2dvy40xupvn5xnp6gfqs.png)
- event.rb:
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2puz9eszymzv16tlikhy.png)
- location.rb:
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hauqiij656zh17yg3hzw.png)

Here is an example of the schema for my fullset model:
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hilhv9d2u8mhpvcnhp5c.png)

In addition to the artist/event/location ID points, ‘fullset’ also has a title, video_link, and rating. The artist, event, and location models only contain their respected ID and name.

Now to show you my application controller so you can see how my routes are written.

First off, I have my fullsets model setup with full CRUD. 
GET and POST requests being sent to “.../fullsets”, and PATCH and DELETE requests sent to “.../fullsets/:id” with the id parameter being the specific “fullset” item that exists in the database.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/825u04xynk4d6g7ibza7.png)

My artist, event, and location models have a GET and POST route sent out to “.../artists”, “.../events”, and “.../locations”. I also have written  DELETE routes but only use it through postman; it is currently not attached to the application.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fwbo9d711fe6lflt289t.png)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5udfk1q3w1my2alapoyh.png)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3f7qhiry5d223njare5i.png)


Now that there is an understanding of how my backend works, let me give you a brief introduction to my application and how I am using my frontend to make fetch requests to my server.

I’ll start with my ‘App.js’ component:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3je3js4jin4hlqlgn3os.png)

Here, I am importing all my needed components, including the useState and useEffect hook. I will use these hooks to create some states and hold data for fullsets, artists, events, and locations, that are all loaded up with 4 separate GET requests to each endpoint on the initial rendering of the application.

App.js has 3 child components that take utilize the backends endpoints, Search, AddSet, and Edit

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jj5w92utcelnuuafof9b.png)

fullSetData is passed down to my Search component as a prop to make cards that display the data for each element in ‘fullsets’. Each one of these cards also has an edit and delete button.
If the user clicks delete, a fetch request is made with the id of the selected item and the item is simply deleted from the database and saves the new state for fullSetData.

(Search.js)
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xx1i922g9fobwvdpdfyg.png)

If the user clicks edit, the Edit component is rendered with a form that is matching the API’s schema and default values set to the values of the selected item. Upon submission of this form the PATCH requests are made to update the database with its new values.

(EditSet.js)
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2zxx1egv7sty6pnjx1yt.png)

Finally, we have my AddSet component. AddSet has 2 child components, AddSetDropdowns and AddSetForm. The data fetched from artist, event, and location is used to display a list of each item in AddSetDropdowns. The user must select an item from the dropdown, which will assign the form's value its ID. If there is data that is absent and the user is looking for an artist that doesn’t exist yet in the database, there is another form that makes a POST request and adds a new artist to the database that can then be selected. 

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/232684joewx257xwqza8.png)

The user is then asked to input a title, video link, and rating. On submission, a POST request is made using the provided forms values, adding a new ‘fullsets’ item to the database and setting fullSetData’s new state.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/z5t9xcmkrx1hcl0lqa7o.png)


That is pretty much it, my first full stack application. I hope this post finds itself useful to someone (including my future self). Thank you for taking the time to read, happy coding!