Studio Matrx Monthly · Volume 1 · Issue 3 · August 2026
Amogh N P
 In loving memory of Amogh N P — Architect · Designer · Visionary 
APIs and Getting Web DataLesson 8.4
PSD for Architecture, Planning & Urban Design/Module 8 · Automation & the Everyday Toolkit

Lesson 8.4 · Automation & the Everyday Toolkit

APIs and Getting Web Data

What an API is, the requests library, and pulling live JSON - weather, sun, geocoding, material data - straight into your design scripts

13 min Interactive lessonFree · open lessonByAmogh N P· Architect & interior designer
The hook

Ask a server for today's weather at your site, get back a Python dictionary, and drop it straight into your climate analysis - in five lines.

A vast amount of data useful to designers lives online and changes constantly: weather and climate normals, sun positions, geocoded coordinates for a site address, elevation, air quality, material and product databases. Copy-pasting it by hand is slow and goes stale immediately.

An API - Application Programming Interface - is how one program asks another for data directly, in a format built for code rather than eyes. With Python's requests library you send a request to a web address, the server sends back structured JSON, and requests hands it to you as an ordinary Python dictionary you already know how to use. This lesson demystifies APIs, walks a real example end to end, and covers the etiquette - keys, rate limits, errors - that keeps you a welcome guest.

API = menu of requests. get -> status + JSON. r.json() is a dict. Key secret, timeout set, rate limits respected.

What an API actually is

Strip away the jargon and an API is a menu of requests a service agrees to answer. When you open a weather website, a human reads a page designed for eyes. An API is the same data offered in a form designed for code: you send a precise request to a web address (a URL), and the server sends back clean, structured data - no page layout, no adverts, just the values. Think of a restaurant: the menu (the API documentation) lists exactly what you can order and how to ask; you place an order (a request); the kitchen returns your dish (the response). You do not need to know how the kitchen works, only how to order.

Most design-relevant APIs are web APIs spoken over HTTP - the same protocol your browser uses. The most common action is a GET request, which reads data: give me the weather at this latitude and longitude, geocode this address, look up this material. You often refine the request with parameters - the lat, lon, date bolted onto the URL after a ?. The server answers with two things: a status code telling you how it went (200 means OK; 404 not found; 429 you are asking too often) and a body, usually JSON - the same key-value structure as a Python dictionary. That mapping is the whole reason APIs are so usable from Python: the response is, in effect, a dictionary waiting for you.

You will often hear these called REST APIs and their addresses called endpoints - an endpoint is simply a specific URL for a specific kind of request, one for weather, another for geocoding, another for a material lookup. The vocabulary sounds formal, but for the everyday job of reading data it always reduces to the same three questions: which URL, which parameters, and what does the returned JSON look like. Answer those from the documentation and the code almost writes itself.

REQUEST -> RESPONSEYOUR SCRIPTrequests.get(url,params=...)SERVER / APIweather, geo,material dataGET ?lat=12.9&lon=77.6200 OK { "temp": 28.4 }r.json() -> Python dictdata["temp"] == 28.4
Zoom
An API call is a conversation. Your script sends a GET request to a URL with parameters; the server answers with a status code and a JSON body, which requests parses into an ordinary Python dictionary you can read straight into your design work.

The requests library - a GET in three lines

requests (pip install requests) is the friendly standard for talking to web APIs. The core is requests.get(url), which returns a response object carrying the status code and the body. A minimal call against a real, key-free API - Open-Meteo for weather:

python
import requests

url = "https://api.open-meteo.com/v1/forecast"
params = {"latitude": 12.97, "longitude": 77.59,
          "current": "temperature_2m"}
r = requests.get(url, params=params, timeout=10)
r.raise_for_status()
data = r.json()
print(data["current"]["temperature_2m"], "deg C")

