REST API Communication
REST (Representational State Transfer) is an architectural style for designing web services. A REST API is an application programming interface that conforms to the design principles of REST. REST APIs provide a lightweight way to build web APIs and are commonly used to exchange data between applications, web services and databases. In a RESTful design the client and server are decoupled; the client only needs to know the URI of the resource and the server is responsible for processing the request.
REST design principles
A well‑designed REST API adheres to several architectural constraints:
- Uniform interface – each resource is identified by a URI and all requests for the same resource look the same.
- Client/server decoupling – the client and server operate independently; the client should not know anything about how the server is implemented.
- Statelessness – each HTTP request contains all information necessary to process it; no client context is stored on the server.
- Cacheability – responses can be labeled as cacheable to improve performance.
- Layered system – requests may pass through multiple layers (such as proxies or load balancers) but the client cannot tell whether it communicates with the end server or an intermediary.
HTTP defines verbs such as GET, POST, PUT, DELETE, etc. These verbs have different properties. For example, GET and PUT are idempotent—issuing the same request multiple times has the same effect—whereas POST is not. In a REST API, GET is used to read data, POST to create new resources, PUT to update resources, and DELETE to remove them.
Install packages
To build a REST API in Python you need a web framework for the server and a client library for sending HTTP requests. Use Flask to create a simple server and requests to act as an HTTP client.
REST server with Flask
The following script implements a minimal REST API that manages key–value pairs. It defines endpoints for the HTTP verbs GET, POST, PUT and DELETE. Run the script to start the server on port 5000.
app = Flask(__name__)
# in‑memory store for demonstration
items = {}
@app.route('/items/<key>', methods=['GET'])
def get_item(key):
"""Return the value for a given key or a 404 error."""
if key not in items:
return jsonify({'error': 'Not found'}), 404
return jsonify({'value': items[key]})
@app.route('/items/<key>', methods=['POST'])
def create_item(key):
"""Create a new item; returns 201 on success."""
data = request.get_json()
items[key] = data['value']
return jsonify({'message': 'Item created'}), 201
@app.route('/items/<key>', methods=['PUT'])
def update_item(key):
"""Update an existing item or create it if missing."""
data = request.get_json()
items[key] = data['value']
return jsonify({'message': 'Item updated'})
@app.route('/items/<key>', methods=['DELETE'])
def delete_item(key):
"""Delete an existing item."""
if key in items:
del items[key]
return jsonify({'message': 'Item deleted'})
return jsonify({'error': 'Not found'}), 404
if __name__ == '__main__':
app.run(port=5000)
REST client with requests
Use the requests library to interact with the API. The following example sends POST, GET, PUT and DELETE requests against the /items/<key> endpoint.
base_url = "http://localhost:5000/items"
# Create a new item
resp = requests.post(f"{base_url}/username", json={'value': 'Alice'})
print('POST:', resp.status_code, resp.json())
# Retrieve the item
resp = requests.get(f"{base_url}/username")
print('GET:', resp.status_code, resp.json())
# Update the item
resp = requests.put(f"{base_url}/username", json={'value': 'Bob'})
print('PUT:', resp.status_code, resp.json())
# Delete the item
resp = requests.delete(f"{base_url}/username")
print('DELETE:', resp.status_code, resp.json())
✅ Activity
Develop a RESTful API for managing a simple to‑do list. The server should support adding new tasks (POST), listing all tasks (GET), updating a task’s completion status (PUT), and deleting tasks (DELETE). Each task can have a unique identifier, a description and a Boolean flag indicating whether it is complete.
- Server: Use Flask to implement the /tasks resource. Store tasks in a dictionary (or list) with a task ID as the key. Implement endpoints for GET /tasks (list all tasks), POST /tasks/<id> (create a task with a JSON payload containing a description), PUT /tasks/<id> (update the completion status), and DELETE /tasks/<id> (delete a task).
app = Flask(__name__)
tasks = {} # {id: {'description': str, 'complete': bool}}
@app.route('/tasks', methods=['GET'])
def list_tasks():
return jsonify(list(tasks.values()))
@app.route('/tasks/<task_id>', methods=['POST'])
def add_task(task_id):
data = request.get_json()
tasks[task_id] = {'id': task_id, 'description': data['description'], 'complete': False}
return jsonify({'message': 'Task added'}), 201
@app.route('/tasks/<task_id>', methods=['PUT'])
def update_task(task_id):
if task_id in tasks:
data = request.get_json()
tasks[task_id]['complete'] = data.get('complete', tasks[task_id]['complete'])
return jsonify({'message': 'Task updated'})
return jsonify({'error': 'Task not found'}), 404
@app.route('/tasks/<task_id>', methods=['DELETE'])
def delete_task(task_id):
if task_id in tasks:
del tasks[task_id]
return jsonify({'message': 'Task deleted'})
return jsonify({'error': 'Task not found'}), 404
if __name__ == '__main__':
app.run(port=5001)
- Client: Write a Python script that sends requests to your API to add a task, mark it complete and retrieve the task list. Print the JSON responses to the console.
base = 'http://localhost:5001/tasks'
# Add tasks
requests.post(f'{base}/task1', json={'description': 'Learn REST APIs'})
requests.post(f'{base}/task2', json={'description': 'Build a Flask server'})
# Mark task1 complete
requests.put(f'{base}/task1', json={'complete': True})
# List all tasks
resp = requests.get(base)
print('All tasks:', resp.json())
# Delete task2
requests.delete(f'{base}/task2')
# List again
resp = requests.get(base)
print('Remaining tasks:', resp.json())
✅ Knowledge Check
1. Which HTTP method is idempotent and should be used to update an existing resource without creating a duplicate?
- Incorrect. POST is used to create new resources and is not idempotent; sending the same POST multiple times creates multiple resources or side effects.
- Correct. PUT is idempotent — sending the same PUT request repeatedly results in the same state because the resource is fully replaced.
- Incorrect. Although DELETE is idempotent, its purpose is to remove resources, not update them.
- Incorrect. PATCH modifies resources but is not guaranteed to be idempotent.
2. According to REST architectural constraints, where is client state stored?
- Incorrect. REST APIs are stateless: each request contains all necessary information and the server does not store client state.
- Incorrect. Statelessness means the server does not rely on hidden cookies to track client context.
- Correct. Each REST request must include all information necessary to process it; servers do not retain client state between requests.
- Incorrect. Caching improves performance, but the authoritative state of the resource is stored on the server, not in a shared client cache.