By: Malcom Calivar

Published: May 31, 2020

Project description

This was an opt-in project for one of my web development class. The professor offered the option of taking an exam based on everything we'd learned up until that point, or simply showing what we learned by creating a project. One of the requirements for this project was that it needed to consume a public API. Other than that, we were given complete freedom as to how to carry out the project.

I decided I wanted to create a single page application that would load recipes as the user typed on a search bar. Before this project, when I'd worked with APIs, I would make a call to the endpoint, then use the information I received to render a page. Thus, a page load was required whenever the user wanted to make a search. This time, I wanted to eliminate that completely. In fact, even clicking on a recipe would not load a new page. I wanted the user to never have to load a page to get the information they needed. 

Searching for the right tools

I was familiar at this point, though only in name, with front-end frameworks such as ReactJS, AngularJS, and VueJS. I knew that in order to render content dynamically, and thus, keep the user's activity to a single page, I would have to use one of these front-end frameworks. It may make for a more interesting story to say that this was a difficult endeavour and that -- like my experience with Java frameworks -- getting a simple project up and running was a gruelling process. 

This was not the case, however. I opted for using ReactJS, as my investigation at the time revealed it was one of the more in-demand and popular front-end frameworks. Their documentation had everything I needed to get started, and I had a React project running in Visual Studio Code in just a few minutes.

Finding a public recipe API was also fairly simple. I used an API called Spoonacular. With my tools in order, I could now start developing my app.

Problems along the way

I learned fairly quickly during the development process that this API had a very limited amount of calls I could make to it per day. I got around this problem by saving one of the calls to a JSON file that I could just use for testing purposes during the development of the app. This worked great, though it did restrict me to one set of data.

How was I burning through my API call limit so quickly? As mentioned previously, I wanted to make sure the user would receive data without having to load a page. This meant I needed to check for the user typing and make an API call whenever they entered a term into the search bar. No need to submit your search input and load the page.

Unfortunately, the way I initially programmed it was that an API call would be made for every keystroke. This meant that if a user typed "pizza," the app would make five API calls. If a user, in their search for a delicious Boeuf Bourguignon, had to correct typographical errors several times during their attempt to find a recipe, the app could easily end up with a couple dozen API calls made to the endpoint. 

The solution to this second problem was simple: I created a function that would either reset a timer, or time out after one second. Only when it timed out would it alter the state that the search bar used to make a call. This function was called whenever the component was updated. In other words, everytime a keystroke was entered into the serach, a timer would start. If another keystroke was made within 1000ms, the timer would reset. If no keystrokes were made for one second, an API call would be made.

Even accounting for slow typers, this reduced the amount of API calls made significantly. 

Presenting recipes without loading a new page

I thought for a while how I could keep my single page application from having to send the user to a different page where they would see their recipe. It wasn't that I thought having to move the user to a different page was necessarily bad, it was just part of the challenge I had set for myself to try to see if I could keep it all on one page.

The answer to that came from ReactstrapReactstrap made it easy for me to use Bootstrap components in my app, and in particular, I was looking for something that would render over the page. The modal component was what I decided to use in this case. So when the user clicked on a recipe, a modal component would overlay the search results and display all the recipe information.

Final design

In the end I accomplished what I set out to do. This was a single page application and the user never needed to be redirected anywhere in order to find the information they were looking for. Everything from the first step of searching for a recipe to the final step of opening up one you liked to see the details was done on one page.



Lessons learned

This was my first time using ReactJS. I loved working with it so much that I ended up almost immediately planning out a few more projects to use it on when I was finished with this one. The idea of component-based design was somewhat new to me, and I had to learn about how states are passed within a React application. Initially, I struggled with it a bit, as it was a brand new concept to wrap my head around. It wasn't long before I understood how it was all meant to work, though.

In the end, this component-based architecture approach to thinking is something that I still consider even if I'm not necessarily using ReactJS. Most apps I make these days now rely on this kind of thinking. I approach problem solving in more bite-sized component pieces, which is great because many of these components are reusable; there's no need to reinvent the wheel every time I'm faced with a task.