Each line earns its place. Passing params as a dictionary lets requests build the ?latitude=12.97&longitude=77.59&... query string for you, correctly encoded - never hand-glue URLs. timeout=10 caps how long to wait so a slow server cannot hang your script forever. r.raise_for_status() turns a failure code (404, 500) into a clear Python error instead of letting a broken response slip silently downstream. r.json() parses the JSON body into Python objects - dictionaries and lists - so data["current"]["temperature_2m"] reaches into the structure exactly as you index any dictionary. That is the entire mechanic of pulling web data: build a request, check it, parse it, index it. Everything else is reading the particular API's documentation to learn its URL, its parameters, and the shape of the JSON it returns.

It is worth pausing on the response object r, because you will lean on it constantly. Beyond r.json(), r.status_code is the numeric result to compare against 200, r.ok is a quick boolean for success, and r.url shows the exact address requests built from your parameters - printing it is the fastest way to confirm your query went out as you intended. When a call misbehaves, these three attributes usually reveal why long before you need anything more elaborate, so reach for them first whenever a request surprises you.

get(url, params=dict, timeout=10) -> raise_for_status() -> r.json() -> index like a dict. Read the docs for the shape.

Reading JSON - a response is nested dictionaries and lists

The response body is JSON - JavaScript Object Notation - a text format of nested objects ({}, which become Python dicts) and arrays ([], which become Python lists). Once r.json() parses it, navigating is exactly the dict-and-list indexing from Module 2, just deeper. A geocoding response - turning a place name into coordinates - shows the nesting:

python
import requests

r = requests.get("https://geocoding-api.open-meteo.com/v1/search",
                 params={"name": "Jaipur", "count": 1}, timeout=10)
result = r.json()["results"][0]
lat = result["latitude"]
lon = result["longitude"]
print(f"Jaipur is at {lat}, {lon}")

Walk the path: r.json() is a dict; ["results"] is a list of matches; [0] takes the first; ["latitude"] reads a field from it. Reading the API's documentation - or simply print(r.json()) once to see the shape - tells you that path. Real data is messy, so code defensively: a place might have no matches ("results" missing or empty), a field might be absent. Reach in with .get() and check before indexing:

python
results = r.json().get("results", [])
if results:
    first = results[0]
    lat = first.get("latitude")
else:
    print("No match found")

This is the same defensive instinct as guarding against blank spreadsheet cells - assume the data can surprise you, and handle the empty case rather than crashing on it. A practical tip for exploring an unfamiliar response: import json; print(json.dumps(r.json(), indent=2)) pretty-prints the whole structure with clear indentation, so you can see exactly where every value sits before writing a single line of parsing. Now chain the two: geocode an address to coordinates, then feed those into the weather call - a two-request pipeline that turns 'what is the climate at this site?' into a few lines, live.

WEB DATA -> DESIGNsite name"Jaipur"geocode API-> lat, lonweather API-> temp, sundesign studyshading, passiveChain requests: each JSON response feeds the next call, and live data lands in your analysis.
Zoom
Live web data as a design input. A place name becomes coordinates (geocoding API), coordinates become live weather (forecast API), and that data flows straight into a shading study or passive-design spreadsheet - the web treated as just another input stage.

Keys, rate limits and being a good guest

Two practical realities separate a toy call from a dependable script. First, authentication: many APIs require a key - a personal token that identifies you - which you register for and then pass with each request, often as a parameter or a header. Treat a key like a password: never paste it into code you share or commit to git. Read it from an environment variable instead, so the secret stays out of the source:

python
import os, requests

key = os.environ["WEATHER_API_KEY"]
r = requests.get(url, params={"q": "Delhi", "appid": key}, timeout=10)

Second, etiquette. An API is someone else's server, and abusing it gets you blocked. The rules are simple courtesy. Respect rate limits - the cap on requests per minute or day, stated in the docs; a 429 status means slow down. If you are fetching for many sites in a loop, add a small time.sleep(1) between calls so you do not hammer the server. Cache results you will reuse: geocoding the same address a hundred times is a hundred needless requests - fetch once, save the JSON to a file, and read it back. Always set a timeout, and handle failure so one bad response does not sink a long run:

python
import time, requests

