Part One
The Waiter Analogy
Imagine you are sitting in a restaurant. You don't walk into the kitchen to get your food. Instead, you tell the waiter what you want — the waiter goes to the kitchen, the kitchen prepares the meal, and the waiter brings it back to your table.
An API works exactly the same way. Your program is the customer. The API is the waiter. The server or database is the kitchen. You ask for something specific, the kitchen prepares the answer, and the waiter delivers it — in a format your program can read.
API stands for Application Programming Interface. The word "interface" is the important one. It is a defined contract: you ask in a specific way, and you always get the answer in a specific, predictable format. You never have to know what is happening inside the kitchen.
Part Two
Anatomy of an API Request
An API request is just a URL. You visit it with your browser — or your Python program — and the server responds with data. Let's look at a real one.
Diavgeia is the Greek government's online transparency registry. Every official government decision — contracts, appointments, spending — must be published there by law. Diavgeia provides a public API so that anyone can query this data programmatically, without an account and without any special permission.
A search request to the Diavgeia API looks like this:
https://diavgeia.gov.gr/luminapi/api/search?q=subject:"κλιματισμός"&size=5
Let's break it into its parts:
| Part | Example | What it means |
|---|---|---|
| Base URL | https://diavgeia.gov.gr/luminapi/api/ |
The address of the API server |
| Endpoint | search |
The specific action you are requesting — here, a search |
| ? | ? |
Separates the endpoint from the parameters |
| Parameter | q=subject:"κλιματισμός" |
The search query — Diavgeia expects a field name (subject) followed by the search term in quotes |
| & | & |
Separates multiple parameters |
| Parameter | size=5 |
How many results to return |
You can think of the endpoint as the waiter's notepad category ("I'd like something from the seafood section"), and the parameters as your specific order ("grilled, medium, no lemon").
subject:"κλιματισμός" searches the decision title. q:"κλιματισμός" does a general full-text search. ada:"6ΛΩΖ7ΛΞ-ΦΨΥ" looks up a specific decision by its unique code. You will see all three patterns used in practice.
https://diavgeia.gov.gr/luminapi/api/search?q=subject:"κλιματισμός"&size=3 into a new tab. You will see the raw response — a wall of structured text called JSON.
Part Three
The Response — JSON
When the API server answers, it doesn't send HTML. It sends a structured text format called JSON — JavaScript Object Notation. Despite the name, JSON is language-agnostic: Python, JavaScript, R, and most other programming languages can read it natively.
Here is a small, realistic piece of what the Diavgeia API returns for a search request:
{
"info": {
"total": 1842
},
"decisions": [
{
"ada": "ΨΦΔΔ46ΜΤΛΡ-ΑΩΣ",
"subject": "Ανάληψη υποχρέωσης για την προμήθεια κλιματιστικών μονάδων",
"issueDate": "2025-06-10",
"submissionTimestamp": "2025-06-11T09:15:00.000+0300",
"documentUrl": "https://diavgeia.gov.gr/doc/ΨΦΔΔ46ΜΤΛΡ-ΑΩΣ",
"documentType": "pdf",
"organization": {
"label": "ΔΗΜΟΣ ΑΘΗΝΑΙΩΝ"
},
"decisionType": {
"label": "Ανάληψη Υποχρέωσης"
}
}
]
}
This might look unfamiliar at first, but you already know most of the patterns. JSON is built from two structures:
| JSON structure | Python equivalent | How to recognise it |
|---|---|---|
| Object | dict |
Curly braces { } with "key": value pairs |
| Array | list |
Square brackets [ ] with comma-separated values |
| String | str |
Always double-quoted: "like this" |
| Number | int / float |
No quotes: 1842, 14500.00 |
| Boolean | bool |
true / false (lowercase in JSON) |
| Null | None |
null |
When Python reads JSON, it converts each of those structures automatically to the Python equivalent. A JSON object becomes a dict. A JSON array becomes a list. A JSON string becomes a str. You don't have to do anything special — Python handles the conversion for you.
Part Four
Reading JSON with Python
Python's built-in json module converts a JSON string into a Python object with a single function call: json.loads(). The s in loads stands for "string" — you are loading from a string.
The JSON string becomes a Python dictionary. You access its values exactly as you would any other dict — with square brackets and the key name.
Now let's try a more realistic response — the kind Diavgeia actually returns, with a nested structure and a list of decisions:
Notice two things about that code. First, data["info"]["total"] — you chain square brackets to navigate into nested objects. The same works for decision["organization"]["label"]: organization is itself a dict with a label key inside it. Second, data["decisions"] is a Python list, so you can loop over it with for exactly as you would any other list.
json.loads() parses a string. json.load() (no s) reads from a file object. You will use loads() when you get the response from an API, and load() if you ever open a saved .json file from disk.
Part Five
Your Turn — Navigate the Response
The cell below contains a Diavgeia-style response with three decisions. Your task: loop through them and print the ADA code, the organisation name, and the decision type label for each one. The organisation name and decision type label are nested one level deep — use the bracket-chaining technique you just saw.
json.loads() and turns into familiar dictionaries and lists. In the next chapter you will send a real request to the Diavgeia API using Python's requests library.
Chapter Navigation
Move between chapters.