APIs: What They Are and Why They Exist

Why This Matters (It’s Everywhere)

Here’s the thing: every time you check the weather on your phone, post to social media, or pay for something online, you’re using an API. When you write import requests in Python or import java.net.http.* in Java, you’re using an API. When your React app talks to your backend server, that’s an API too.

APIs are the glue that holds modern software together. Understanding them isn’t optional—it’s fundamental. I’ve seen junior developers get completely stuck because they didn’t understand the difference between “calling an API” and “making a web request” (spoiler: they’re often the same thing). Once you get this concept, entire categories of programming suddenly make sense.

What Is an API, Really?

API stands for Application Programming Interface. Let me break that down in plain English:

  • Application - a program or service
  • Programming - you interact with it through code
  • Interface - a set of rules for how to interact

An API is basically a contract that says “here’s how you can talk to me and here’s what I’ll give you back.”

Think of it like ordering at a restaurant. You don’t go into the kitchen and cook the food yourself. You look at the menu (the interface), place an order (make a request), and the kitchen sends out your food (the response). You don’t need to know how the kitchen works—you just need to know how to order.

An API is the menu for software.

The Different Types of APIs

Here’s where people get confused: “API” means different things in different contexts. Let me walk you through the main types.

Type 1: Library/Code APIs

When you use functions and classes from a library, you’re using an API.

Python example:

1import random
2
3# random.randint() is part of Python's API
4number = random.randint(1, 100)  # "Give me a random number between 1 and 100"
5
6# random.choice() is another part of the API
7colors = ["red", "blue", "green"]
8color = random.choice(colors)  # "Pick one of these for me"

The random module is the “kitchen.” The functions like randint() and choice() are the “menu items.” You don’t need to know how they generate random numbers—you just need to know how to call them.

Java example:

1import java.util.ArrayList;
2
3// ArrayList's API defines methods like add(), get(), size()
4ArrayList<String> names = new ArrayList<>();
5names.add("Alice");      // "Add this item"
6String first = names.get(0);  // "Give me the item at position 0"
7int count = names.size();     // "How many items do you have?"

The ArrayList class exposes an API—a set of methods you can call. You don’t need to know how it stores data internally. You just need to know the interface.

Type 2: Web APIs (REST APIs, HTTP APIs)

This is what most people mean when they say “API” in modern development. A web API lets your code communicate with a service over the internet using HTTP requests.

Real-world examples:

  • Weather API - “Give me the current weather for New York”
  • Stripe API - “Process this credit card payment”
  • GitHub API - “List all repositories for this user”
  • Google Maps API - “Give me directions from A to B”

You send a request (usually over HTTP), and you get a response (usually JSON or XML).

Python example (calling a weather API):

 1import requests
 2
 3# Make a GET request to a weather API
 4url = "https://api.openweathermap.org/data/2.5/weather"
 5params = {
 6    "q": "New York",
 7    "appid": "your-api-key"
 8}
 9
10response = requests.get(url, params=params)
11data = response.json()  # Parse the JSON response
12
13print(f"Temperature: {data['main']['temp']}")
14print(f"Conditions: {data['weather'][0]['description']}")

You’re asking the OpenWeather API for data, and it sends back JSON that looks like this:

 1{
 2  "main": {
 3    "temp": 72.5,
 4    "humidity": 60
 5  },
 6  "weather": [
 7    {
 8      "description": "clear sky"
 9    }
10  ]
11}

Java example (calling a REST API):

 1import java.net.URI;
 2import java.net.http.HttpClient;
 3import java.net.http.HttpRequest;
 4import java.net.http.HttpResponse;
 5
 6public class WeatherAPI {
 7    public static void main(String[] args) throws Exception {
 8        HttpClient client = HttpClient.newHttpClient();
 9
10        // Build the request
11        HttpRequest request = HttpRequest.newBuilder()
12            .uri(URI.create("https://api.openweathermap.org/data/2.5/weather?q=NewYork&appid=your-api-key"))
13            .GET()
14            .build();
15
16        // Send the request and get the response
17        HttpResponse<String> response = client.send(request,
18            HttpResponse.BodyHandlers.ofString());
19
20        System.out.println("Response: " + response.body());
21    }
22}

