Content Overview

  • What is JSON?
  • JSON Syntax & Examples
  • The Golden Rule of Quotes
  • Common Uses for JSON
  • The `json` Module in Python
  • From JSON String to Python Dictionary (`json.loads()`)
  • Accessing Loaded Data
  • From Python Dictionary to JSON String (`json.dumps()`)
  • Formatting JSON Output (`indent`, `sort_keys`)
  • Working with JSON Files (`json.load()`, `json.dump()`)
  • EE Application Examples (Component Datasheet, Test Automation, IoT Sensor Data)
  • Practice Exercise: Read, Modify, Write JSON File
  • APIs in Detail: The Digital Glue of the Modern World
  • What is an API? (Waiter Analogy)
  • Why Do We Need APIs?
  • How APIs Work: The Request-Response Cycle
  • Anatomy of an API Request
  • Anatomy of an API Response
  • The Language of APIs: JSON
  • Common API Architectures
  • APIs in the Wild (Real-World Examples)
  • API Example 1: Weather API (GET Request)
  • API Example 2: Payment API (POST Request)
  • API Example 3: AI/Generative API (POST Request)

Working with JSON in Python

As Fast As Possible

What is JSON?

  • JSON stands for JavaScript Object Notation.
  • It's a standard, language-independent format for data interchange.
  • The name is historical; it's not tied exclusively to JavaScript.

JSON Syntax

The syntax for JSON is very similar to that of a Python dictionary.

  • Data is in key/value pairs.
  • Data is separated by commas.
  • Curly braces {} hold objects.
  • Square brackets [] hold arrays (lists).

JSON Syntax Example

This is a valid JSON string.

Notice the structure:

  • An outer object {}.
  • A key "students".
  • The value is an array [] of other JSON objects.
{
  "students": [
    {
      "id": 1,
      "name": "Tim",
      "age": 21,
      "full-time": true
    },
    {
      "id": 2,
      "name": "Joe",
      "age": 24,
      "full-time": false
    }
  ]
}

The Golden Rule of Quotes

In JSON, you MUST use double quotation marks (" ") for keys and string values.

Single quotes (' ') are not permitted and will cause an error.

Common Uses for JSON

JSON is widely used for:

  • APIs: Sending and receiving data from web servers.
  • Configuration Files: Storing settings for applications.
  • Data Storage: A simple, human-readable way to store structured data.

The json Module

Python has a built-in library for working with JSON data.

  • It's part of the standard library, so no installation is needed.
  • Simply import it at the top of your script to get started.
# Import the built-in json library
import json

From JSON String to Python Dictionary

You can "load" a JSON string into a Python object (specifically, a dictionary).

The function to use is json.loads().

The "s" in loads stands for "string".

# 's' is for string
json.loads(json_string)

Code: json.loads()

Pass a valid JSON string to json.loads().

The result is a Python dictionary that you can work with directly.

import json

json_string = '{"name": "Tim", "age": 21}'

# Load the string into a Python dictionary
data = json.loads(json_string)

print(data)
# Output: {'name': 'Tim', 'age': 21}

print(type(data))
# Output: <class 'dict'>

Accessing Loaded Data

Once loaded, the data behaves just like a regular Python dictionary or list.

You can use standard key and index lookups to access nested values.

# Assuming 'data' is the loaded object from the
# larger JSON example

# Get the list of students
all_students = data['students']

# Get the first student in the list
first_student = data['students'][0]

# Get the name of the first student
name = data['students'][0]['name']

print(name)
# Output: Tim

From Python Dictionary to JSON String

You can also "dump" a Python dictionary into a JSON formatted string.

The function to use is json.dumps().

Again, the "s" in dumps stands for "string".

# 's' is for string
json.dumps(python_dictionary)

Code: json.dumps()

Pass a Python dictionary to json.dumps() to get a JSON-formatted string as a result.

Note how Python's True boolean becomes JSON's true.

import json

data = {
    'name': 'Joe',
    'age': 24,
    'full-time': True
}

# Dump the dictionary into a JSON string
new_json = json.dumps(data)

print(new_json)
# Output: {"name": "Joe", "age": 24, "full-time": true}

Formatting JSON Output: Indentation

When dumping to a string, the default output is compact and not very readable.

You can use the indent argument to "pretty-print" the JSON, making it much easier for humans to read.

# Use the indent argument
# A value of 2 or 4 is common.
json.dumps(data, indent=4)

Code: indent Example

Using indent=4 adds newlines and 4-space indents to create a nicely formatted string.

new_json = json.dumps(data, indent=4)
print(new_json)

# Output:
# {
#     "name": "Joe",
#     "age": 24,
#     "full-time": true
# }

