# How to Implement a Weather App with External API Integration

> Learn to implement a weather app with external API integration using JavaScript Fetch API and OpenWeatherMap. Display live weather data dynamically with vanilla JS.

- Repository: [Jisan Mia/dom-projects](https://github.com/jisan-mia/dom-projects)
- Tags: tutorial
- Published: 2026-03-04

---

**You can implement a weather app with external API integration by using the browser's Fetch API to call OpenWeatherMap endpoints, parsing the JSON response for temperature and conditions, and dynamically injecting formatted HTML into the DOM using vanilla JavaScript.**

This guide walks through a minimal yet complete implementation of a weather application using only HTML, CSS, and vanilla JavaScript. According to the `jisan-mia/dom-projects` source code, you can build a fully functional weather app with external API integration by following a simple three-file architecture that handles user input, fetches live meteorological data, and renders responsive results without any frameworks.

## Project Architecture and File Structure

The repository follows a clean separation of concerns with dedicated files for markup, styling, and logic. In [`projects/weather-app/index.html`](https://github.com/jisan-mia/dom-projects/blob/main/projects/weather-app/index.html), you'll find the search form and result container. The visual design lives in [`projects/weather-app/style.css`](https://github.com/jisan-mia/dom-projects/blob/main/projects/weather-app/style.css), featuring gradient backgrounds and responsive layouts. Finally, [`projects/weather-app/script.js`](https://github.com/jisan-mia/dom-projects/blob/main/projects/weather-app/script.js) contains the core integration logic that communicates with the external weather service.

The data flow works as follows:

- **User Input**: The visitor types a city name into the search field and clicks the **Search** button
- **API Request**: JavaScript intercepts the form submission and constructs a request to the **OpenWeatherMap** API
- **Response Processing**: The script checks the response code, extracts temperature, location name, and weather conditions
- **DOM Injection**: Template literals build HTML markup that is injected into the result container, updating the page instantly without a reload

## Setting Up the HTML Foundation

The markup provides a minimal interface with an input field for city names and a placeholder `div` where JavaScript will render the weather data. The structure intentionally avoids complexity to focus on the API integration logic.

```html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <link rel="stylesheet" href="style.css" />
  <title>Weather App | DOM Projects</title>
</head>
<body>
  <main>
    <section class="main-section">
      <div class="search-div">
        <div class="title"><h1>Current Weather Condition</h1></div>
        <form>
          <div class="form-group">
            <input id="searchInput" placeholder="Search by your city name" type="text"
                   autocomplete="off" spellcheck="false" />
            <button id="submit-btn" class="submit-btn">Search</button>
          </div>
        </form>
      </div>

      <div id="result-div" class="result-div"></div>
    </section>
  </main>

  <script src="script.js"></script>
</body>
</html>

```

This structure lives in [`projects/weather-app/index.html`](https://github.com/jisan-mia/dom-projects/blob/main/projects/weather-app/index.html) and provides the semantic foundation for the application.

## Fetching Weather Data with JavaScript

The core API integration happens in [`projects/weather-app/script.js`](https://github.com/jisan-mia/dom-projects/blob/main/projects/weather-app/script.js), where the **Fetch API** constructs a request URL with the city name, units preference, and API key.

```javascript
// Grab the input field once
const searchInput = document.getElementById('searchInput');

// Click handler for the Search button
document.getElementById('submit-btn').addEventListener('click', e => {
  e.preventDefault();                 // Stop form submission
  const city = searchInput.value.trim();

  if (!city) {
    alert('Please enter your city name');
    return;
  }

  // Replace the hard-coded key with your own or a proxy endpoint
  const apiKey = '30c57aaa31356639f82849e3808f9f81';
  const url = `https://api.openweathermap.org/data/2.5/weather?q=${city}&units=metric&appid=${apiKey}`;

  fetch(url)
    .then(r => r.json())
    .then(data => {
      renderWeather(data);
      searchInput.value = '';
    })
    .catch(err => console.error('Fetch error:', err));
});

```

The endpoint `https://api.openweathermap.org/data/2.5/weather` accepts query parameters for the city name (`q`), unit system (`units=metric`), and authentication (`appid`). The script uses `e.preventDefault()` to stop the form from submitting traditionally, enabling asynchronous data fetching instead.

## Rendering Results to the DOM

Once the API returns data, the `renderWeather` function validates the response and constructs the display markup. If the `cod` property equals **404**, the function alerts the user that the city was not found.

```javascript
function renderWeather(data) {
  if (data.cod === 404) {
    alert('404, City not found');
    return;
  }

  const { temp } = data.main;
  const location = data.name;
  const condition = data.weather[0].main;
  const icon = data.weather[0].icon;

  const html = `
    <div class="result-div-inner">
      <img src="https://openweathermap.org/img/wn/${icon}@2x.png" alt="${condition}" />
    </div>
    <div class="result-div-inner"><h2>${location}</h2></div>
    <div class="result-div-inner"><h3>${temp}<sup>°</sup> C</h3></div>
    <div class="result-div-inner"><h4>${condition}</h4></div>
  `;

  document.getElementById('result-div').innerHTML = html;
}

```

The function extracts `data.main.temp` for temperature, `data.name` for the location, and `data.weather[0]` for the condition description and icon ID. Using a template literal, it builds HTML with the OpenWeatherMap icon CDN URL and injects the complete string into the `#result-div` container via `innerHTML`.

## Styling the Interface with CSS

The visual layer in [`projects/weather-app/style.css`](https://github.com/jisan-mia/dom-projects/blob/main/projects/weather-app/style.css) uses CSS gradients and flexbox to create a modern, responsive layout that works on mobile and desktop screens.

```css
/* Gradient background for the search area */
.search-div {
  height: 240px;
  width: 100%;
  background-image: linear-gradient(to left, #00b4db, #0083b0);
}

/* Centered form on larger screens */
form {
  width: 400px;
  margin: 0 auto;
  text-align: center;
}

/* Result card with a top-to-bottom gradient */
.result-div {
  width: 100%;
  height: 423px;
  background-image: linear-gradient(to top, #2193b0, #6dd5ed);
  display: flex;
  flex-direction: column;
  align-items: center;
  color: #fff;
}

/* Small-screen tweaks */
@media (max-width: 375px) {
  form { width: 350px; }
}

```

The stylesheet defines a gradient header for the search section and a contrasting gradient for the results area, using flexbox to center content vertically within the result container.

## Security Considerations for Production

While the implementation in `jisan-mia/dom-projects` demonstrates the core integration pattern, several adjustments are necessary before deploying to production.

- **API Key Management**: Storing the **API key** directly in [`script.js`](https://github.com/jisan-mia/dom-projects/blob/main/script.js) exposes it to anyone viewing the source code. Replace the hard-coded key with a server-side proxy or environment variable loaded at build time.
- **Error Handling**: The current implementation only checks for 404 errors. Add handling for network failures, rate-limit responses (HTTP 429), and invalid API key errors (HTTP 401).
- **Code Modularization**: As the app grows, move the fetch logic into a separate module (e.g., [`weatherService.js`](https://github.com/jisan-mia/dom-projects/blob/main/weatherService.js)) and use ES modules (`import/export`) for better maintainability.

## Summary

- The weather app consists of three files: [`index.html`](https://github.com/jisan-mia/dom-projects/blob/main/index.html) for structure, [`style.css`](https://github.com/jisan-mia/dom-projects/blob/main/style.css) for presentation, and [`script.js`](https://github.com/jisan-mia/dom-projects/blob/main/script.js) for API integration logic.
- **OpenWeatherMap** provides the meteorological data via a REST endpoint that accepts city names and returns JSON payloads containing temperature, conditions, and icon references.
- The **Fetch API** handles the asynchronous request, while template literals and `innerHTML` enable instant UI updates without page reloads.
- Production deployments require server-side API key storage and expanded error handling beyond the basic 404 check implemented in the source code.

## Frequently Asked Questions

### What external API does the weather app use?

The application integrates with the **OpenWeatherMap API**, specifically the `/data/2.5/weather` endpoint. This service returns current weather conditions, temperature data, and icon references for any valid city name passed as a query parameter.

### How does the app display weather data without reloading the page?

The implementation uses the **Fetch API** to make asynchronous HTTP requests in the background. When the promise resolves, JavaScript parses the JSON response and updates the DOM directly using `innerHTML`, creating a single-page application experience where only the content within the result container changes.

### Is it safe to hardcode the API key in the JavaScript file?

No, storing the **API key** directly in client-side code is insecure for production environments because the key is visible to anyone who inspects the source. You should replace the hard-coded string with a server-side proxy endpoint that securely stores the key, or use environment variables during a build process to inject the key only at deployment time.

### How does the app handle invalid city names?

The `renderWeather` function checks if `data.cod === 404` immediately after receiving the API response. If this condition is true, the function triggers an alert notifying the user that the city was not found and returns early without attempting to render weather data. For production use, you should replace the generic alert with a more user-friendly inline error message.