DEV Community

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

Posted on

4 1 1 1

How to use Firebase Studio to build a weather app.

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/

DevCycle image

Fast, Flexible Releases with OpenFeature Built-in

Ship faster on the first feature management platform with OpenFeature built-in to all of our open source SDKs.

Start shipping

Top comments (4)

Collapse
 
nevodavid profile image
Nevo David

pretty cool seeing the workflow laid out like this - tbh launching is always the real test for me, you think real-world feedback changes how folks actually build stuff long-term?

Collapse
 
hr21don profile image
Helitha Rupasinghe

Its why i tried out firebase studio. Rapid Launch!

Collapse
 
nathan_tarbert profile image
Nathan Tarbert

pretty cool seeing a start-to-finish build like this tbh, you think improvements come more from constantly shipping updates or getting real users to try it out and give you feedback?

Collapse
 
hr21don profile image
Helitha Rupasinghe

A bit of both to be honest.

Some comments may only be visible to logged-in visitors. Sign in to view all comments. Some comments have been hidden by the post's author - find out more

Tiger Data image

🐯 🚀 Timescale is now TigerData: Building the Modern PostgreSQL for the Analytical and Agentic Era

We’ve quietly evolved from a time-series database into the modern PostgreSQL for today’s and tomorrow’s computing, built for performance, scale, and the agentic future.

So we’re changing our name: from Timescale to TigerData. Not to change who we are, but to reflect who we’ve become. TigerData is bold, fast, and built to power the next era of software.

Read more

👋 Kindness is contagious

Embark on this engaging article, highly regarded by the DEV Community. Whether you're a newcomer or a seasoned pro, your contributions help us grow together.

A heartfelt "thank you" can make someone’s day—drop your kudos below!

On DEV, sharing insights ignites innovation and strengthens our bonds. If this post resonated with you, a quick note of appreciation goes a long way.

Get Started