Type 3: Your Own APIs

When you build a backend server for your app, you’re creating an API.

Example: A simple REST API you might build

Let’s say you’re building a todo app. Your frontend needs to get, create, and delete todos. You’d create an API like this:

1GET    /api/todos          → Get all todos
2POST   /api/todos          → Create a new todo
3DELETE /api/todos/123      → Delete todo with ID 123

Python backend (Flask):

 1from flask import Flask, jsonify, request
 2
 3app = Flask(__name__)
 4
 5todos = [
 6    {"id": 1, "task": "Learn about APIs", "done": False},
 7    {"id": 2, "task": "Build a project", "done": False}
 8]
 9
10# API endpoint: Get all todos
11@app.route('/api/todos', methods=['GET'])
12def get_todos():
13    return jsonify(todos)
14
15# API endpoint: Create a new todo
16@app.route('/api/todos', methods=['POST'])
17def create_todo():
18    new_todo = request.json
19    todos.append(new_todo)
20    return jsonify(new_todo), 201
21
22# API endpoint: Delete a todo
23@app.route('/api/todos/<int:todo_id>', methods=['DELETE'])
24def delete_todo(todo_id):
25    global todos
26    todos = [t for t in todos if t['id'] != todo_id]
27    return '', 204

Now any client (web browser, mobile app, another server) can interact with your todo data by calling these endpoints.

Java backend (Spring Boot):

 1import org.springframework.web.bind.annotation.*;
 2import java.util.ArrayList;
 3import java.util.List;
 4
 5@RestController
 6@RequestMapping("/api/todos")
 7public class TodoController {
 8
 9    private List<Todo> todos = new ArrayList<>();
10
11    // GET /api/todos - Get all todos
12    @GetMapping
13    public List<Todo> getTodos() {
14        return todos;
15    }
16
17    // POST /api/todos - Create a new todo
18    @PostMapping
19    public Todo createTodo(@RequestBody Todo todo) {
20        todos.add(todo);
21        return todo;
22    }
23
24    // DELETE /api/todos/{id} - Delete a todo
25    @DeleteMapping("/{id}")
26    public void deleteTodo(@PathVariable int id) {
27        todos.removeIf(t -> t.getId() == id);
28    }
29}

Why Do APIs Exist?

APIs solve some fundamental problems in software development. Let me walk you through the big ones.

Reason 1: Separation of Concerns

You don’t want your frontend code to directly access a database. That’s a security nightmare and a maintenance headache. Instead, you create an API layer that sits in between.

1Frontend (React, mobile app)
2    ↓  (makes API calls)
3Backend API (your server)
4    ↓  (queries database)
5Database (PostgreSQL, MongoDB)

Each layer has one job. The frontend handles user interaction. The API handles business logic. The database stores data. Clean separation.

Reason 2: Reusability

Once you build an API, any client can use it—web app, mobile app, desktop app, another server. You write the logic once, and everyone benefits.

Example:

1Your Todo API
23Used by:
4- Web frontend (React)
5- iOS app (Swift)
6- Android app (Kotlin)
7- Command-line tool (Python)

One API, four different clients. No code duplication.

Reason 3: Access to Services You Don’t Want to Build

Why write your own payment processing when Stripe has an API? Why build your own maps when Google Maps has an API? Why create your own email service when SendGrid has an API?

APIs let you leverage other people’s work.

Common third-party APIs:

  • Stripe - payment processing
  • Twilio - SMS and phone calls
  • SendGrid - email delivery
  • Google Maps - maps and directions
  • OpenAI - AI language models
  • GitHub - code repository management

Reason 4: Security and Control

APIs let you control exactly what data people can access and what they can do with it.

Example: API with authentication

 1@app.route('/api/users', methods=['GET'])
 2def get_users():
 3    # Check if request has a valid API key
 4    api_key = request.headers.get('Authorization')
 5
 6    if not is_valid_api_key(api_key):
 7        return jsonify({"error": "Unauthorized"}), 401
 8
 9    # Only return non-sensitive user data
10    users = [{"id": u.id, "name": u.name} for u in get_all_users()]
11    return jsonify(users)

You’re not giving direct database access. You’re giving controlled access through the API.

