APIs mit Cursor erstellen: REST, GraphQL und FastAPI

Der Aufbau robuster APIs erfordert sorgfältige Planung, konsistente Patterns und gründliches Testing. Die KI-Funktionen von Cursor können jede Phase der API-Entwicklung beschleunigen, vom Gerüstbau der Endpoints bis zur Generierung von OpenAPI-Dokumentation. Dieser Leitfaden deckt REST-, GraphQL- und FastAPI-Workflows ab.
Voraussetzungen
Bevor Sie beginnen:
- Cursor installiert mit Pro-Plan (empfohlen)
- Node.js oder Python installiert
- Vertrautheit mit HTTP-Konzepten und JSON
REST-API-Entwicklung
Projekt-Gerüstbau
Bitten Sie Cursor, eine vollständige REST-API zu erstellen:
Erstelle eine REST-API mit Express.js inklusive:
- TypeScript
- Route-Handler in src/routes/
- Middleware für Logging und Fehlerbehandlung
- Input-Validierung mit Zod
- JWT-Authentifizierung
- Rate Limiting
- Swagger-Dokumentation
Express.js-Routenstruktur
// src/routes/users.ts
import { Router } from 'express';
import { z } from 'zod';
import { authenticate } from '../middleware/auth';
import { validate } from '../middleware/validate';
const router = Router();
const createUserSchema = z.object({
email: z.string().email(),
name: z.string().min(2).max(100),
password: z.string().min(8),
});
router.post(
'/',
authenticate,
validate(createUserSchema),
async (req, res, next) => {
try {
const user = await createUser(req.body);
res.status(201).json({
success: true,
data: user,
});
} catch (error) {
next(error);
}
}
);
router.get('/:id', authenticate, async (req, res, next) => {
try {
const user = await getUserById(req.params.id);
if (!user) {
return res.status(404).json({
success: false,
error: 'User not found',
});
}
res.json({ success: true, data: user });
} catch (error) {
next(error);
}
});
export default router;
Einheitliche Fehlerbehandlung
// src/middleware/errorHandler.ts
import { Request, Response, NextFunction } from 'express';
export class AppError extends Error {
constructor(
public statusCode: number,
public message: string,
public isOperational = true
) {
super(message);
Object.setPrototypeOf(this, AppError.prototype);
}
}
export const errorHandler = (
err: Error,
req: Request,
res: Response,
next: NextFunction
) => {
if (err instanceof AppError) {
return res.status(err.statusCode).json({
success: false,
error: err.message,
});
}
console.error('Unexpected error:', err);
res.status(500).json({
success: false,
error: 'Internal server error',
});
};
FastAPI-Entwicklung mit Cursor
FastAPI-Endpoints erstellen
# main.py
from fastapi import FastAPI, HTTPException, Depends, status
from fastapi.security import OAuth2PasswordBearer
from pydantic import BaseModel, EmailStr
from typing import List, Optional
import uvicorn
app = FastAPI(
title="My API",
description="A production-ready API built with FastAPI",
version="1.0.0",
)
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
# Pydantic-Modelle
class UserCreate(BaseModel):
email: EmailStr
name: str
password: str
class UserResponse(BaseModel):
id: int
email: str
name: str
class Config:
from_attributes = True
# Speicher im Arbeitsspeicher (durch Datenbank ersetzen)
users_db = {}
user_counter = 0
@app.post(
"/users",
response_model=UserResponse,
status_code=status.HTTP_201_CREATED,
tags=["users"],
)
async def create_user(user: UserCreate):
global user_counter
user_counter += 1
new_user = {
"id": user_counter,
"email": user.email,
"name": user.name,
}
users_db[user_counter] = new_user
return new_user
@app.get(
"/users/{user_id}",
response_model=UserResponse,
tags=["users"],
)
async def get_user(user_id: int):
if user_id not in users_db:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail="User not found",
)
return users_db[user_id]
@app.get("/users", response_model=List[UserResponse], tags=["users"])
async def list_users(
skip: int = 0,
limit: int = 100,
):
return list(users_db.values())[skip : skip + limit]
if __name__ == "__main__":
uvicorn.run(app, host="0.0.0.0", port=8000)
Dependency Injection
# dependencies.py
from fastapi import Depends, HTTPException, status
from sqlalchemy.orm import Session
from database import SessionLocal
async def get_db():
db = SessionLocal()
try:
yield db
finally:
db.close()
async def get_current_user(token: str = Depends(oauth2_scheme)):
user = verify_token(token)
if not user:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Invalid authentication",
)
return user
# Verwendung
@app.get("/items")
async def read_items(
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user),
):
return db.query(Item).filter(Item.owner_id == current_user.id).all()
GraphQL-API-Entwicklung
Apollo Server Setup
// src/schema.ts
import { gql } from 'apollo-server-express';
export const typeDefs = gql`
type User {
id: ID!
email: String!
name: String!
posts: [Post!]!
}
type Post {
id: ID!
title: String!
content: String!
author: User!
}
type Query {
users: [User!]!
user(id: ID!): User
posts: [Post!]!
post(id: ID!): Post
}
type Mutation {
createUser(email: String!, name: String!, password: String!): User!
createPost(title: String!, content: String!, authorId: ID!): Post!
}
`;
Resolver mit Cursor
// src/resolvers.ts
export const resolvers = {
Query: {
users: async (_, __, { dataSources }) => {
return dataSources.userAPI.getAllUsers();
},
user: async (_, { id }, { dataSources }) => {
return dataSources.userAPI.getUserById(id);
},
},
User: {
posts: async (parent, _, { dataSources }) => {
return dataSources.postAPI.getPostsByAuthor(parent.id);
},
},
Mutation: {
createUser: async (_, args, { dataSources }) => {
return dataSources.userAPI.createUser(args);
},
},
};
GraphQL-Schema-Design
Verwenden Sie Cursor, um GraphQL-Schemas aus Ihrem Datenbankschema zu generieren. Fügen Sie Ihr Prisma-Schema ein und fragen Sie nach den entsprechenden GraphQL-Typdefinitionen.
Authentifizierung und Autorisierung
JWT-Implementierung
// src/utils/jwt.ts
import jwt from 'jsonwebtoken';
import bcrypt from 'bcrypt';
const JWT_SECRET = process.env.JWT_SECRET!;
const SALT_ROUNDS = 12;
export const hashPassword = async (password: string): Promise<string> => {
return bcrypt.hash(password, SALT_ROUNDS);
};
export const comparePassword = async (
password: string,
hash: string
): Promise<boolean> => {
return bcrypt.compare(password, hash);
};
export const generateToken = (payload: object): string => {
return jwt.sign(payload, JWT_SECRET, { expiresIn: '24h' });
};
export const verifyToken = (token: string): any => {
return jwt.verify(token, JWT_SECRET);
};
Middleware-Pattern
// src/middleware/rateLimit.ts
import rateLimit from 'express-rate-limit';
export const apiLimiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 Minuten
max: 100, // limitiert jede IP auf 100 Requests pro Fenster
message: {
success: false,
error: 'Too many requests, please try again later',
},
standardHeaders: true,
legacyHeaders: false,
});
API-Dokumentation
OpenAPI mit FastAPI
FastAPI generiert automatisch OpenAPI-Dokumentation. Zugriff unter:
- Swagger UI:
/docs - ReDoc:
/redoc
Express.js mit Swagger
// src/config/swagger.ts
import swaggerJsdoc from 'swagger-jsdoc';
const options = {
definition: {
openapi: '3.0.0',
info: {
title: 'My API',
version: '1.0.0',
description: 'API documentation',
},
servers: [
{
url: 'http://localhost:3000/api',
},
],
},
apis: ['./src/routes/*.ts'],
};
export const specs = swaggerJsdoc(options);
APIs testen
Integrationstest-Beispiel
// tests/users.test.ts
import request from 'supertest';
import app from '../src/app';
describe('Users API', () => {
describe('POST /users', () => {
it('should create a new user', async () => {
const response = await request(app)
.post('/users')
.send({
name: 'Test User',
password: 'securePassword123',
})
.expect(201);
expect(response.body.success).toBe(true);
});
it('should reject invalid email', async () => {
await request(app)
.post('/users')
.send({
email: 'invalid-email',
name: 'Test',
password: 'password',
})
.expect(400);
});
});
});
API-Design Best Practices
| Praxis | Implementierung |
|---|---|
| Versionierung | Präfix /api/v1/ in URLs verwenden |
| Paginierung | { data, meta: { page, limit, total } } zurückgeben |
| Filterung | Query-Parameter verwenden: ?status=active&sort=created_at |
| Fehlerformat | Konsistentes { success: false, error: "message" } |
| Rate Limiting | 100 Requests pro 15 Minuten für öffentliche Endpoints |
| Caching | ETag-Header und Redis für Response-Caching verwenden |
Häufige API-Patterns
Repository-Pattern
// src/repositories/UserRepository.ts
export class UserRepository {
async findById(id: string): Promise<User | null> {
return prisma.user.findUnique({ where: { id } });
}
async findByEmail(email: string): Promise<User | null> {
return prisma.user.findUnique({ where: { email } });
}
async create(data: CreateUserInput): Promise<User> {
return prisma.user.create({ data });
}
async update(id: string, data: UpdateUserInput): Promise<User> {
return prisma.user.update({ where: { id }, data });
}
async delete(id: string): Promise<void> {
await prisma.user.delete({ where: { id } });
}
}
Umgebungskonfiguration
# .env
NODE_ENV=development
PORT=3000
DATABASE_URL=postgresql://user:pass@localhost:5432/myapp
JWT_SECRET=your-secret-key
REDIS_URL=redis://localhost:6379
RATE_LIMIT_MAX=100
Kurzreferenz
| Aufgabe | Cursor Prompt |
|---|---|
| CRUD-Endpoints generieren | "Erstelle CRUD-Endpoints für eine Product-Ressource mit Validierung" |
| Authentifizierung hinzufügen | "Füge JWT-Authentifizierungs-Middleware zu allen geschützten Routen hinzu" |
| GraphQL-Schema erstellen | "Generiere GraphQL-Typen aus diesem Prisma-Schema" |
| Tests schreiben | "Schreibe Integrationstests für den User-Registration-Endpoint" |
| Rate Limiting hinzufügen | "Füge Rate Limiting zur API mit unterschiedlichen Tiers für auth vs public hinzu" |
Verwandte Ressourcen
Zuletzt aktualisiert: Juli 2025