Formatting JSON Output: Sorting Keys

You can also ensure the keys in your JSON output are in alphabetical order using the sort_keys argument.

This is useful for making JSON output consistent and easier to compare.

new_json = json.dumps(data, indent=4, sort_keys=True)
print(new_json)

# Output:
# {
#     "age": 24,
#     "full-time": true,
#     "name": "Joe"
# }

Working with JSON Files

The json library provides similar functions for reading from and writing to files directly.

  • To read from a file: json.load() (no 's')
  • To write to a file: json.dump() (no 's')

These functions work with file objects, not strings.

Code: Reading from a File

First, open the file in read mode ('r'). Then, pass the file object to json.load().

This is the standard and safest way to handle files in Python.

import json

# Assumes a file named 'data.json' exists
with open('data.json', 'r') as f:
  my_data = json.load(f)

print(my_data)

Writing to a File

To write a Python dictionary to a JSON file, you use json.dump().

  1. Open a file in write mode ('w').
  2. Call json.dump(), passing it two arguments:
    1. The Python object you want to save.
    2. The file object to write to.

Code: Writing to a File

This example takes our `data` dictionary and saves it to a new file named `data2.json`.

The formatting arguments like indent also work with json.dump().

import json

# The dictionary we want to save
data = {
    'name': 'Joe',
    'age': 24,
    'full-time': True
}

with open('data2.json', 'w') as f:
  json.dump(data, f, indent=4)

# A file named 'data2.json' is now created
# with the formatted JSON content.

EE Application 1: Component Datasheet

JSON is ideal for creating a digital library or a Bill of Materials (BOM) by storing electronic component specifications in a structured way.

This allows for easy parsing, searching, and integration with design or simulation software.

# Python dictionary representing a microcontroller
atmega328p = {
  "part_number": "ATMEGA328P-PU",
  "manufacturer": "Microchip",
  "category": "Microcontroller",
  "package": "PDIP-28",
  "specs": {
    "flash_memory_kb": 32,
    "ram_kb": 2,
    "pins": 28,
    "operating_voltage": "1.8V - 5.5V"
  }
}

# Convert to a readable JSON string for a database
component_json = json.dumps(atmega328p, indent=4)
print(component_json)

EE Application 2: Test Automation

In automated testing, JSON is used to define test configurations and log results from instruments like oscilloscopes or power supplies.

This creates a clear, machine-readable record of every test run.

# Python dictionary of test results for a power amplifier
test_results = {
  "test_id": "PA-GAIN-SWEEP-001",
  "timestamp": "2023-10-27T14:30:15Z",
  "device_under_test": "RF-AMP-78B",
  "measurements": [
    {"frequency_mhz": 100, "gain_db": 10.2, "status": "PASS"},
    {"frequency_mhz": 500, "gain_db": 9.8, "status": "PASS"},
    {"frequency_mhz": 900, "gain_db": 8.5, "status": "FAIL"}
  ]
}

# Dump results to a log file
with open('test_run_001.json', 'w') as log_file:
    json.dump(test_results, log_file, indent=2)

EE Application 3: IoT Device Communication

IoT devices, like environmental sensors, send data to servers using JSON. It is lightweight, making it efficient for network transmission (e.g., over MQTT or HTTP).

import datetime

# Data from a hypothetical weather sensor node
sensor_payload = {
  "device_id": "WEATHER-STN-04",
  "timestamp": datetime.datetime.now().isoformat(),
  "location": {
      "lat": 34.0522,
      "lon": -118.2437
  },
  "sensor_readings": {
      "temperature_c": 22.5,
      "humidity_rh": 55.2,
      "pressure_hpa": 1012.5
  }
}

# Convert to a compact JSON string for network sending
json_payload = json.dumps(sensor_payload)
print(json_payload)

Practice Exercise: Setup

Let's put your knowledge to the test!

  1. Create a new file in the same directory as your Python script.
  2. Name the file pcb_design.json.
  3. Copy the JSON content from the right panel and paste it into your new file.

This file represents basic metadata for a Printed Circuit Board design.

{
  "project_name": "Audio Amplifier v1",
  "version": 1.0,
  "designer": "Alex Ray",
  "is_finalized": false,
  "dimensions_mm": {
    "width": 100,
    "height": 75
  },
  "layers": 2,
  "components": [
    {
      "designator": "U1",
      "part_number": "LM386",
      "description": "Low Voltage Audio Power Amplifier"
    },
    {
      "designator": "C1",
      "part_number": "CAP-ELEC-100uF",
      "description": "100uF Electrolytic Capacitor"
    },
    {
      "designator": "R1",
      "part_number": "RES-10K-OHM",
      "description": "10k Ohm Resistor"
    }
  ]
}

