1. Open a resilient database connection
Create a dedicated module (e.g.,connection.py) that attempts to connect in a retry loop. This pattern is helpful when your database may still be initializing (for example in containers or managed services).
from connection import conn, cursor and execute queries.
Common connection errors and quick fixes
2. Understand cursor.execute() vs fetch methods
Important:cursor.execute() runs the SQL statement but returns None. To retrieve rows from a SELECT query you must call one of the fetch methods.
Remember: always invoke the fetch method with parentheses — e.g.
cursor.fetchall() — otherwise you only have a reference to the function, not the query results.
Always use parameterized queries to avoid SQL injection, passing parameters as the second argument to
cursor.execute():
INSERT, UPDATE, DELETE), call conn.commit() to persist changes, or set conn.autocommit = True.
3. Example in-memory posts (for comparison / simple create route)
4. Route handlers (main.py)
Below is an example FastAPI app that imports the database connection and demonstrates reading rows from PostgreSQL for the/posts endpoint. It also includes a simple in-memory create route to illustrate POST handling.
5. Example JSON response
Example response returned by the/posts endpoint (FastAPI serializes RealDictRow objects naturally as JSON):
RealDictCursoryieldsRealDictRowobjects that behave like dictionaries and serialize to JSON correctly.- PostgreSQL may add metadata columns such as
created_atwith timezone-aware timestamps.
Do not keep plaintext database credentials in source code for production. Use environment variables, configuration systems, or secret management (e.g., Vault, AWS Secrets Manager) and rotate credentials regularly.
6. Quick checklist and best practices
- Use a retry loop for resilient connections when databases may be slow to start.
- Call
cursor.execute()to run SQL, thencursor.fetchall()/cursor.fetchone()/cursor.fetchmany()to retrieve results. - Use
fetchall()for queries returning multiple rows andfetchone()for a single-row lookup by unique key. - For writes, call
conn.commit()or enableconn.autocommit = True. - Always use parameterized queries to prevent SQL injection (e.g.,
cursor.execute(sql, params)). - Keep credentials out of code (use environment variables or secret stores).