Working with APIs & Structured Data
A 2-hour practical workshop for researchers using JavaScript to work with data, starting from lesson_2.zip
Overview
This workshop introduces Application Programming Interfaces (APIs) and structured data formats commonly used in research and public data portals.
Participants will learn how to request data from an API, interpret structured responses, and display results in a clean, readable format using JavaScript.
- Duration: 2 hours
- Outcome: A webpage that automatically loads and displays weather forecast data
What Are APIs?
An API is a structured way for software systems to share data. For researchers, APIs provide programmatic access to datasets that are frequently updated or too large to download manually.
Common research uses of APIs include:
- Accessing public datasets (environmental data, census, etc.)
- Automating data collection (e.g., fetching weather data every hour)
- Ensuring reproducibility
- Building interactive research outputs
Common Structured Data Formats
JSON
JavaScript Object Notation. Human-readable, widely used, and native to JavaScript.
GeoJSON
A geographic extension of JSON for spatial data (points, lines, polygons).
CSV
Comma-Separated Values. Common for spreadsheets and tabular research data.
XML
Extensible Markup Language. Older but still used in many scholarly systems.
In this workshop, we focus on JSON and GeoJSON because they work naturally with JavaScript.
The National Weather Service (NWS) API
The NWS provides a free, public API that returns weather forecasts in JSON format.
A typical request looks like this:
https://api.weather.gov/points/39.7456,-97.0892
This endpoint returns metadata, including a link to the forecast for that location. See the NWS API Web Service page for details.
Mini Exercise (5–7 min)
Explore the NWS API response in your browser.
- Install a json-formatter extension in your browser (e.g., JSON Formatter for Chrome)
- Open https://api.weather.gov/points/39.7456,-97.0892
- Notice how the data is organized
Using the Visitor’s Location
Instead of hard-coding latitude and longitude, we can use the browser’s navigator.geolocation API.
navigator.geolocation.getCurrentPosition(position => {
const lat = position.coords.latitude;
const lon = position.coords.longitude;
});
These coordinates can then be used to replace 39.7456,-97.0892 dynamically.
Fetching Data with JavaScript
JavaScript uses the fetch() function to request data from an API.
async function get_weather_forcast(lat, lon) {
console.log("Fetching forecast for:", lat, lon);
const pointsRes = await fetch(`https://api.weather.gov/points/${lat},${lon}`);
const pointsData = await pointsRes.json();
const forecastRes = await fetch(pointsData.properties.forecast);
return await forecastRes.json();
}
fetch() returns a Promise, not the data, and is often used with the following to complete the request:
- async allows operations to run without blocking the main program thread, ensuring the application remains responsive
- await used to pause the execution of an async function until a Promise is settled (fulfilled or rejected)
This chained request pattern is common when working with linked APIs.
Then What
.then() is a method used with Promises to handle the results of asynchronous operations. The updated geolocation below shows how to work with .then()
navigator.geolocation.getCurrentPosition(position => {
let lat = position.coords.latitude;
let lon = position.coords.longitude;
get_weather_forcast(lat,lon)
.then(data => {
update_forcast(data);
}
)
});
Looping Over Forecast Data
The forecast response includes an array of time periods. We can loop over this data and build a table.
forecastData.properties.periods.forEach(period => {
console.log(period.name, period.temperature, period.shortForecast);
});
Displaying Data in a Table
<table id="forecast">
<thead>
<tr>
<th>Period</th>
<th>Temperature</th>
<th>Forecast</th>
</tr>
</thead>
<tbody></tbody>
</table>
const tbody = document.querySelector('#forecast tbody');
tbody.innerHTML = ""; // Clear existing rows
forecastData.properties.periods.forEach(period => {
const row = document.createElement('tr');
row.innerHTML = `
<td>${period.name}</td>
<td>${period.temperature}°F</td>
<td>${period.shortForecast}</td>
`;
tbody.appendChild(row);
});
This approach cleanly separates data retrieval from presentation.
To make this table much more visually appealing, the following CSS can be used:
table {
width: 100%;
border-collapse: collapse;
margin: 2rem 0;
font-size: 0.95rem;
background-color: #ffffff;
border-radius: 0.5rem;
overflow: hidden;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
}
thead {
background-color: #0f172a;
color: #ffffff;
}
thead th {
text-align: left;
padding: 0.75rem 1rem;
font-weight: 600;
letter-spacing: 0.02em;
}
tbody tr {
border-bottom: 1px solid #e5e7eb;
}
tbody tr:nth-child(even) {
background-color: #f8fafc;
}
tbody tr:hover {
background-color: #eef2ff;
}
td {
padding: 0.75rem 1rem;
vertical-align: top;
}
Mini Exercise (5–7 min)
Update the HTML Table and JavaScriptforecastData forEach loop to include the icon property
- Create new HTML
- th element
- Update Javascript 'template' string
Web Services
Web services are powerful network-accessible resources capable of being pulled into your website. There are plenty of web services available for developers to use in their projects.
The ArcGIS Living Atlas of the World is a great index of these, with lots to choose from.
We'll use the Current Weather and Wind Station Data.
ArcGIS Online, the plaform that powers the ArcGIS Living Atlas, uses a consistent API structure for all its web services.
Let's look at how to work with this API and pull in some weather station data. From the Current Weather and Wind Station Data page, you should see a link to the REST API on the right labled URL.
- Navigating to this page will bring you to the REST Services Directory.
- From here, clicking the Layers link for stations will bring you to the Layer page for the station data.
- On the bottom of this page is the link to query the data.
Clicking the query link reveals the Query:Stations form.
This complex form isn't as itimitating as it looks as we only have to fill out a few fields to get data back. Make the following entrys:- where: 1=1
- outFields: *
- And change the Formate to: GEOJSON
- Then click Query (GET)
Note: if you only want to return one record, set "Result Record Count:" to 1. Great to testing large datasets! The complete code for this example can been seen at lesson 3, and can be download from lesson_3.zip.