Last Updated on 2024-06-02 by Clay
Introduction
RESTful design (Representational State Transfer, REST) is an architectural style for designing network applications. It follows principles that make network applications simpler, more scalable, and easier to maintain.
Below are the core concepts and principles of RESTful design:
Core Concepts
- Resources:
- Resources are any entities on the network, such as users, images, documents, etc.
- Each resource is uniquely identified by a URI (Uniform Resource Identifier).
- Representations:
- Resources can have multiple representations, such as JSON, XML, HTML, etc.
- Clients interact with resources through these representations.
- State Transfer:
- Interactions between clients and servers are stateless; each request contains all necessary information.
- State transfer occurs through HTTP methods (e.g., GET, POST, PUT, DELETE).
Basic Principles
- Statelessness:
- Each request should be independent and not rely on previous requests.
- Servers do not retain client state between requests.
- Uniform Interface:
- Use standard HTTP methods and status codes.
- Resource representations should be meaningful for clients to understand and use them.
- Scalability:
- Improve scalability through stateless requests and layered system design.
- Cacheability:
- Servers should explicitly indicate which resources are cacheable to improve performance.
- Layered System:
- Clients do not need to know if they are directly communicating with the final server; requests may go through multiple intermediary layers.
- This layered design helps improve scalability and security.
- Code on Demand (Optional):
- Servers can transfer executable code (e.g., JavaScript) to clients for execution at runtime.
HTTP Methods
When designing APIs based on RESTful principles, it’s important to use the following HTTP request methods:
- GET:
- Used to retrieve resources.
- This is a read-only operation and does not change the state of the resource.
- POST:
- Used to create new resources.
- Typically, a new resource is created on the server, and its URI is returned.
- PUT:
- Used to update existing resources.
- If the resource does not exist, a new one can be created (similar to an upsert operation combining insert and update).
- DELETE:
- Used to delete resources.
- PATCH:
- Used to partially update resources.
By adhering to these principles, we can design APIs that are simple, scalable, maintainable, and flexible. Let’s proceed with a practical example.
Practical Example
Below is a simple RESTful API interface using Python’s FastAPI, covering basic CRUD operations.
from typing import List, Optional
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
import uvicorn
app = FastAPI()
# Define resource model
class Item(BaseModel):
id: int
name: str
description: Optional[str] = None
price: float
tax: Optional[float] = None
# Simulated database
items_db = []
# POST - Create resource
@app.post("/items/", response_model=Item)
def create_item(item: Item):
for db_item in items_db:
if db_item.id == item.id:
raise HTTPException(status_code=400, detail="Item already exists")
items_db.append(item)
return item
# GET - Get all resources
@app.get("/items/", response_model=List[Item])
def read_items():
return items_db
# GET - Get a specific resource
@app.get("/items/{item_id}", response_model=Item)
def read_item(item_id: int):
for item in items_db:
if item.id == item_id:
return item
raise HTTPException(status_code=404, detail="Item not found")
# PUT - Update resource
@app.put("/items/{item_id}", response_model=Item)
def update_item(item_id: int, updated_item: Item):
for index, item in enumerate(items_db):
if item.id == item_id:
items_db[index] = updated_item
return updated_item
raise HTTPException(status_code=404, detail="Item not found")
# PATCH - Partially update resource
@app.patch("/items/{item_id}", response_model=Item)
def partial_update_item(item_id: int, item_update: dict):
for item in items_db:
if item.id == item_id:
if "name" in item_update:
item.name = item_update["name"]
if "description" in item_update:
item.description = item_update["description"]
if "price" in item_update:
item.price = item_update["price"]
if "tax" in item_update:
item.tax = item_update["tax"]
return item
raise HTTPException(status_code=404, detail="Item not found")
# DELETE - Delete resource
@app.delete("/items/{item_id}")
def delete_item(item_id: int):
for index, item in enumerate(items_db):
if item.id == item_id:
del items_db[index]
return {"detail": "Item deleted"}
raise HTTPException(status_code=404, detail="Item not found")
if __name__ == "__main__":
uvicorn.run("app:app", host="0.0.0.0", port=8000, reload=True)
CURL Terminal Request Examples
After starting the FastAPI service, you can use the following HTTP methods to request resources. Here are the commands; prepend each with the curl
command to test.
Create Resource (POST)
-X POST "http://127.0.0.1:8000/items/" -H "Content-Type: application/json" -d '{"id": 1, "name": "Item1", "description": "A sample item", "price": 10.0, "tax": 1.0}'
Get All Resources (GET)
-X GET "http://127.0.0.1:8000/items/"
Get a Single Resource (GET)
-X GET "http://127.0.0.1:8000/items/1"
Update Resource (PUT)
-X PUT "http://127.0.0.1:8000/items/1" -H "Content-Type: application/json" -d '{"id": 1, "name": "Updated Item", "description": "Updated description", "price": 20.0, "tax": 2.0}'
Partially Update Resource (PATCH)
-X PATCH "http://127.0.0.1:8000/items/1" -H "Content-Type: application/json" -d '{"name": "Partially Updated Item", "price": 15.0}'
Delete Resource (DELETE)
-X DELETE "http://127.0.0.1:8000/items/1"
These commands display how to use curl
to request the RESTful APIs.