How to use Firebase Studio to build a weather app.
Helitha Rupasinghe

Helitha Rupasinghe @hr21don

About: Developer 💻 | Technical Writer 📝 @ThePracticalDev @Medium @Teelfeed @Hashnode @LinkedIn | Open to collaborate 🔓 | AI Enthusiast 🤑 | Caught 🔥 Coding | 4.4 Blog Subscribers

Joined:
Jan 14, 2022

How to use Firebase Studio to build a weather app.

Publish Date: Jun 8
7 6

Firebase Studio allows you to rapidly prototype, build, and ship full-stack AI-infused apps quickly and efficiently, right from your browser. And in this post, we'll guide you through the process of building a weather app using Gemini.

Step 1: Gather your information

Before you start building your weather app, it's important to define the features you want to include. This can be included in a wireframe that covers elements such as input fields for city names, a search button, weather display sections based on geolocation, and error handling.

Wireframe

For this project, we’ll use the OpenWeatherMap API to get the current weather data and display it in the browser. The following information will be shown:

  • City name
  • Temperature
  • Humidity
  • Wind speed
  • Weather description
  • Weather condition

API Documentation: https://openweathermap.org/current#cityid

Step 2: Create your website content

Now it's time to create your website content. This involves providing Firebase Studio with a use case.


Generate a basic structure for a weather app. The core features for this app are included in the wireframe and should include:

- City Input: City Input Field: Allows users to enter a city name to request weather data.
- Search: Search Button: Triggers the weather fetch functionality with a clear, clickable button.
- Weather Display: Weather Display Sections: Displays current weather conditions such as temperature, humidity, wind speed, and weather description.
- Error Handling: Error Handling: Shows user-friendly error messages when a city is not found or when data cannot be retrieved.

Enter fullscreen mode Exit fullscreen mode

When reviewing this content generated by Gemini, it's important to remember that you can fine-tune it as you go along.

SkyCast

It'll take about 1–2 minutes to generate the project along with all necessary dependencies, including React, TypeScript, NextJS, Tailwind CSS.

Step 3: Test your site

This project generated the following file structure with Mock API data for successful responses:

FolderStructure.png

The mock api data can be found in the action.ts file:


  // Mock data for successful responses
  const mockWeatherData: { [key: string]: WeatherData } = {
    london: {
      city: 'London',
      temperature: 15.2,
      humidity: 72,
      windSpeed: 5.1,
      description: 'scattered clouds',
      iconName: 'Clouds',
    },
    paris: {
      city: 'Paris',
      temperature: 18.5,
      humidity: 65,
      windSpeed: 3.5,
      description: 'clear sky',
      iconName: 'Clear',
    },
    tokyo: {
      city: 'Tokyo',
      temperature: 22.0,
      humidity: 80,
      windSpeed: 2.0,
      description: 'light rain',
      iconName: 'Rain',
    },
    newyork: {
        city: 'New York',
        temperature: 25.0,
        humidity: 60,
        windSpeed: 7.0,
        description: 'few clouds',
        iconName: 'Clouds',
    }
  };


Enter fullscreen mode Exit fullscreen mode

Mock data successfully displayed the relevant weather content in the browser, given the user enters one of the cities from the prompt, such as London, New York, or Tokyo.

Mockup

Step 4: Modify your site

Next, you'll need to add the API key from OpenWeatherMap.org to your environment variables.

Secondly, you can modify the getWeather function in src/app/actions.ts using Gemini:

  1. Read the city list from src/app/city.list.json.
  2. Find the city ID based on the provided city name (The list can be downloaded from https://openweathermap.org/current#cityid).
  3. Make an API call to OpenWeatherMap using the city ID and the API key from the environment variables.
  4. Parse the API response and return the weather data in the desired format.

Note: OpenWeatherMap recommends calling the API by city ID to get unambiguous result for your city.

'use server';

import type { WeatherData, WeatherError, WeatherResponse } from '@/lib/types';
import cityList from './city.list.json';

// Mock API call - in a real app, this would fetch from OpenWeatherMap
export async function getWeather(
  // biome-ignore lint/correctness/noUnusedVariables: parameter reserved for framework integration
  _prevState: WeatherResponse | null,
  formData: FormData
): Promise<WeatherResponse> {
  const cityEntry = formData.get("city");

  if (typeof cityEntry !== "string" || cityEntry.trim() === "") {
    return { error: "Please enter a city name." };
  }

  const city = cityEntry.trim();
  const openWeatherMapApiKey = process.env.OPENWEATHERMAP_API_KEY;

  if (!openWeatherMapApiKey) {
    console.error("OPENWEATHERMAP_API_KEY is not set in environment variables.");
    return { error: "Server configuration error: API key missing.", city };
  }

  // Ensure cityList is available
  if (typeof cityList === "undefined") {
    return { error: "Internal error: city list is not available.", city };
  }

  const foundCity = cityList.find(c => c.name.toLowerCase() === city.toLowerCase());
  if (!foundCity) {
    return { error: `City "${city}" not found. Please check the spelling.`, city };
  }

  const cityId = foundCity.id;
  const apiUrl = `https://api.openweathermap.org/data/2.5/forecast?id=${cityId}&appid=${openWeatherMapApiKey}&units=metric`;

  try {
    const controller = new AbortController();
    const timeout = setTimeout(() => controller.abort(), 10000); // 10s timeout

    const response = await fetch(apiUrl, { signal: controller.signal });
    clearTimeout(timeout);

    if (!response.ok) {
      const errorBody = await response.text();
      console.error(`OpenWeatherMap API error: ${response.status} ${response.statusText}`, errorBody);
      return { error: `Could not retrieve weather data: ${response.statusText}`, city };
    }

    const data = await response.json();

    if (!Array.isArray(data.list) || data.list.length === 0) {
      return { error: "Weather data is missing or malformed.", city };
    }

    const forecast = data.list[0];

    if (
      !forecast.main ||
      !forecast.weather ||
      !Array.isArray(forecast.weather) ||
      forecast.weather.length === 0 ||
      !forecast.wind
    ) {
      return { error: "Incomplete weather information received.", city };
    }

    return {
      city: foundCity.name,
      temperature: forecast.main.temp,
      humidity: forecast.main.humidity,
      windSpeed: forecast.wind.speed,
      description: forecast.weather[0].description,
      iconName: forecast.weather[0].main,
    };
  } catch (error) {
    if ((error as Error).name === "AbortError") {
      return { error: "Weather data request timed out.", city };
    }

    console.error("Error fetching weather data:", error);
    return { error: "An error occurred while fetching weather data.", city };
  }
}

Enter fullscreen mode Exit fullscreen mode

The final result is a successful response from the API returning the weather display based on the city name provided by the user.

End-Result

Step 5: Launch your site

When you're satisfied with the result, you can launch your site and start showcasing your weather app to the world.

Github 👉 https://github.com/JavascriptDon/SkyCast

Live Demo 👉 https://sky-cast-three-plum.vercel.app/

Comments 6 total

Add comment