api.py•6.47 kB
from fastapi import FastAPI, Depends, HTTPException, Request
from fastapi.responses import JSONResponse
from fastapi.middleware.cors import CORSMiddleware
from fastapi.exception_handlers import http_exception_handler
import logging
from src.models import Search, Photos, Random
from src.services import search_service, photos_service, random_service
from src.config import settings
from src.app.mcp import setup_mcp
# Configure logger for MCP requests
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger("mcp_logger")
app = FastAPI(
title=settings.PROJECT_NAME,
description="API for accessing Unsplash images and metadata",
version="1.0.0",
debug=settings.DEBUG,
)
# Add MCP-specific exception handler
@app.exception_handler(HTTPException)
async def mcp_http_exception_handler(request: Request, exc: HTTPException):
if request.url.path.startswith("/mcp"):
# Custom error formatting for MCP clients
return JSONResponse(
status_code=exc.status_code,
content={
"error": exc.detail,
"suggestion": "Try adjusting your query parameters or check the documentation.",
},
)
# Default handling for other clients
return await http_exception_handler(request, exc)
origins = ["*"]
app.add_middleware(
CORSMiddleware,
allow_origins=origins,
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# Middleware for logging MCP requests
@app.middleware("http")
async def log_mcp_requests(request: Request, call_next):
if request.url.path.startswith("/mcp"):
logger.info(f"MCP Request: {request.method} {request.url.path}")
response = await call_next(request)
return response
@app.get("/")
async def root():
"""
Root endpoint.
Returns basic information about the API and available endpoints.
"""
return {
"message": f"Welcome to {settings.PROJECT_NAME}",
"status": "running",
"version": "1.0.0",
"health_check": "/health",
"docs_url": "/docs",
"redoc_url": "/redoc",
"endpoints": {},
}
@app.get(
"/search_photos",
description="""
Search for images on Unsplash based on a query string.
This endpoint allows you to search for photos using keywords. The results include comprehensive
metadata about each photo, including descriptions, author information, download links, and engagement metrics.
Examples:
- Search for nature photos: `?query=nature&page=1&per_page=10&order_by=relevant`
- Search for city skylines: `?query=city+skyline&page=1&per_page=20&order_by=latest`
- Search for minimal workspace: `?query=minimal+workspace&page=1&per_page=5&order_by=relevant`
The `order_by` parameter accepts:
- `relevant` (default): Orders by relevance to the search query
- `latest`: Orders by most recently published
""",
operation_id="search_photos",
tags=["search", "photos"],
)
def search_photos(search=Depends(Search)):
try:
res = search_service(
query=search.query,
page=search.page,
per_page=search.per_page,
order_by=search.order_by,
)
return JSONResponse(status_code=200, content=res)
except Exception as e:
return JSONResponse(status_code=500, content=e)
@app.get(
"/get_photos",
description="""
Retrieve a curated collection of photos from Unsplash.
This endpoint returns a list of photos with complete metadata, sorted according to your preferences.
It's useful for getting high-quality images without specific search criteria.
The response includes comprehensive details about each photo:
- High-resolution image URLs in various sizes
- Photographer information (name, profile, portfolio)
- Photo statistics (downloads, views, likes)
- Photo metadata (description, alt text, camera info when available)
- Related collections and tags
Examples:
- Get 10 latest photos: `?page=1&per_page=10&order_by=latest`
- Get 20 popular photos: `?page=1&per_page=20&order_by=popular`
- Get 5 oldest photos: `?page=1&per_page=5&order_by=oldest`
The `order_by` parameter accepts:
- `latest` (default): Most recently published photos
- `oldest`: Oldest published photos
- `popular`: Most popular photos based on views, downloads, and likes
""",
operation_id="get_photos",
tags=["photos"],
)
def get_photos(photos=Depends(Photos)):
try:
res = photos_service(
page=photos.page, per_page=photos.per_page, order_by=photos.order_by
)
return JSONResponse(status_code=200, content=res)
except Exception as e:
return JSONResponse(status_code=500, content=e)
@app.get(
"/get_random_photos",
description="""
Get random photos from Unsplash, optionally filtered by a search term.
This endpoint returns a collection of random photos from Unsplash's extensive library.
You can optionally provide a search query to get random photos matching specific criteria.
This is particularly useful for:
- Creating dynamic image galleries that change on each page load
- Displaying varied content for inspiration or background images
- Getting a diverse set of images for a specific theme or topic
The response includes the same comprehensive metadata as other photo endpoints:
- Multiple resolution URLs
- Complete photographer information
- Engagement statistics
- Technical photo details
Examples:
- Get 1 completely random photo: `?count=1`
- Get 5 random nature photos: `?query=nature&count=5`
- Get 3 random architecture photos: `?query=architecture&count=3`
Note: The random selection is made from Unsplash's curated collection of high-quality images,
ensuring you receive professional-grade photography regardless of the randomization.
""",
operation_id="get_random_photos",
tags=["photos", "random"],
)
def get_random_photos(random=Depends(Random)):
try:
res = random_service(query=random.query, count=random.count)
return JSONResponse(status_code=200, content=res)
except Exception as e:
return JSONResponse(status_code=500, content=e)
# Create FastAPI-MCP instance after all endpoints are defined
mcp = setup_mcp(app)
# Re-register all tools to ensure they're available to MCP clients
mcp.setup_server()