How Web APIs Work (The Request-Response Cycle)

Let’s break down what actually happens when you call a web API.

Step 1: Client Makes a Request

Your code sends an HTTP request to a URL (endpoint).

1# Python - making a GET request
2response = requests.get('https://api.github.com/users/octocat')
1// Java - making a GET request
2HttpRequest request = HttpRequest.newBuilder()
3    .uri(URI.create("https://api.github.com/users/octocat"))
4    .GET()
5    .build();

Step 2: Server Processes the Request

The server receives your request, runs some code (queries database, does calculations, whatever), and prepares a response.

Step 3: Server Sends a Response

The server sends back data (usually JSON) and a status code.

Status codes you need to know:

  • 200 OK - request succeeded
  • 201 Created - new resource created successfully
  • 400 Bad Request - you sent invalid data
  • 401 Unauthorized - you need to authenticate
  • 404 Not Found - resource doesn’t exist
  • 500 Internal Server Error - server crashed

Step 4: Client Handles the Response

Your code receives the response and does something with it.

1response = requests.get('https://api.github.com/users/octocat')
2
3if response.status_code == 200:
4    data = response.json()
5    print(f"Name: {data['name']}")
6    print(f"Followers: {data['followers']}")
7else:
8    print(f"Error: {response.status_code}")
1HttpResponse<String> response = client.send(request,
2    HttpResponse.BodyHandlers.ofString());
3
4if (response.statusCode() == 200) {
5    System.out.println("Success: " + response.body());
6} else {
7    System.out.println("Error: " + response.statusCode());
8}

REST APIs: The Most Common Pattern

REST (Representational State Transfer) is a style of API design that most modern web APIs follow. Here’s what you need to know:

REST Uses HTTP Methods

  • GET - retrieve data (doesn’t change anything)
  • POST - create new data
  • PUT - update existing data (replace entirely)
  • PATCH - update existing data (partial update)
  • DELETE - delete data

REST Uses Meaningful URLs (Endpoints)

1GET    /api/users           → Get all users
2GET    /api/users/123       → Get user with ID 123
3POST   /api/users           → Create a new user
4PUT    /api/users/123       → Update user 123 (replace)
5PATCH  /api/users/123       → Update user 123 (partial)
6DELETE /api/users/123       → Delete user 123

Notice the pattern? The URL describes the resource (users), and the HTTP method describes the action.

REST Returns JSON (Usually)

Most REST APIs return data in JSON format because it’s easy to parse in any programming language.

1{
2  "id": 123,
3  "name": "Alice",
4  "email": "alice@example.com",
5  "role": "developer"
6}

Common Patterns in API Usage

Pattern 1: Fetch Data and Display It

Python:

1import requests
2
3# Fetch user data from an API
4response = requests.get('https://api.github.com/users/torvalds')
5user = response.json()
6
7print(f"Name: {user['name']}")
8print(f"Company: {user['company']}")
9print(f"Public repos: {user['public_repos']}")

Java:

1HttpResponse<String> response = client.send(request,
2    HttpResponse.BodyHandlers.ofString());
3
4// Parse JSON (using a library like Jackson or Gson)
5ObjectMapper mapper = new ObjectMapper();
6User user = mapper.readValue(response.body(), User.class);
7
8System.out.println("Name: " + user.getName());

Pattern 2: Send Data to Create a Resource

Python:

 1import requests
 2
 3# Create a new todo via API
 4new_todo = {
 5    "task": "Learn about APIs",
 6    "done": False
 7}
 8
 9response = requests.post(
10    'https://api.example.com/todos',
11    json=new_todo,
12    headers={"Authorization": "Bearer your-token"}
13)
14
15if response.status_code == 201:
16    print("Todo created:", response.json())

Java:

 1String jsonData = "{\"task\":\"Learn about APIs\",\"done\":false}";
 2
 3HttpRequest request = HttpRequest.newBuilder()
 4    .uri(URI.create("https://api.example.com/todos"))
 5    .header("Content-Type", "application/json")
 6    .header("Authorization", "Bearer your-token")
 7    .POST(HttpRequest.BodyPublishers.ofString(jsonData))
 8    .build();
 9
10HttpResponse<String> response = client.send(request,
11    HttpResponse.BodyHandlers.ofString());

