Ojasa Mirai

Ojasa Mirai

Python

Loading...

Learning Level

🟢 Beginner🔵 Advanced
REST API BasicsHTTP RequestsStatus CodesJSON SerializationError HandlingAPI AuthenticationRate LimitingBuilding APIsWeb Scraping Basics
Python/Apis Json/Building Apis

🏗️ Building APIs — Creating Your Own Web Services

Now that you understand how to consume APIs, let's create your own! Building APIs allows you to expose your application's functionality to other developers. REST APIs using Flask are an excellent way to get started with API development.


🎯 What is an API Server?

An API server is a program that listens for requests and responds with data. It follows the same REST principles you learned about earlier, but now you're on the server side, not the client side.

# This is what you'll be building
from flask import Flask, jsonify

app = Flask(__name__)

@app.route('/api/hello')
def hello():
    return jsonify({'message': 'Hello from my API!'})

# Client requests this:
# GET http://localhost:5000/api/hello
# Client receives: {"message": "Hello from my API!"}

🚀 Getting Started with Flask

Flask is a lightweight web framework perfect for building APIs:

# Installation
pip install flask

Your First API

from flask import Flask

# Create Flask application
app = Flask(__name__)

# Define an endpoint
@app.route('/api/hello', methods=['GET'])
def hello():
    return {'message': 'Hello World'}

# Run the server
if __name__ == '__main__':
    app.run(debug=True, port=5000)

# Visit http://localhost:5000/api/hello in browser or curl:
# curl http://localhost:5000/api/hello
# Response: {"message":"Hello World"}

📍 Creating Endpoints

Endpoints are URLs that clients can request. Each endpoint represents a resource or action.

GET Endpoints - Retrieve Data

from flask import Flask, jsonify

app = Flask(__name__)

# Sample data
users = [
    {'id': 1, 'name': 'Alice', 'email': 'alice@example.com'},
    {'id': 2, 'name': 'Bob', 'email': 'bob@example.com'},
    {'id': 3, 'name': 'Carol', 'email': 'carol@example.com'}
]

# Get all users
@app.route('/api/users', methods=['GET'])
def get_all_users():
    return jsonify(users)

# Get 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({'error': 'User not found'}), 404

    return jsonify(user)

# Get user by email
@app.route('/api/users/search/<email>', methods=['GET'])
def search_user(email):
    user = next((u for u in users if u['email'] == email), None)

    if not user:
        return jsonify({'error': 'User not found'}), 404

    return jsonify(user)

if __name__ == '__main__':
    app.run(debug=True)

# Test with:
# curl http://localhost:5000/api/users
# curl http://localhost:5000/api/users/1
# curl http://localhost:5000/api/users/search/alice@example.com

POST Endpoints - Create Data

from flask import Flask, jsonify, request

app = Flask(__name__)

users = [
    {'id': 1, 'name': 'Alice', 'email': 'alice@example.com'},
]
next_id = 2

# Create new user
@app.route('/api/users', methods=['POST'])
def create_user():
    global next_id

    # Get JSON data from request
    data = request.get_json()

    # Validate required fields
    if not data or 'name' not in data or 'email' not in data:
        return jsonify({'error': 'Missing required fields'}), 400

    # Create new user
    new_user = {
        'id': next_id,
        'name': data['name'],
        'email': data['email']
    }

    users.append(new_user)
    next_id += 1

    # Return created user with 201 status
    return jsonify(new_user), 201

if __name__ == '__main__':
    app.run(debug=True)

# Test with curl:
# curl -X POST http://localhost:5000/api/users \
#   -H "Content-Type: application/json" \
#   -d '{"name": "Dave", "email": "dave@example.com"}'

PUT Endpoints - Update Data

from flask import Flask, jsonify, request

app = Flask(__name__)

users = [
    {'id': 1, 'name': 'Alice', 'email': 'alice@example.com'},
    {'id': 2, 'name': 'Bob', 'email': 'bob@example.com'},
]