Practice Challenge: Read, Modify, Write

Write a Python script that performs the following steps:

Part 1: Read and Access Data

  1. Open and read the pcb_design.json file.
  2. Load the data into a Python dictionary.
  3. Print the Project Name and the Designer's Name.
  4. Print the part number of the component with the designator "C1".

Part 2: Modify and Write Data

  1. Update the version to 1.1.
  2. Change the is_finalized status to True.
  3. Add a new component (a 1k Ohm resistor, R2) to the end of the components list.
  4. Write the entire modified dictionary to a new file called pcb_design_v2.json. Make sure the output is nicely formatted with an indent of 4.

APIs in Detail

The Digital Glue of the Modern World

What is an API?

API stands for Application Programming Interface. At its core, an API is a set of rules, definitions, and protocols that allow different software applications to communicate with each other.

Think of it as a waiter in a restaurant:

  • You (the Client) look at the menu (the API documentation) to see what you can order.
  • You give your order (a Request) to the waiter (the API).
  • The waiter takes your order to the kitchen (the Server), which prepares the food.
  • The waiter brings the food (the Response) back to your table.

The API is the intermediary that lets you get what you need from the server without having to know how the kitchen works.

Why Do We Need APIs?

APIs solve fundamental challenges in software development by enabling interoperability and efficiency.

  • Modularity: Developers don't have to build everything from scratch. A travel app can use a weather API, a maps API, and a payment API instead of building those systems itself.
  • Security: An API exposes only the necessary data and functionality. It acts as a gatekeeper, protecting the application's sensitive internal database and logic from the outside world.
  • Specialization: Companies can focus on what they do best. Stripe focuses on payments; Google focuses on maps. They provide APIs so others can leverage their expertise.
  • Abstraction: It hides complexity. When you use an API to process a credit card payment, you don't need to understand the intricate details of banking networks.

How APIs Work: The Request-Response Cycle

API communication follows a standard client-server model based on a request and a response.

  1. Client Initiates a Request: An application (the "client") needs data or wants to perform an action. It constructs a request and sends it to a specific URL called an endpoint.
  2. Request Reaches the Server: The server hosting the API receives and parses the request.
  3. Server Processes the Request: The server performs the requested operation—retrieving data from a database, creating a new user, deleting a file, etc.
  4. Server Sends a Response: Once processing is complete, the server sends a response back to the client. This response contains the requested data (if any) and a status code indicating success or failure.

Anatomy of an API Request

A typical web API request (over HTTP) is made up of several key parts:

  • Endpoint (URL): The specific "address" where the request is sent. Example: `https://api.example.com/v1/users`
  • HTTP Method (Verb): The action the client wants to perform. The most common are:
    • GET: Retrieve data.
    • POST: Create new data.
    • PUT / PATCH: Update existing data.
    • DELETE: Remove data.
  • Headers: Metadata about the request, such as the data format (`Content-Type`) and authentication credentials (e.g., an API Key or Token).
  • Body (Payload): The actual data being sent to the server, typically used with POST or PUT requests. Usually formatted in JSON.

Anatomy of an API Response

After processing a request, the server sends back a response with the following components:

  • Status Code: A 3-digit number indicating the result of the request.
    • 2xx (e.g., 200 OK): Success! The request was completed.
    • 4xx (e.g., 404 Not Found): Client Error. Something was wrong with the request (bad URL, missing authentication).
    • 5xx (e.g., 500 Internal Server Error): Server Error. Something went wrong on the server's end.
  • Headers: Metadata about the response, such as the data format of the body (`Content-Type: application/json`).
  • Body (Payload): The data requested by the client, most commonly formatted as JSON.

The Language of APIs: JSON

JSON (JavaScript Object Notation) is the most common data format for APIs. It is lightweight, text-based, and easy for both humans and machines to read and write.

It represents data as a collection of key-value pairs, similar to a Python dictionary.

{
  "user": {
    "id": 123,
    "username": "api_user",
    "email": "user@example.com",
    "isActive": true,
    "roles": [
      "editor",
      "contributor"
    ]
  }
}

Common API Architectures

While the concept is universal, APIs can be designed using different architectural styles.

  • REST (Representational State Transfer): The most popular style for web APIs. It's a set of architectural constraints (not a strict protocol) that uses standard HTTP methods (GET, POST, etc.) and is stateless (each request is independent).
  • SOAP (Simple Object Access Protocol): An older, more rigid protocol-based standard that relies heavily on XML. It's known for being highly structured and secure, often used in enterprise environments.
  • GraphQL: A newer query language for APIs developed by Facebook. It gives clients the power to ask for exactly what they need and nothing more, preventing the over-fetching of data common in REST APIs.
  • gRPC (Google Remote Procedure Call): A high-performance framework for building APIs, often used for communication between microservices.