for city in cities:
    try:
        r = requests.get(url, params={"name": city}, timeout=10)
        r.raise_for_status()
        handle(r.json())
    except requests.RequestException as e:
        print(f"skipped {city}: {e}")
    time.sleep(1)

Finally, know the line between an API and web scraping. An API is data offered for programs, with terms you should honour; scraping - parsing a human web page - is a last resort when no API exists, and it comes with legal and ethical strings and brittle code that breaks when the page changes. Prefer the front door. Used politely, APIs turn the live web into just another input to your design scripts.

Beyond GET - a fuller picture and its limits

Reading data with GET covers the overwhelming majority of what a designer needs, but it helps to know the shape of the rest. Alongside GET, APIs use verbs like POST (send data to create something on the server) among others; you will rarely need them for pulling design data, but you will recognise them in the documentation. Some services want their key or options in headers rather than URL parameters - requests takes a headers={...} dictionary for exactly that. And the response object carries far more than JSON: r.status_code, r.headers and r.text (the raw body) are all there when you need to debug why a call behaved oddly - printing them is the first thing to do when a request surprises you.

The real power comes from joining web data to the rest of your toolkit. A parsed response is an ordinary Python dictionary, so you can write it to disk with the json module, load it into pandas for analysis, drop the numbers into an openpyxl spreadsheet, or feed coordinates straight into a geometry script. Saving the fetched data locally is not only politeness - it makes your analysis reproducible: the snapshot is stored with the project, so re-running the study months later gives the same result even if the live service has since changed its numbers.

python
import json, requests

r = requests.get(url, params=params, timeout=10)
r.raise_for_status()
data = r.json()
with open("site_weather.json", "w") as f:
    json.dump(data, f, indent=2)

That one habit - fetch once, save the JSON, then work from the file - keeps you polite to the server, fast on every re-run, and honest about exactly which data a design decision rested on. It is the natural bridge back to the file, spreadsheet and document tools of this module: the web becomes just another source feeding the same dependable pipelines.

Tools & terms in this lesson

API

A program's menu of requests

Application Programming Interface: one program asks another for data in a code-friendly form. Web APIs speak HTTP; read the docs to learn the menu.

requests.get

Send an HTTP GET, get a response

The core call. Pass params as a dict; set timeout; check with raise_for_status(); parse the body with .json().

JSON

The response data format

Nested objects and arrays that map directly to Python dicts and lists. r.json() parses it; then index as usual, defensively with .get().

Status code / rate limit

How it went / how often you may ask

200 OK, 404 not found, 429 too many requests. Respect the cap, sleep between calls, cache reused results, keep keys secret.

Hands-on workshop

Workshop — the site climate fetcher

Build a script that takes a place name, geocodes it to coordinates, then fetches the current weather there - a real two-request pipeline using key-free public APIs, with proper timeout, error handling and defensive JSON reading.

Python 3, `pip install requests`, an internet connection. No API key needed (Open-Meteo is key-free); optionally register a key elsewhere to practise reading it from an environment variable.

Given & goal
Goal: place name -> coordinates -> current weather, live
Inputs: a city or site name as a string
Time: ~45 minutes
  1. 1Install and smoke-test: pip install requests, then GET the Open-Meteo geocoding URL for a known city with params={"name": city, "count": 1} and print(r.status_code) and r.json() to see the response shape.
  2. 2Parse defensively: read r.json().get("results", []), handle the empty case with a clear message, and on success pull latitude and longitude from the first result.
  3. 3Chain the weather call: pass those coordinates as latitude/longitude params to the Open-Meteo forecast URL requesting current=temperature_2m, and read the temperature out of the returned JSON.
  4. 4Make it robust: add timeout=10 to both calls and wrap each in try / except requests.RequestException so a network hiccup prints a friendly message instead of a traceback.
  5. 5Be a good guest: wrap the whole thing in a function site_weather(name), loop it over a list of cities with a time.sleep(1) between iterations, and (bonus) cache each result to a JSON file so a repeat run makes no new requests.

