{"slug": "fix-ai-generated-code-practical-steps-for-backend-engineers", "title": "Fix AI Generated Code: Practical Steps for Backend Engineers", "summary": "A backend engineer has outlined a practical workflow for auditing and fixing AI-generated code, warning that AI tools frequently produce code that looks correct but introduces hardcoded secrets, SQL injection through string concatenation, and missing input validation. The guidance recommends parameterized queries, disabling debug modes in production, handling database integrity errors, and adding authentication and Pydantic validation to every AI-generated endpoint before it reaches production.", "body_md": "Fix AI generated code by starting with what you can see: broken endpoints, silent failures, or security warnings. I’ve been bitten by this more times than I can count - AI tools spit out code that looks right but fails in production. Here’s how to find and fix the real issues.\n\nThe most common vulnerabilities I see are hardcoded secrets, SQL injection via string concatenation, and missing input validation. AI often pulls patterns from public repos without understanding context. For example, it might generate a login endpoint like this:\n\n``` python\n@app.post(\"/login\")\ndef login(username: str, password: str):\n    query = f\"SELECT * FROM users WHERE username='{username}' AND password='{password}'\"\n    return db.execute(query).fetchone()\n```\n\nThis is an SQL injection waiting to happen. Never trust user input in a query string. Fix it by using parameterized queries with SQLAlchemy:\n\n``` python\n@app.post(\"/login\")\ndef login(username: str, password: str):\n    stmt = text(\"SELECT * FROM users WHERE username=:username AND password=:password\")\n    return db.execute(stmt, {\"username\": username, \"password\": password}).fetchone()\n```\n\nAnother frequent issue is leaving debug modes on or exposing internal errors. AI doesn’t know your deployment setup. Always override defaults in production:\n\n```\n# In your FastAPI app setup\napp = FastAPI(debug=False)  # Never True in prod\n```\n\nDetect logic errors by writing tests that mirror real user flows, not just unit tests on functions. AI often gets the “what” right but misses the “when” and “why.” For example, it might generate a user creation endpoint that doesn’t handle duplicate emails:\n\n``` python\n@app.post(\"/users\")\ndef create_user(user: UserCreate):\n    db_user = UserModel(**user.dict())\n    db.add(db_user)\n    db.commit()\n    return db_user\n```\n\nThis will crash on duplicate email if your DB has a unique constraint. Instead, catch the integrity error:\n\n``` python\nfrom sqlalchemy.exc import IntegrityError\n\n@app.post(\"/users\")\ndef create_user(user: UserCreate):\n    db_user = UserModel(**user.dict())\n    db.add(db_user)\n    try:\n        db.commit()\n    except IntegrityError:\n        db.rollback()\n        raise HTTPException(status_code=400, detail=\"Email already registered\")\n    return db_user\n```\n\nWrite a test that tries to create two users with the same email. If it passes, your logic holds. I use Pytest with fixtures to isolate DB state:\n\n``` python\ndef test_duplicate_email_rejected(client, db_session):\n    client.post(\"/users\", json={\"email\": \"a@b.com\", \"password\": \"x\"})\n    response = client.post(\"/users\", json={\"email\": \"a@b.com\", \"password\": \"y\"})\n    assert response.status_code == 400\n    assert \"Email already registered\" in response.json()[\"detail\"]\n```\n\nFix security flaws by assuming every AI-generated endpoint is insecure until proven otherwise. Start with authentication, then input validation, then rate limiting. AI often skips auth entirely or uses fake tokens.\n\nHere’s a typical AI-generated endpoint missing auth:\n\n``` python\n@app.get(\"/data\")\ndef get_data():\n    return {\"sensitive\": \"info\"}\n```\n\nAdd real auth using FastAPI’s dependencies. I use JWT with a simple verification function:\n\n``` python\nfrom fastapi import Depends, HTTPException, status\nfrom fastapi.security import HTTPBearer, HTTPAuthorizationCredentials\n\nsecurity = HTTPBearer()\n\ndef verify_token(credentials: HTTPAuthorizationCredentials = Depends(security)):\n    token = credentials.credentials\n    # In real life: verify signature, expiry, etc.\n    if token != \"valid-token-for-demo\":\n        raise HTTPException(\n            status_code=status.HTTP_401_UNAUTHORIZED,\n            detail=\"Invalid token\",\n        )\n    return token\n\n@app.get(\"/data\")\ndef get_data(token: str = Depends(verify_token)):\n    return {\"sensitive\": \"info\"}\n```\n\nThen validate inputs with Pydantic. Never accept raw dicts. AI often does this:\n\n``` python\n@app.post(\"/update\")\ndef update_item(data: dict):  # Bad\n    return {\"received\": data}\n```\n\nFix it with a model:\n\n``` python\nfrom pydantic import BaseModel\n\nclass UpdateItem(BaseModel):\n    item_id: int\n    value: str\n\n@app.post(\"/update\")\ndef update_item(item: UpdateItem):\n    return {\"updated\": item.item_id}\n```\n\nThis catches malformed JSON early and documents your API.\n\nValidate SQLAlchemy models by checking constraints, relationships, and migrations. AI often creates models without nullable defaults, wrong cascade rules, or missing indexes. I once saw a model where `created_at` had no default and wasn’t indexed - causing slow queries and NULL errors.\n\nHere’s a risky AI-generated model:\n\n```\nclass User(Base):\n    __tablename__ = \"users\"\n    id = Column(Integer, primary_key=True)\n    email = Column(String)  # No unique, no index\n    password = Column(String)\n```\n\nFix it by adding constraints and indexes that match your business rules:\n\n```\nclass User(Base):\n    __tablename__ = \"users\"\n    id = Column(Integer, primary_key=True)\n    email = Column(String, unique=True, index=True, nullable=False)\n    password = Column(String, nullable=False)\n    created_at = Column(DateTime, server_default=func.now(), nullable=False)\n```\n\nUse Alembic to generate migrations after you fix the model. Then run them in a staging DB before deploying. Never skip this step - AI doesn’t know your schema evolution.\n\nTest API contracts by treating your OpenAPI spec as the source of truth. AI often generates endpoints that don’t match the declared schema - missing fields, wrong types, or extra keys. I use Pytest to validate responses against the schema.\n\nFirst, generate your OpenAPI JSON:\n\n```\ncurl http://localhost:8000/openapi.json > openapi.json\n```\n\nThen write a test that checks every endpoint:\n\n``` python\nimport jsonschema\nimport json\n\nwith open(\"openapi.json\") as f:\n    OPENAPI_SCHEMA = json.load(f)\n\ndef test_api_matches_schema(client):\n    for path, path_item in OPENAPI_SCHEMA[\"paths\"].items():\n        for method, operation in path_item.items():\n            if method.lower() in [\"get\", \"post\", \"put\", \"delete\", \"patch\"]:\n                response = client.request(method, path)\n                jsonschema.validate(\n                    instance=response.json(),\n                    schema=operation[\"responses\"][\"200\"][\"content\"][\"application/json\"][\"schema\"]\n                )\n```\n\nThis catches mismatches early. If AI adds a field not in the schema, the test fails. If it omits a required one, same thing. It’s saved me from silent data corruption more than once.\n\nRefactor AI-generated async code by removing blocking calls and ensuring proper error propagation. AI often mixes sync and async or forgets to await. I’ve seen endpoints that call `time.sleep(5)` inside an async function - destroying concurrency.\n\nHere’s a bad example:\n\n``` python\n@app.get(\"/slow\")\nasync def slow_endpoint():\n    time.sleep(2)  # Blocking!\n    return {\"done\": True}\n```\n\nFix it by using `asyncio.sleep` if you need a delay, or better - remove the delay entirely. For real work like HTTP calls, use `httpx.AsyncClient`:\n\n``` python\nimport httpx\n\n@app.get(\"/fetch\")\nasync def fetch_external():\n    async with httpx.AsyncClient() as client:\n        resp = await client.get(\"https://api.example.com/data\")\n        return resp.json()\n```\n\nAlso, watch for missing `try/except` blocks. AI often omits error handling in async code. Wrap external calls:\n\n``` python\n@app.get(\"/fetch\")\nasync def fetch_external():\n    try:\n        async with httpx.AsyncClient() as client:\n            resp = await client.get(\"https://api.example.com/data\")\n            resp.raise_for_status()\n            return resp.json()\n    except httpx.RequestError as e:\n        raise HTTPException(status_code=502, detail=f\"External error: {str(e)}\")\n```\n\nFinally, use logging instead of `print`. AI loves `print` - it’s useless in production. Use structlog or Python’s logging module with JSON output.\n\nDon’t trust AI generated code for authentication, payment processing, or any code handling PII. I’ve seen AI generate OAuth flows that skipped state validation - critical for security. For those, use battle-tested libraries like `fastapi-users` or `python-jose` and read the docs.\n\nAlso, avoid using AI to generate migration scripts. Schema changes are too risky. Write them yourself or use Alembic’s autogenerate with careful review.\n\nAI is great for boilerplate, repetitive CRUD, or getting unstuck on a tricky algorithm. But production systems need human judgment. Treat AI output like a junior engineer’s first draft: review it, test it, and break it on purpose.\n\nIf you’re stuck fixing AI generated code in your FastAPI or data stack, I’ve helped indie builders do this exact work. You can [hire me](https://www.logiclooptech.dev/hire/) to audit your endpoints, write tests, and make your AI-generated code production ready - no fluff, just fixes.\n\nLook for string concatenation with user input in SQL queries. If you see `f\"SELECT ... {user_input}\"` or `+ user_input +`, it’s vulnerable. Fix it with parameterized queries or ORM methods.\n\nNot safely. AI often misses token validation, scope checks, or refresh token handling. Use a trusted library and have AI only generate non-critical parts like route stubs or response models.\n\nRun it through a linter like `ruff` or `flake8`, then write a test that exercises the happy path and one edge case. If it passes both, it’s likely safe for low-risk code.\n\nNo. Migrations alter your data schema. A mistake can corrupt or lose data. Write them manually, test them in a copy of production, and review every line.", "url": "https://wpnews.pro/news/fix-ai-generated-code-practical-steps-for-backend-engineers", "canonical_source": "https://dev.to/ayush_kumar_085a0f2c54e3f/fix-ai-generated-code-practical-steps-for-backend-engineers-47eg", "published_at": "2026-09-14 05:46:25+00:00", "updated_at": "2026-09-14 05:56:44.530134+00:00", "lang": "en", "topics": ["ai-tools", "developer-tools", "ai-safety", "ai-products"], "entities": ["FastAPI", "SQLAlchemy", "Pydantic", "Pytest", "JWT"], "alternates": {"html": "https://wpnews.pro/news/fix-ai-generated-code-practical-steps-for-backend-engineers", "markdown": "https://wpnews.pro/news/fix-ai-generated-code-practical-steps-for-backend-engineers.md", "text": "https://wpnews.pro/news/fix-ai-generated-code-practical-steps-for-backend-engineers.txt", "jsonld": "https://wpnews.pro/news/fix-ai-generated-code-practical-steps-for-backend-engineers.jsonld"}}