APIs in the Wild

You interact with APIs every day, often without realizing it.

  • "Log in with Google/Facebook": When a website lets you log in with your social media account, it's using that platform's authentication API to verify your identity securely.
  • Online Shopping: When you complete a purchase on an e-commerce site, the site uses a payment gateway's API (like Stripe or PayPal) to process your credit card information.
  • Travel Aggregators: A site like Expedia or Kayak uses APIs from dozens of different airlines and hotels to fetch flight and room availability and prices in real-time.
  • Weather Apps: Your phone's weather app doesn't have its own weather station; it calls a weather service's API (like OpenWeatherMap) to get the latest forecast data for your location.

Example 1: Weather API (GET)

This API retrieves current weather data for a specified location. The client sends a GET request with the city name and an API key as parameters in the URL.

The server responds with a JSON object containing the requested weather information.

Example Response (JSON):

{'location': {'name': 'Auckland',
  'region': '',
  'country': 'New Zealand',
  'lat': -36.8667,
  'lon': 174.7667,
  'tz_id': 'Pacific/Auckland',
  'localtime_epoch': 1756313420,
  'localtime': '2025-08-28 04:50'},
 'current': {'last_updated_epoch': 1756313100,
  'last_updated': '2025-08-28 04:45',
  'temp_c': 8.4,
  'temp_f': 47.1,
  'is_day': 0, ...}
# Using Python's 'requests' library
import requests
import json

# --- 1. The Request ---
API_KEY = "your_actual_api_key"
city = "London"
url = f"http://api.weatherapi.com/v1/current.json?key={API_KEY}&q={city}&aqi=no"


response = requests.get(url)

# --- 2. The Response ---
if response.status_code == 200:
    data = response.json()
    temp_celsius = data['current']['temp_c']
        
    print(f"Temperature in {city}: {temp_celsius:.2f}°C")
else:
    print(f"Error: {response.status_code}")

Example 2: Payment API (POST)

A payment API like Stripe allows you to process payments securely. Here, we send a POST request to create a "Payment Intent," signaling our intent to collect a payment.

The request body contains details like amount and currency. The API responds with a secure client secret that the frontend uses to complete the payment.

Example Response (JSON):

{
  "id": "pi_3L...",
  "object": "payment_intent",
  "amount": 2000,
  "currency": "usd",
  "status": "requires_payment_method",
  "client_secret": "pi_3L..._secret_5m..."
}
# Using the official Stripe Python library
import stripe

# --- 1. The Request ---
stripe.api_key = "your_secret_stripe_key"

try:
    # Create a PaymentIntent on the server
    intent = stripe.PaymentIntent.create(
        amount=2000,  # Amount in cents ($20.00)
        currency="usd",
        automatic_payment_methods={"enabled": True},
    )
    
    # --- 2. The Response ---
    # Send the client_secret back to the frontend
    print({
        'clientSecret': intent.client_secret
    })

except stripe.error.StripeError as e:
    print(f"Stripe Error: {e}")

Example 3: AI/Generative API (POST)

Generative AI APIs, like OpenAI's DALL-E, create content based on a prompt. The client sends a POST request with a JSON body containing the text prompt and other options (like image size).

The API processes the prompt and responds with a URL pointing to the newly generated image.

Example Response (JSON):

{
  "created": 1686940366,
  "data": [
    {
      "url": "https://oaidalleapiprodscus.blob.core.windows.net/..."
    }
  ]
}
# Using Python's 'requests' library
import requests
import json
import os
import PIL
import io

# --- 1. The Request ---
API_KEY = "your_openai_api_key"
url = "https://api.openai.com/v1/images/generations"

headers = {
    "Authorization": f"Bearer {API_KEY}",
    "Content-Type": "application/json"
}

body = {
    "prompt": "a photo of a happy corgi wearing a cowboy hat",
    "n": 1,
    "size": "1024x1024"
}

response = requests.post(url, headers=headers, json=body)

# --- 2. The Response ---
if response.status_code == 200:
    data = response.json()
    image_url = data['data'][0]['url']
    print(f"Image generated successfully!")
    print(f"URL: {image_url}")

    # Get the image data from the URL
    image_response = requests.get(image_url)
    # Raise an exception if the download failed
    image_response.raise_for_status() 

    # Open the image from the in-memory bytes
    image_bytes = io.BytesIO(image_response.content)
    img = Image.open(image_bytes)

    # Display the image (will open in your default image viewer)
    print("Displaying image...")
    img.show(title="Generated Corgi")

else:
    print(f"Error: {response.status_code}")
    print(response.text)