JSON (JavaScript Object Notation) is the most popular data format for REST APIs. Whether you're building a new API or consuming an existing one, understanding how to work with JSON is essential for modern web development.
This comprehensive tutorial covers both sides: building JSON APIs (with Node.js, Python, and C# examples) and consuming JSON APIs (making requests and handling responses). You can also use our JSON Formatter and JSON Validator to work with API responses.
Related: Want to learn about the JSON:API specification? See our What is JSON:API guide.
What is a JSON API?
A JSON API is simply an API (Application Programming Interface) that uses JSON as its data format for requests and responses. Most modern REST APIs use JSON because it's:
Building JSON APIs
Let's create a simple JSON API in three popular languages. Each example creates an endpoint that returns user data.
Example 1: Node.js with Express
// Install: npm install express
const express = require('express');
const app = express();
// Middleware to parse JSON
app.use(express.json());
// Sample data
const users = [
{ id: 1, name: "Alice", email: "[email protected]" },
{ id: 2, name: "Bob", email: "[email protected]" }
];
// GET - Retrieve all users
app.get('/api/users', (req, res) => {
res.json({
success: true,
data: users
});
});
// GET - Retrieve single user
app.get('/api/users/:id', (req, res) => {
const user = users.find(u => u.id === parseInt(req.params.id));
if (!user) {
return res.status(404).json({
success: false,
error: "User not found"
});
}
res.json({
success: true,
data: user
});
});
// POST - Create new user
app.post('/api/users', (req, res) => {
const newUser = {
id: users.length + 1,
name: req.body.name,
email: req.body.email
};
users.push(newUser);
res.status(201).json({
success: true,
data: newUser
});
});
app.listen(3000, () => {
console.log('API running on http://localhost:3000');
});Express.js makes it easy to build JSON APIs with built-in JSON parsing. Learn more at expressjs.com.
Example 2: Python with Flask
# Install: pip install flask
from flask import Flask, jsonify, request
app = Flask(__name__)
# Sample data
users = [
{"id": 1, "name": "Alice", "email": "[email protected]"},
{"id": 2, "name": "Bob", "email": "[email protected]"}
]
# GET - Retrieve all users
@app.route('/api/users', methods=['GET'])
def get_users():
return jsonify({
"success": True,
"data": users
})
# GET - Retrieve single user
@app.route('/api/users/<int:user_id>', methods=['GET'])
def get_user(user_id):
user = next((u for u in users if u["id"] == user_id), None)
if not user:
return jsonify({
"success": False,
"error": "User not found"
}), 404
return jsonify({
"success": True,
"data": user
})
# POST - Create new user
@app.route('/api/users', methods=['POST'])
def create_user():
data = request.get_json()
new_user = {
"id": len(users) + 1,
"name": data.get("name"),
"email": data.get("email")
}
users.append(new_user)
return jsonify({
"success": True,
"data": new_user
}), 201
if __name__ == '__main__':
app.run(debug=True, port=3000)Flask's jsonify() automatically converts Python dictionaries to JSON. For more Python JSON handling, see our Python JSON Parser guide.
Example 3: C# with ASP.NET Core
// UserController.cs
using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;
using System.Linq;
[ApiController]
[Route("api/[controller]")]
public class UsersController : ControllerBase
{
private static List<User> users = new List<User>
{
new User { Id = 1, Name = "Alice", Email = "[email protected]" },
new User { Id = 2, Name = "Bob", Email = "[email protected]" }
};
// GET api/users
[HttpGet]
public IActionResult GetUsers()
{
return Ok(new
{
Success = true,
Data = users
});
}
// GET api/users/1
[HttpGet("{id}")]
public IActionResult GetUser(int id)
{
var user = users.FirstOrDefault(u => u.Id == id);
if (user == null)
{
return NotFound(new
{
Success = false,
Error = "User not found"
});
}
return Ok(new
{
Success = true,
Data = user
});
}
// POST api/users
[HttpPost]
public IActionResult CreateUser([FromBody] User newUser)
{
newUser.Id = users.Count + 1;
users.Add(newUser);
return CreatedAtAction(nameof(GetUser), new { id = newUser.Id }, new
{
Success = true,
Data = newUser
});
}
}
public class User
{
public int Id { get; set; }
public string Name { get; set; }
public string Email { get; set; }
}ASP.NET Core automatically serializes objects to JSON. For more C# JSON handling, see our Newtonsoft.Json tutorial.
Consuming JSON APIs
Now let's look at how to make requests to JSON APIs and handle the responses in different languages.
JavaScript - Using Fetch API
// GET request
async function getUsers() {
try {
const response = await fetch('https://api.example.com/users');
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
console.log(data);
return data;
} catch (error) {
console.error('Error fetching users:', error);
}
}
// POST request
async function createUser(userData) {
try {
const response = await fetch('https://api.example.com/users', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(userData)
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
console.log('User created:', data);
return data;
} catch (error) {
console.error('Error creating user:', error);
}
}
// Usage
getUsers();
createUser({ name: "Charlie", email: "[email protected]" });The Fetch API is built into modern browsers. Learn more at MDN Web Docs.
JavaScript - Using Axios
// Install: npm install axios
const axios = require('axios');
// GET request
async function getUsers() {
try {
const response = await axios.get('https://api.example.com/users');
console.log(response.data);
return response.data;
} catch (error) {
console.error('Error:', error.response ? error.response.data : error.message);
}
}
// POST request
async function createUser(userData) {
try {
const response = await axios.post('https://api.example.com/users', userData);
console.log('User created:', response.data);
return response.data;
} catch (error) {
console.error('Error:', error.response ? error.response.data : error.message);
}
}
// With authentication
const api = axios.create({
baseURL: 'https://api.example.com',
headers: {
'Authorization': 'Bearer YOUR_TOKEN_HERE'
}
});
// Usage
getUsers();
createUser({ name: "Charlie", email: "[email protected]" });Axios automatically parses JSON and provides better error handling. Learn more at axios-http.com.
Python - Using Requests Library
# Install: pip install requests
import requests
import json
# GET request
def get_users():
try:
response = requests.get('https://api.example.com/users')
response.raise_for_status() # Raise exception for bad status codes
data = response.json()
print(data)
return data
except requests.exceptions.RequestException as e:
print(f'Error: {e}')
# POST request
def create_user(user_data):
try:
response = requests.post(
'https://api.example.com/users',
json=user_data # Automatically serializes to JSON
)
response.raise_for_status()
data = response.json()
print('User created:', data)
return data
except requests.exceptions.RequestException as e:
print(f'Error: {e}')
# With authentication
headers = {
'Authorization': 'Bearer YOUR_TOKEN_HERE'
}
response = requests.get('https://api.example.com/users', headers=headers)
# Usage
get_users()
create_user({'name': 'Charlie', 'email': '[email protected]'})Python's requests library makes HTTP simple. See our Python JSON to Dict guide for parsing responses.
C# - Using HttpClient
using System;
using System.Net.Http;
using System.Net.Http.Json;
using System.Threading.Tasks;
public class ApiClient
{
private static readonly HttpClient client = new HttpClient();
// GET request
public static async Task GetUsers()
{
try
{
var response = await client.GetAsync("https://api.example.com/users");
response.EnsureSuccessStatusCode();
var data = await response.Content.ReadAsStringAsync();
Console.WriteLine(data);
// Or deserialize to object
// var users = await response.Content.ReadFromJsonAsync<List<User>>();
}
catch (HttpRequestException e)
{
Console.WriteLine($"Error: {e.Message}");
}
}
// POST request
public static async Task CreateUser(User newUser)
{
try
{
var response = await client.PostAsJsonAsync("https://api.example.com/users", newUser);
response.EnsureSuccessStatusCode();
var createdUser = await response.Content.ReadFromJsonAsync<User>();
Console.WriteLine($"User created: {createdUser.Name}");
}
catch (HttpRequestException e)
{
Console.WriteLine($"Error: {e.Message}");
}
}
// With authentication
public static void SetAuthToken(string token)
{
client.DefaultRequestHeaders.Authorization =
new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token);
}
}
// Usage
await ApiClient.GetUsers();
await ApiClient.CreateUser(new User { Name = "Charlie", Email = "[email protected]" });HttpClient is the recommended way to make HTTP requests in .NET. Learn more at Microsoft Docs.
API Authentication
Most production APIs require authentication. Here are common patterns:
Bearer Token (Most Common)
// JavaScript
fetch('https://api.example.com/users', {
headers: {
'Authorization': 'Bearer YOUR_TOKEN_HERE'
}
})
// Python
headers = {'Authorization': 'Bearer YOUR_TOKEN_HERE'}
requests.get('https://api.example.com/users', headers=headers)
// C#
client.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", "YOUR_TOKEN_HERE");API Key in Header
// JavaScript
fetch('https://api.example.com/users', {
headers: {
'X-API-Key': 'YOUR_API_KEY'
}
})
// Python
headers = {'X-API-Key': 'YOUR_API_KEY'}
requests.get('https://api.example.com/users', headers=headers)API Key in Query Parameter
// JavaScript
fetch('https://api.example.com/users?api_key=YOUR_API_KEY')
// Python
requests.get('https://api.example.com/users', params={'api_key': 'YOUR_API_KEY'})⚠️ Less secure as the key is visible in URLs and logs.
Error Handling Best Practices
Always handle errors properly when working with APIs:
Comprehensive Error Handling Example (JavaScript)
async function fetchWithErrorHandling(url) {
try {
const response = await fetch(url);
// Handle HTTP errors
if (!response.ok) {
const errorData = await response.json();
switch (response.status) {
case 400:
throw new Error('Bad Request: ' + errorData.message);
case 401:
throw new Error('Unauthorized: Please login');
case 403:
throw new Error('Forbidden: Access denied');
case 404:
throw new Error('Not Found: Resource does not exist');
case 500:
throw new Error('Server Error: Please try again later');
default:
throw new Error(`HTTP ${response.status}: ${errorData.message}`);
}
}
const data = await response.json();
return { success: true, data };
} catch (error) {
// Handle network errors
if (error instanceof TypeError) {
return { success: false, error: 'Network error: Please check your connection' };
}
// Handle JSON parsing errors
if (error instanceof SyntaxError) {
return { success: false, error: 'Invalid JSON response' };
}
// Handle other errors
return { success: false, error: error.message };
}
}
// Usage
const result = await fetchWithErrorHandling('https://api.example.com/users');
if (result.success) {
console.log('Data:', result.data);
} else {
console.error('Error:', result.error);
}Common JSON API Patterns
Pagination
// Request
GET /api/users?page=2&limit=20
// Response
{
"data": [...],
"pagination": {
"page": 2,
"limit": 20,
"total": 100,
"totalPages": 5,
"hasNext": true,
"hasPrevious": true
}
}Filtering
// Request
GET /api/products?category=electronics&price_max=500&in_stock=true
// Response
{
"data": [
{
"id": 1,
"name": "Laptop",
"category": "electronics",
"price": 450,
"inStock": true
}
],
"filters": {
"category": "electronics",
"priceMax": 500,
"inStock": true
}
}Success Response Pattern
{
"success": true,
"data": {
"id": 1,
"name": "Alice"
},
"message": "User retrieved successfully",
"timestamp": "2025-01-16T14:30:00Z"
}Error Response Pattern
{
"success": false,
"error": {
"code": "VALIDATION_ERROR",
"message": "Invalid input data",
"details": [
{
"field": "email",
"message": "Email format is invalid"
}
]
},
"timestamp": "2025-01-16T14:30:00Z"
}JSON API Best Practices
/api/v1/ for backwards compatibilityHelpful Tools
Learn More
Summary
Working with JSON APIs is a fundamental skill for modern developers. Whether you're building or consuming APIs, understanding the patterns, best practices, and common pitfalls will make your work more efficient and reliable.
- •JSON is the standard format for modern REST APIs
- •Every major language has excellent tools for working with JSON APIs
- •Always handle errors, validate input, and use proper authentication
- •Follow REST conventions and return appropriate HTTP status codes
- •Document your API and use consistent patterns
Related Guides: Check out our Python JSON Parser, C# Newtonsoft.Json tutorial, and JSON:API specification guide.