You’ll walk away with
A `site_weather(name)` function that reliably turns a place name into its current temperature via two chained public APIs - with timeouts, error handling, defensive JSON parsing and polite rate-limiting - runnable over a list of sites.

The worked example

Three altitudes on the same idea

Read the band that fits you — or all three.

For the architectAutomate busywork & build custom tools

Climate-responsive design runs on live and historical environmental data. Geocode a site, pull weather normals, temperature and humidity ranges, or sun positions, and feed them straight into a shading study or a passive-design spreadsheet - no manual copying, always current. The same requests-and-JSON pattern reaches elevation, air-quality and mapping services, so site analysis that meant hunting across websites becomes one reproducible script you re-run for every project.

For the interior designerScripts for data, schedules & layouts

Product and material data increasingly lives behind APIs. Where a supplier or catalogue offers one, you can pull current prices, specifications and availability into a schedule automatically rather than transcribing PDFs. Even public APIs help - daylight hours and seasonal weather to inform a lighting or textile scheme for a specific city. The skill is the same GET-and-read-JSON loop; only the URL and the fields change.

For the studentA hireable computational skill

APIs are how modern computational and data projects get real inputs. A studio brief, a thesis map, a climate analysis or a generative piece driven by live data all start with a request and a JSON response. Learning requests now means your projects can use current, real-world data instead of invented numbers - and API literacy is an expected skill in the computational-design and data roles this Academy's other courses lead toward.

Misconception check

Using an API means writing complicated networking code and understanding servers and HTTP deeply.

For the everyday case - reading data with a GET request - it is genuinely a few lines, and requests hides the hard parts. You do not implement HTTP, manage sockets, or run a server; you call requests.get(url, params=...), check it succeeded, and read r.json() as a dictionary. The real work is not networking but two ordinary skills you already have: reading the API's documentation to learn its URL, parameters and the shape of its JSON, and then indexing that JSON like any nested dict and list. Authentication adds a key, and politeness adds a timeout, error handling and respect for rate limits - all small. What is genuinely advanced (building your own API, streaming, complex auth flows) is a different, later topic. Reading public data is beginner-friendly.
Try it

Do it yourself

Reason about the request and response before running.

  1. 1In one sentence, what is an API, and what does a GET request do?
  2. 2Why pass parameters as a dictionary to requests.get rather than building the URL string yourself?
  3. 3What does r.raise_for_status() do, and why is it worth calling?
  4. 4A response is JSON like {"results": [{"latitude": 26.9}]} - how do you read the latitude, and how do you guard against an empty results?
  5. 5What does a 429 status code mean, and name two ways to be a polite API client.
Take this with you

The one line to carry out

An API lets your script ask a server for data; with requests you send a GET, check it, and read the JSON as a Python dictionary - then index it like any nested dict, defensively. The real work is reading the docs and being a polite guest, not networking.
Take it further
References & further reading

Peer-reviewed journals & authoritative standards

  1. 01Requests: HTTP for Humansrequests documentation, 2026.
  2. 02Application programming interfaceWikipedia, 2026.
  3. 03JSONWikipedia, 2026.
  4. 04json - JSON encoder and decoderPython documentation, 2026.
  5. 05Web scrapingWikipedia, 2026.
Related lessons
Recap
APIs let one program ask another for data in a code-friendly form. A web API answers a GET request at a URL, refined by parameters, with a status code and a JSON body. The requests library makes this a few lines: get(url, params=..., timeout=...), raise_for_status(), then r.json() parsed into dicts and lists you index defensively. Handle keys secretly, respect rate limits, cache reused data, and prefer an API to scraping.
Carry forward →

That completes the everyday toolkit - files, media, documents and now live web data, all automated. Module 9 turns from automating chores to _generating_ design: randomness and noise, recursion and L-systems, algorithms for form, and optimization loops, where code becomes a design instrument in its own right.

A

The author

Amogh N P

Architect, interior designer, and creative polymath. Studio Matrx began in his notebooks — his vision of design made honest, useful, and open to everyone. Its Academy is written and taught in his memory, and free, forever.

More about Amogh →