Snowflake Frontend Phone Screen

📋 Problem Statement

You are given two asynchronous API functions:

  • getTemperatureData(day) — returns a Promise resolving to an object mapping cities to temperature data.
  • getRainData(day) — returns a Promise resolving to an object mapping cities to rainfall data, but fails every alternate time it's called (counter % 2 === 0) and takes up to 3 seconds to respond.

Both functions accept a day string (e.g. "2024-07-17").

The goal is to display merged data in the following format for each city:
Seattle - 75 22
San Mateo - 80 15
Austin - 90 30

Where each line contains:
-

If getRainData() fails, just omit rainfall from the output:
Seattle - 75
San Mateo - 80
Austin - 90

Constraints

  • Rain data is not guaranteed.
  • Do not block UI for 3 seconds if rain fails — be resilient and render what you can.
  • You may use React or vanilla JS.

Mock Data:
// mockData.js

let rainCounter = 0;

export function getRainData(day) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      rainCounter++;
      if (rainCounter % 2 === 0) {
        reject(new Error("Rain API failed"));
      } else {
        resolve({
          Seattle: 13 + day,
          "San Mateo": 25 + day,
          Austin: 8 + day,
        });
      }
    }, 3000 * Math.random());
  });
}

export function getTemperatureData(day) {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve({
        Seattle: 103 + day,
        "San Mateo": 84 + day,
        Austin: 91 + day,
      });
    }, 500 * Math.random());
  });
}

Potential Solution:
// WeatherComponent.jsx

import React, { useEffect, useState } from "react";
import "./App.css";
import { getRainData, getTemperatureData } from "./mockData";

function App() {
  const [rainData, setRainData] = React.useState({});
  const [temperatureData, setTemperatureData] = React.useState({});
  const [rainError, setRainError] = React.useState(null);
  const [tempError, setTempError] = React.useState(null);
  const [loading, setLoading] = React.useState(false);

  const fetchData = async () => {
    console.log('fetchData called at:', new Date().toISOString());
    try {
      setLoading(true);
      const [rainInfo, tempInfo] = await Promise.allSettled([
        getRainData(),
        getTemperatureData(),
      ]);

      if (rainInfo.status === 'fulfilled') {
        setRainData(rainInfo.value);
        setRainError(null);
      } else {
        setRainError('Rain data fetch failed');
      }

      if (tempInfo.status === 'fulfilled') {
        setTemperatureData(tempInfo.value);
        setTempError(null);
      } else {
        setTempError('Temperature data fetch failed');
      }
    } finally {
      setLoading(false);
    }
  };

  useEffect(() => {
    fetchData();
  }, []);

  const displayMap = new Map();
  for (const city in rainData) {
    displayMap.set(city, {
      rain: rainData[city],
      temperature: temperatureData[city] || 'N/A',
    });
  }

  return (
    <div className="App">
      <p>Weather Data Fetching Example</p>
      {loading && <p>Loading...</p>}
      
      <div>
        <h2>Rain Data</h2>
        {rainError ? (
          <p>Error: {rainError}</p>
        ) : (
          <pre>{JSON.stringify(rainData, null, 2)}</pre>
        )}

        <h2>Temperature Data</h2>
        {tempError ? (
          <p>Error: {tempError}</p>
        ) : (
          <pre>{JSON.stringify(temperatureData, null, 2)}</pre>
        )}

        {displayMap.size > 0 && (
          <div>
            <h2>Combined Data</h2>
            <ul>
              {Array.from(displayMap.entries()).map(([city, data]) => (
                <li key={city}>
                  <strong>{city}</strong>: Rain - {data.rain}mm, Temperature - {data.temperature}°F
                </li>
              ))}
            </ul>
          </div>
        )}
      </div>
    </div>
  );
}

export default App;

I failed, but later tried a solution with chatgpt.

Comments (2)