APIs are not just interfaces; they’re contracts that define how two pieces of software can talk to each other without knowing the messy details of their internal workings.

Imagine you’re at a restaurant. You don’t need to know how the kitchen operates, who’s washing the dishes, or the exact temperature of the oven. You just need to know the menu (the API) and how to order (make a request). The waiter (the API gateway or client) takes your order, relays it to the kitchen (the backend service), and brings back your food (the response).

Let’s see this in action with a simple example using curl to interact with a public API, like the GitHub API to get information about a repository.

curl -s "https://api.github.com/repos/kubernetes/kubernetes"

This command asks the GitHub API for data about the kubernetes/kubernetes repository. The -s flag makes curl silent, so you only see the output. The output is a JSON object containing details like the repository’s name, description, stars, forks, and more.

{
  "id": 60230000,
  "node_id": "MDEwOlJlcG9zaXRvcnk2MDIzMDAwMA==",
  "name": "kubernetes",
  "full_name": "kubernetes/kubernetes",
  "private": false,
  "owner": {
    "login": "kubernetes",
    "id": 13433347,
    "node_id": "ORG_ পাচ...",
    "avatar_url": "https://avatars.githubusercontent.com/u/13433347?v=4",
    "gravatar_id": "",
    "url": "https://api.github.com/users/kubernetes",
    "html_url": "https://github.com/kubernetes",
    "followers_url": "https://api.github.com/users/kubernetes/followers",
    "following_url": "https://api.github.com/users/kubernetes/following{/other_user}",
    "gists_url": "https://api.github.com/users/kubernetes/gists{/gist_id}",
    "starred_url": "https://api.github.com/users/kubernetes/starred{/owner}{/repo}",
    "subscriptions_url": "https://api.github.com/users/kubernetes/subscriptions",
    "organizations_url": "https://api.github.com/users/kubernetes/orgs",
    "repos_url": "https://api.github.com/users/kubernetes/repos",
    "events_url": "https://api.github.com/users/kubernetes/events{/privacy}",
    "received_events_url": "https://api.github.com/users/kubernetes/received_events",
    "type": "Organization",
    "site_admin": false
  },
  "fork": false,
  "url": "https://api.github.com/repos/kubernetes/kubernetes",
  "html_url": "https://github.com/kubernetes/kubernetes",
  "created_at": "2016-06-01T22:37:00Z",
  "updated_at": "2024-07-29T10:00:00Z",
  "pushed_at": "2024-07-29T09:55:00Z",
  "git_url": "git://github.com/kubernetes/kubernetes.git",
  "ssh_url": "git@github.com:kubernetes/kubernetes.git",
  "clone_url": "https://github.com/kubernetes/kubernetes.git",
  "svn_url": "https://github.com/kubernetes/kubernetes",
  "homepage": "https://kubernetes.io/",
  "size": 2300000,
  "stargazers_count": 110000,
  "watchers_count": 110000,
  "language": "Go",
  "has_issues": true,
  "has_projects": true,
  "has_downloads": true,
  "has_wiki": true,
  "has_pages": false,
  "has_discussions": false,
  "forks_count": 30000,
  "mirror_url": null,
  "open_issues_count": 40000,
  "license": {
    "key": "apache-2.0",
    "name": "Apache License 2.0",
    "spdx_id": "Apache-2.0",
    "url": "https://api.github.com/licenses/apache-2.0",
    "node_id": "MDc6TGljZW5zZTI="
  },
  "allow_forking": true,
  "is_template": false,
  "web_commit_signoff_required": false,
  "topics": [
    "cloud-native",
    "container",
    "containers",
    "distro",
    "kubernetes",
    "orchestration",
    "platform",
    "runtime"
  ],
  "visibility": "public",
  "archived": false,
  "disabled": false,
  "open_issues": 40000,
  "subscribers_count": 11000
}

This JSON is the API’s response. It’s structured data that your application can easily parse and use. The beauty of this is that the GitHub API could change its internal implementation tomorrow (e.g., switch from Go to Rust for its backend), but as long as it adheres to the contract defined by the API endpoints, URLs, request formats, and response structures, your application won’t break.

APIs solve the problem of distributed systems needing to interact. Before APIs, integrating different software systems was a monumental task, often requiring custom, tightly coupled code that was brittle and hard to maintain. APIs provide a standardized way for services to communicate, enabling modularity, scalability, and the creation of complex ecosystems where different applications can leverage each other’s functionality. Think of how many apps use Google Maps – they don’t build their own mapping system; they use Google Maps’ API.

The core components of an API interaction are:

  • Endpoints: These are specific URLs that your application sends requests to. For example, https://api.github.com/repos/kubernetes/kubernetes is an endpoint.
  • HTTP Methods: These define the action you want to perform. Common ones are GET (retrieve data), POST (create data), PUT (update data), and DELETE (remove data).
  • Requests: This is the message your application sends to the API. It includes the endpoint, HTTP method, headers (like authentication tokens or content type), and potentially a body (for POST or PUT requests).
  • Responses: This is what the API sends back. It includes a status code (e.g., 200 OK, 404 Not Found, 500 Internal Server Error), headers, and a body containing the requested data, often in JSON or XML format.

When you make a GET request to https://api.github.com/repos/kubernetes/kubernetes, your client (like curl or a web browser) constructs a request. The GitHub API receives this request, identifies the resource you’re asking for (the kubernetes/kubernetes repository), retrieves the relevant data from its databases, formats it as JSON, and sends it back as a response. Your curl command then displays this JSON.

Many developers don’t realize that the Accept header in an HTTP request is crucial for content negotiation. If an API can return data in multiple formats (like JSON and XML), the Accept header tells the server which format the client prefers. For instance, sending Accept: application/json explicitly asks for a JSON response. If this header is omitted or set to */*, the server might default to a format you don’t expect, or it might choose a less efficient one, impacting your application’s performance.

The next step is understanding how to handle API authentication, which is critical for accessing protected resources and securing your applications.

Want structured learning?

Take the full Computer Networking course →