# Update entire user
@app.route('/api/users/<int:user_id>', methods=['PUT'])
def update_user(user_id):
    user = next((u for u in users if u['id'] == user_id), None)

    if not user:
        return jsonify({'error': 'User not found'}), 404

    data = request.get_json()

    if not data:
        return jsonify({'error': 'No data provided'}), 400

    # Update fields
    user['name'] = data.get('name', user['name'])
    user['email'] = data.get('email', user['email'])

    return jsonify(user)

if __name__ == '__main__':
    app.run(debug=True)

# Test with:
# curl -X PUT http://localhost:5000/api/users/1 \
#   -H "Content-Type: application/json" \
#   -d '{"name": "Alice Smith", "email": "alice.smith@example.com"}'

DELETE Endpoints - Remove Data

from flask import Flask, jsonify

app = Flask(__name__)

users = [
    {'id': 1, 'name': 'Alice', 'email': 'alice@example.com'},
    {'id': 2, 'name': 'Bob', 'email': 'bob@example.com'},
]

# Delete user
@app.route('/api/users/<int:user_id>', methods=['DELETE'])
def delete_user(user_id):
    global users

    user = next((u for u in users if u['id'] == user_id), None)

    if not user:
        return jsonify({'error': 'User not found'}), 404

    users = [u for u in users if u['id'] != user_id]

    return jsonify({'message': 'User deleted'}), 204

if __name__ == '__main__':
    app.run(debug=True)

# Test with:
# curl -X DELETE http://localhost:5000/api/users/1

🛡️ Complete REST API Example

from flask import Flask, jsonify, request
from typing import List, Dict, Optional

app = Flask(__name__)

# In-memory data store
users: List[Dict] = [
    {'id': 1, 'name': 'Alice', 'email': 'alice@example.com', 'role': 'admin'},
    {'id': 2, 'name': 'Bob', 'email': 'bob@example.com', 'role': 'user'},
]
next_id = 3

# Helper functions
def get_user_by_id(user_id: int) -> Optional[Dict]:
    """Find user by ID"""
    return next((u for u in users if u['id'] == user_id), None)

def validate_user_data(data: Dict) -> tuple[bool, str]:
    """Validate user data"""
    if not data:
        return False, 'No data provided'

    if 'name' not in data or not data['name']:
        return False, 'Name is required'

    if 'email' not in data or not data['email']:
        return False, 'Email is required'

    return True, 'Valid'

# Routes
@app.route('/api/users', methods=['GET'])
def list_users():
    """Get all users"""
    return jsonify(users), 200

@app.route('/api/users/<int:user_id>', methods=['GET'])
def get_user(user_id):
    """Get single user by ID"""
    user = get_user_by_id(user_id)

    if not user:
        return jsonify({'error': 'User not found'}), 404

    return jsonify(user), 200

@app.route('/api/users', methods=['POST'])
def create_user():
    """Create new user"""
    global next_id

    data = request.get_json()
    valid, message = validate_user_data(data)

    if not valid:
        return jsonify({'error': message}), 400

    new_user = {
        'id': next_id,
        'name': data['name'],
        'email': data['email'],
        'role': data.get('role', 'user')
    }

    users.append(new_user)
    next_id += 1

    return jsonify(new_user), 201

@app.route('/api/users/<int:user_id>', methods=['PUT'])
def update_user(user_id):
    """Update user"""
    user = get_user_by_id(user_id)

    if not user:
        return jsonify({'error': 'User not found'}), 404

    data = request.get_json()
    valid, message = validate_user_data(data)

    if not valid:
        return jsonify({'error': message}), 400

    user['name'] = data.get('name', user['name'])
    user['email'] = data.get('email', user['email'])
    user['role'] = data.get('role', user['role'])

    return jsonify(user), 200

