Vacations are fun. You have a well earned right to do pretty much nothing. It is very nice to ditch the keyboard and computer aside for a while, and maybe travel to some place nice, read a book, or just lay down in a hammock. Just like pretty much every summer for the past two decades, I did just about all of that. Good habits die hard...
After a couple of weeks of travel and procrastination, I got tired of doing not really anything, and realized I needed a vacation project. You now – one of those cool little hobby projects – when you can do absolutely anything you wish. Maybe try some new fancy technology, new awesome service, or just build something fun and useful for yourself.
Since I like to travel and see cool places, I would like to easily document these places I visit. By document, I mean things like:
- Pin the location to a map.
- Write a short description to remember the best places to see and experience, maybe add some links, and of the sort.
- Upload some pictures.
And since there surely cannot be an app in 2019 without a social component, I added an ability to comment the pins. ¯\_(ツ)_/¯
I set myself some rules to keep things interesting: The project must not use Firebase or any AWS services. On the other hand, the project must use GraphQL, OAuth for authentication and React Hooks, and it must deliver something usable in the end.
While building the frontend on top of React, I wanted to use Hooks, which I had not really used before, so it was going to be React version 16.8.0 or newer. I was going to bootstrap the project with Create React App.
The obvious choice for backend would have been Firebase (for data storage and authentication), so I wanted to use something different. I decided to use MongoDB as the datastore. Since I still wanted an easy hosting, I ended up using MongoDB Atlas, which is a fully-managed hosting option. For authentication I wanted to try Google as an OAuth provider.
I have been using GraphQL with Gatsby already, and now I wanted to incorporate GraphQL to a full-blown React app too. Since I had heard only good things about Apollo Client, I was going to look firmly to that direction. I still did not quite know, what to use on the serverside to glue MongoDB, GraphQL and Google OAuth together.
Since there was not going to be Firebase available for this project, Cloudinary would be the the service to process and host the images.
What about the maps? Google Maps? With the pricing changes last year, and to try something else, I was going to go with Mapbox.
For the styling of the app I was going to stick with my default choice of Material-UI, which implements React Components for Google's Material Design.
This is not going to be a detailed tutorial, but a highlevel overview, how things work.
As I wrote in the previous chapter, the frontend is a React app bootstrapped with Create React App. The app consists of a few top-level components:
- Pin Popup for the Pin image, and controls to edit or delete the Pin.
- Pin details for adding, showing and editing of the Pin details.
The user interface is built with Material-UI React components, with the addition of the Map and Popup Components provided by Mapbox.
The state management of the app ended up being super simple by using the Apollo Client, React Hooks and Context. Subscriptions are used to react (pun intended) to the data / state changes. In this case I ended up using the Context for state, but it is not quite intended to use this way — maybe this will need attention in the future.
The user login is handled via
React Google Login React component. Authenticated API calls to the backend uses
In the backend I ended up using Apollo Server, which made the implementation very simple. The authentication uses
Google Auth Library package to verify the client requests. Mongoose is used to tie the Apollo resolvers to the MongoDB.
This was a fun little vacation project. I learned a ton of new and improved / easier ways to build a small React app. Using GraphQL, Apollo and the new(ish) React Hooks and Context features makes the state management so much easier compared to the old way of using State and Class-based components. At least for me they do.
With a three days worth of tinkering, I also ended up with a pretty much functional app, which of course will need a few tweaks, before I would be brave enough to deploy the app to the web. I propably would push the server to Heroku, and the client to Netlify. Or maybe something else.
There's also a lot of things, which could be further developed. Many, many features could be added, and maybe the server and GraphQL parts could be switched to AWS Amplify and App Sync for a fully Serverless solution.
Then again, this was just a Vacation Project, not everything needs to be perfect.