Pattern 3: Handle Errors Gracefully

Python:

 1try:
 2    response = requests.get('https://api.example.com/data', timeout=5)
 3    response.raise_for_status()  # Raises exception for 4xx/5xx status
 4    data = response.json()
 5except requests.exceptions.Timeout:
 6    print("Request timed out")
 7except requests.exceptions.HTTPError as e:
 8    print(f"HTTP error: {e}")
 9except requests.exceptions.RequestException as e:
10    print(f"Error: {e}")

Java:

 1try {
 2    HttpResponse<String> response = client.send(request,
 3        HttpResponse.BodyHandlers.ofString());
 4
 5    if (response.statusCode() >= 400) {
 6        throw new RuntimeException("HTTP Error: " + response.statusCode());
 7    }
 8
 9    // Process response
10} catch (IOException e) {
11    System.out.println("Network error: " + e.getMessage());
12} catch (InterruptedException e) {
13    System.out.println("Request interrupted: " + e.getMessage());
14}

API Authentication: How to Prove Who You Are

Most real-world APIs require authentication. Here are the common methods:

Method 1: API Keys

You get a secret key and include it in every request.

1headers = {"Authorization": "Bearer sk_test_abc123xyz"}
2response = requests.get('https://api.example.com/data', headers=headers)

Method 2: OAuth Tokens

You authenticate once, get a token, and use it for subsequent requests.

1# Get token (usually from a login flow)
2token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
3
4headers = {"Authorization": f"Bearer {token}"}
5response = requests.get('https://api.example.com/user', headers=headers)

Method 3: Username and Password (Basic Auth)

Least secure, but still used for simple APIs.

1from requests.auth import HTTPBasicAuth
2
3response = requests.get(
4    'https://api.example.com/data',
5    auth=HTTPBasicAuth('username', 'password')
6)

Real-World War Story

Let me tell you about a mistake I made early in my career. I was building a weather app, and I put my API key directly in my JavaScript code:

1// DON'T DO THIS!
2const API_KEY = "sk_live_abc123xyz";
3fetch(`https://api.weather.com/data?key=${API_KEY}`)

I pushed it to GitHub. Within a week, someone found my key, used it to make thousands of API calls, and I got a $500 bill. Ouch.

The lesson: Never put API keys in client-side code or commit them to git. Use environment variables and keep them on the server.

The right way:

1import os
2
3# Read API key from environment variable
4API_KEY = os.getenv('WEATHER_API_KEY')
5
6response = requests.get(
7    'https://api.weather.com/data',
8    params={'key': API_KEY}
9)

What You Need to Remember

Here’s what I wish someone had told me when I was learning this:

  1. An API is an interface for software to talk to software - it’s a contract
  2. Library APIs are functions/classes you call in code - like random.randint()
  3. Web APIs are services you call over HTTP - like weather, payment APIs
  4. REST uses HTTP methods - GET, POST, PUT, DELETE
  5. APIs usually return JSON - easy to parse in any language
  6. Always handle errors - network fails, APIs go down, rate limits hit
  7. Never commit API keys to git - use environment variables
  8. Read the documentation - every API is different, docs tell you how to use it

How This Helps Your Career

Understanding APIs is absolutely critical for modern development:

  • Backend development - you’ll build REST APIs
  • Frontend development - you’ll call APIs to get data
  • Mobile development - apps rely on APIs for everything
  • Data engineering - pulling data from APIs into pipelines
  • DevOps - automating infrastructure with APIs
  • Integration work - connecting different systems via APIs

Every technical interview will ask about APIs. Every job will involve working with them. Whether you’re fetching data from a third-party service, building your own API, or connecting a frontend to a backend, this is foundational knowledge.

Six months from now, when you’re integrating Stripe payments or pulling data from the GitHub API, you’ll immediately understand the request-response flow, how to handle errors, and how to authenticate. You’ll know that an API is just a menu—you order what you want, and the service delivers it.

Trust me, once you build your first API and call a few real-world APIs, this all clicks into place. Start with simple GET requests, then try creating your own REST API with Flask or Spring Boot. You’ll never look at web applications the same way again.

Now go call some APIs and see what you can build!