@app.route('/api/users/<int:user_id>', methods=['DELETE'])
def delete_user(user_id):
    """Delete user"""
    global users

    user = get_user_by_id(user_id)

    if not user:
        return jsonify({'error': 'User not found'}), 404

    users = [u for u in users if u['id'] != user_id]

    return '', 204

# Error handling
@app.errorhandler(404)
def not_found(error):
    return jsonify({'error': 'Endpoint not found'}), 404

@app.errorhandler(500)
def internal_error(error):
    return jsonify({'error': 'Internal server error'}), 500

if __name__ == '__main__':
    app.run(debug=True, port=5000)

🔍 Query Parameters

Handle filtering and pagination with query parameters:

from flask import Flask, jsonify, request

app = Flask(__name__)

users = [
    {'id': 1, 'name': 'Alice', 'role': 'admin'},
    {'id': 2, 'name': 'Bob', 'role': 'user'},
    {'id': 3, 'name': 'Carol', 'role': 'user'},
    {'id': 4, 'name': 'Dave', 'role': 'admin'},
]

@app.route('/api/users', methods=['GET'])
def list_users():
    """Get users with filtering and pagination"""

    # Get query parameters
    role = request.args.get('role')  # ?role=admin
    page = request.args.get('page', 1, type=int)  # ?page=1
    limit = request.args.get('limit', 10, type=int)  # ?limit=10

    # Filter by role
    filtered_users = users
    if role:
        filtered_users = [u for u in filtered_users if u['role'] == role]

    # Pagination
    start = (page - 1) * limit
    end = start + limit
    paginated_users = filtered_users[start:end]

    return jsonify({
        'data': paginated_users,
        'total': len(filtered_users),
        'page': page,
        'limit': limit
    })

if __name__ == '__main__':
    app.run(debug=True)

# Test:
# curl http://localhost:5000/api/users
# curl http://localhost:5000/api/users?role=admin
# curl http://localhost:5000/api/users?page=2&limit=2

📝 Request/Response Documentation

from flask import Flask, jsonify

app = Flask(__name__)

@app.route('/api/docs', methods=['GET'])
def get_docs():
    """API documentation"""
    return jsonify({
        'title': 'My API',
        'version': '1.0',
        'endpoints': [
            {
                'method': 'GET',
                'path': '/api/users',
                'description': 'Get all users',
                'response': '[{"id": 1, "name": "Alice", ...}]'
            },
            {
                'method': 'GET',
                'path': '/api/users/<id>',
                'description': 'Get user by ID',
                'response': '{"id": 1, "name": "Alice", ...}'
            },
            {
                'method': 'POST',
                'path': '/api/users',
                'description': 'Create new user',
                'request_body': '{"name": "Alice", "email": "alice@example.com"}',
                'response': '{"id": 1, "name": "Alice", ...}',
                'status': 201
            }
        ]
    })

if __name__ == '__main__':
    app.run(debug=True)

✅ Key Takeaways

ConceptRemember
FlaskLightweight Python web framework for APIs
@app.route()Decorator that maps URLs to functions
methodsList HTTP methods: GET, POST, PUT, DELETE
request.get_json()Get JSON data from request body
jsonify()Convert Python dict to JSON response
Status CodesReturn appropriate codes: 200, 201, 400, 404, 500
URL ParametersUse `<int:id>` to capture from URL
Query ParametersUse `request.args.get()` for ?param=value
Error HandlingReturn error dicts with appropriate status codes

🔗 What's Next?

Learn the fundamentals of web scraping to extract data from websites.

Next: Web Scraping Basics →


Ready to practice? Try challenges or explore resources


Resources

Python Docs

Ojasa Mirai

Master AI-powered development skills through structured learning, real projects, and verified credentials. Whether you're upskilling your team or launching your career, we deliver the skills companies actually need.

Learn Deep • Build Real • Verify Skills • Launch Forward

Courses

PythonFastapiReactJSCloud

© 2026 Ojasa Mirai. All rights reserved.

TwitterGitHubLinkedIn