Full-Stack
WhereTo - Climate Travel App
Completion Date: March 2022
WhereTo is a travel app that suggests locations with weather similar to your input destination. This was the final project for the Northcoders bootcamp, and was built as a team using agile methodology. It uses a non-relational database to store climate and city data, and external APIs to fetch coordinates, photos and weather data.
Technology
- Svelte
- Svelte Kit
- MongoDB
- TypeScript
- Hosted with Vercel
I wanted to use technology that was highly rated by developers, so we built it with Svelte, SvelteKit, MongoDB, and wrote the application using TypeScript. It was a steep learning curve to take on all this new technology and learn it in a short timeframe, but while undertaking the project we came to love the tech, and really enjoyed using Svelte.
A few years ago I saw a fantastic map on Reddit that showed locations that had similar climates. At the time I was working selling wine, and found it so interesting that places like the Hunter Valley near Sydney, Australia had the same climate as Buenos Aires, Argentina, a region on the other side of the world. For bootcamp project pitches I immediately thought of this and knew this was a great idea that we could create.
As this was a group project, we divided the work using a Trello board and had daily stand ups to discuss our progress and deal with blocking issues.
My main contributions were turning the user input into co-ordinates to query the database, fetching information for each city, and creating the location page to display further information for each place.
Since completing the course I have continued to work on the app, re-introducing the seeding feature for people to seed their own database when running locally, and fixing bugs to allow for hosting with Vercel.
Key Features
- Utilizes non-relational database and external APIs
- Type checked with TypeScript
- Uses MongoDB Geospatial Queries to handle coordinate information
// User input string is used to query the Google Autocomplete API to get a place id
const placeIdFetch = async (location: string) => {
const res = await fetch(`/api/destination/${location}`);
if (res.status === 200) {
const resObject = await res.json();
// Place predictions are shown to the user in the autocomplete drop down list
predictions = resObject.predictions;
placeId = resObject.place_id;
} else {
predictions = TEMPPREDICTION;
placeId = 'TEMPPLACEID';
}
};
// Fetch call to Google Geocoding API get lat/long co-ordinates from the place id
const coordinateFetch = async (place_id: string): Promise<Coordinates> => {
const res = await fetch(`/api/latlng/${place_id}`);
const resObject = await res.json();
// PlaceName and country appended to URL for use on the searchresults page
placeName = [resObject.placeName, resObject.country];
return resObject.coordinates;
};
When the user enters their location, the string is passed into Google Autocomplete API, which returns a place ID. This place ID is used to query the Google Places API to get co-ordinates for the user's input destination.
The co-ordinates are then used to query the MongoDB database to return the array of cities with a similar climate.
// Query the database with the co-ordinates to get an array of similar cities
try {
cities = await getCitiesSimilarToLocation([lng, lat], { limit: 9 });
} catch (error) {
console.log(error);
}
// For each city, fetch the weather and a photo
const combinedData = await Promise.all(
cities.map(async (city) => {
const cityWeather = await getWeather(city.city_ascii);
const { photo_reference } = await getPhotoRef(city.city_ascii);
const src = `https://maps.googleapis.com/maps/api/place/photo?maxwidth=400&photoreference=${photo_reference}&key=${process.env['VITE_API_KEY']}`;
return { weather: cityWeather, details: city, src } as City;
})
);
Inside the Search Results page endpoint, current weather and photos are fetched for each city. These cards are iterated and rendered onto the page.
Problems I faced
Using a meta-framework like SvelteKit offered a lot of new possibilities compared to Create React App projects like I had previously made. I found Svelte to be great and intuitive to use, but due to the lack of documentation, and my first time using a meta-framework, I had to re-write some features as I figured out better ways to approach the problem. Originally, I had made fetch requests in the component file. Then, I found out about API endpoints, and moved the fetch calls to there. Finally, I learnt about page endpoints and this was the best solution for fetching data. This was a great learning experience and helped me understand how to structure a project like this in the future.
On the home page there were a few steps required to convert the user's search location into coordinates.
I had to first use the Google Autocomplete API to turn the user's input, generally a city name, into a full address. This query returned a Google place id, which was then subsequently used to call the Google Places API, returning the coordinates needed to query the MongoDB database, giving us the cities with a similar climate. Google Maps has two APIs for different purposes – one for client side, and one for server side. I spent an evening getting one to work, only for me to realize I had implemented the wrong one and needed the server side API. This really helped me to learn to read the documentation and understand what I need before I start writing code.
We used TypeScript on this project because it is highly rated by so many developers. TypeScript can be overwhelming at first, causing a lot of errors (but importantly, before production!). To be able to use it properly I had to spend some extra time in completing the Codecademy TypeScript course to understand how to utilize it's features correctly, especially interfaces and object typing. This was a massive help to me and I will definitely use TypeScript moving forward.
When stitching the final product together, we had some problems linking all the pages together to create a smooth user journey. This was our first project as a group, so merging the branches together had a learning curve to overcome. It definitely improved my Git skills.
What I learnt
- The usefulness of Meta Frameworks
In future projects I will take advantage of features like page endpoints to render content server-side before page load. Svelte Kit's file-based routing makes it so easy to create routes.
- Improved skill working with APIs
I spent a lot of time working with external APIs like Google Places. This has increased my confidence using these tools in future projects.
- How to use TypeScript
I learnt how to use TypeScript, and how useful it is. This will serve me well in future projects now I have overcome the initial learning curve.
- Concise syntax of Svelte
I enjoyed using Svelte, particularly how simple it is to manage state.
// Svelte concise syntax for form submission event handler
<form on:submit|preventDefault={onConfirmSubmit}>
...
</form>
For example, handling a form submission can be done in such a little amount of code, whereas in React this is a more verbose process.
- Improved Git skills
Working in a team on different branches and working with pull requests massively improved my skills with Git. This will be extremely helpful in future projects and working on development teams.
What I would improve
With more time on this project I would create additional features such as flight information, distance to destination, currency exchange rates. The 'My Places' and 'My Searches' pages are both placeholders so I would finish their functionality.
Instead of fetching data in multiple places, I would use Svelte Stores to fetch the data once and allow access to it from different places in the app.
There was a geolocation feature which we didn't have time to fully implement, I would like to finish this functionality by using the co-ordinates to autofill the user location through reverse geocoding.