-- Create API endpoints tableCREATETABLEapi_endpoints(idSERIALPRIMARYKEY,endpoint_pathVARCHAR(200)UNIQUENOTNULL,http_methodVARCHAR(10)NOTNULL,descriptionTEXT,parametersJSONB,response_schemaJSONB,authentication_requiredBOOLEANDEFAULTTRUE,rate_limit_per_minuteINTEGERDEFAULT100,created_atTIMESTAMPTZDEFAULTCURRENT_TIMESTAMP,updated_atTIMESTAMPTZDEFAULTCURRENT_TIMESTAMP);-- Create function to register API endpointCREATEORREPLACEFUNCTIONregister_api_endpoint(p_endpoint_pathVARCHAR(200),p_http_methodVARCHAR(10),p_descriptionTEXT,p_parametersJSONBDEFAULT'{}',p_response_schemaJSONBDEFAULT'{}',p_authentication_requiredBOOLEANDEFAULTTRUE,p_rate_limit_per_minuteINTEGERDEFAULT100)RETURNSVOIDAS$$BEGININSERTINTOapi_endpoints(endpoint_path,http_method,description,parameters,response_schema,authentication_required,rate_limit_per_minute)VALUES(p_endpoint_path,p_http_method,p_description,p_parameters,p_response_schema,p_authentication_required,p_rate_limit_per_minute)ONCONFLICT(endpoint_path)DOUPDATESEThttp_method=EXCLUDED.http_method,description=EXCLUDED.description,parameters=EXCLUDED.parameters,response_schema=EXCLUDED.response_schema,authentication_required=EXCLUDED.authentication_required,rate_limit_per_minute=EXCLUDED.rate_limit_per_minute,updated_at=CURRENT_TIMESTAMP;END;$$LANGUAGEplpgsql;-- Register common API endpointsSELECTregister_api_endpoint('/api/v1/users','GET','Get all users','{}','{"users": []}',TRUE,100);SELECTregister_api_endpoint('/api/v1/users/{id}','GET','Get user by ID','{"id": "integer"}','{"user": {}}',TRUE,100);SELECTregister_api_endpoint('/api/v1/users','POST','Create new user','{"user": {}}','{"user": {}}',TRUE,50);SELECTregister_api_endpoint('/api/v1/users/{id}','PUT','Update user','{"id": "integer", "user": {}}','{"user": {}}',TRUE,50);SELECTregister_api_endpoint('/api/v1/users/{id}','DELETE','Delete user','{"id": "integer"}','{"message": "User deleted"}',TRUE,25);
-- Create API keys tableCREATETABLEapi_keys(idSERIALPRIMARYKEY,key_hashVARCHAR(64)UNIQUENOTNULL,key_nameVARCHAR(100)NOTNULL,user_idINTEGER,permissionsJSONBDEFAULT'{}',rate_limit_per_minuteINTEGERDEFAULT100,is_activeBOOLEANDEFAULTTRUE,expires_atTIMESTAMPTZ,created_atTIMESTAMPTZDEFAULTCURRENT_TIMESTAMP,last_used_atTIMESTAMPTZ);-- Create function to generate API keyCREATEORREPLACEFUNCTIONgenerate_api_key(p_key_nameVARCHAR(100),p_user_idINTEGERDEFAULTNULL,p_permissionsJSONBDEFAULT'{}',p_rate_limit_per_minuteINTEGERDEFAULT100,p_expires_atTIMESTAMPTZDEFAULTNULL)RETURNSTEXTAS$$DECLAREapi_keyTEXT;key_hashVARCHAR(64);BEGIN-- Generate random API keyapi_key:=encode(gen_random_bytes(32),'hex');key_hash:=encode(digest(api_key,'sha256'),'hex');-- Store key hashINSERTINTOapi_keys(key_hash,key_name,user_id,permissions,rate_limit_per_minute,expires_at)VALUES(key_hash,p_key_name,p_user_id,p_permissions,p_rate_limit_per_minute,p_expires_at);RETURNapi_key;END;$$LANGUAGEplpgsql;-- Create function to validate API keyCREATEORREPLACEFUNCTIONvalidate_api_key(p_api_keyTEXT)RETURNSTABLE(is_validBOOLEAN,user_idINTEGER,permissionsJSONB,rate_limit_per_minuteINTEGER)AS$$DECLAREkey_hashVARCHAR(64);key_recordRECORD;BEGIN-- Hash the provided keykey_hash:=encode(digest(p_api_key,'sha256'),'hex');-- Look up keySELECTak.user_id,ak.permissions,ak.rate_limit_per_minuteINTOkey_recordFROMapi_keysakWHEREak.key_hash=key_hashANDak.is_active=TRUEAND(ak.expires_atISNULLORak.expires_at>CURRENT_TIMESTAMP);IFkey_recordISNULLTHENRETURNQUERYSELECTFALSE,NULL::INTEGER,'{}'::JSONB,0::INTEGER;ELSE-- Update last used timestampUPDATEapi_keysSETlast_used_at=CURRENT_TIMESTAMPWHEREkey_hash=key_hash;RETURNQUERYSELECTTRUE,key_record.user_id,key_record.permissions,key_record.rate_limit_per_minute;ENDIF;END;$$LANGUAGEplpgsql;
# api/postgres_api.pyfromfastapiimportFastAPI,HTTPException,Depends,Headerfromfastapi.securityimportHTTPBearer,HTTPAuthorizationCredentialsimportpsycopg2importjsonfromdatetimeimportdatetimefromtypingimportOptional,ListimportloggingclassPostgreSQLAPI:def__init__(self,connection_params):self.conn_params=connection_paramsself.setup_logging()defsetup_logging(self):"""Setup logging."""logging.basicConfig(level=logging.INFO)self.logger=logging.getLogger(__name__)defget_connection(self):"""Get database connection."""returnpsycopg2.connect(**self.conn_params)defvalidate_api_key(self,api_key:str):"""Validate API key."""conn=self.get_connection()try:withconn.cursor()ascur:cur.execute("SELECT * FROM validate_api_key(%s)",(api_key,))result=cur.fetchone()ifresultandresult[0]:# is_validreturn{'user_id':result[1],'permissions':result[2],'rate_limit':result[3]}else:returnNoneexceptExceptionase:self.logger.error(f"Error validating API key: {e}")returnNonefinally:conn.close()defget_users(self,limit:int=100,offset:int=0):"""Get users with pagination."""conn=self.get_connection()try:withconn.cursor()ascur:cur.execute(""" SELECT id, username, email, created_at FROM users ORDER BY created_at DESC LIMIT %s OFFSET %s """,(limit,offset))users=cur.fetchall()return[{'id':u[0],'username':u[1],'email':u[2],'created_at':u[3]}foruinusers]exceptExceptionase:self.logger.error(f"Error getting users: {e}")raiseHTTPException(status_code=500,detail="Internal server error")finally:conn.close()defget_user(self,user_id:int):"""Get user by ID."""conn=self.get_connection()try:withconn.cursor()ascur:cur.execute(""" SELECT id, username, email, created_at FROM users WHERE id = %s """,(user_id,))user=cur.fetchone()ifuser:return{'id':user[0],'username':user[1],'email':user[2],'created_at':user[3]}else:raiseHTTPException(status_code=404,detail="User not found")exceptHTTPException:raiseexceptExceptionase:self.logger.error(f"Error getting user: {e}")raiseHTTPException(status_code=500,detail="Internal server error")finally:conn.close()defcreate_user(self,user_data:dict):"""Create new user."""conn=self.get_connection()try:withconn.cursor()ascur:cur.execute(""" INSERT INTO users (username, email, password_hash) VALUES (%s, %s, %s) RETURNING id, username, email, created_at """,(user_data['username'],user_data['email'],user_data['password_hash']))user=cur.fetchone()conn.commit()return{'id':user[0],'username':user[1],'email':user[2],'created_at':user[3]}exceptExceptionase:conn.rollback()self.logger.error(f"Error creating user: {e}")raiseHTTPException(status_code=500,detail="Internal server error")finally:conn.close()defupdate_user(self,user_id:int,user_data:dict):"""Update user."""conn=self.get_connection()try:withconn.cursor()ascur:cur.execute(""" UPDATE users SET username = %s, email = %s, updated_at = CURRENT_TIMESTAMP WHERE id = %s RETURNING id, username, email, created_at """,(user_data['username'],user_data['email'],user_id))user=cur.fetchone()ifuser:conn.commit()return{'id':user[0],'username':user[1],'email':user[2],'created_at':user[3]}else:raiseHTTPException(status_code=404,detail="User not found")exceptHTTPException:raiseexceptExceptionase:conn.rollback()self.logger.error(f"Error updating user: {e}")raiseHTTPException(status_code=500,detail="Internal server error")finally:conn.close()defdelete_user(self,user_id:int):"""Delete user."""conn=self.get_connection()try:withconn.cursor()ascur:cur.execute("DELETE FROM users WHERE id = %s",(user_id,))ifcur.rowcount>0:conn.commit()return{'message':'User deleted successfully'}else:raiseHTTPException(status_code=404,detail="User not found")exceptHTTPException:raiseexceptExceptionase:conn.rollback()self.logger.error(f"Error deleting user: {e}")raiseHTTPException(status_code=500,detail="Internal server error")finally:conn.close()# FastAPI applicationapp=FastAPI(title="PostgreSQL API",version="1.0.0")security=HTTPBearer()api=PostgreSQLAPI({'host':'localhost','database':'production','user':'api_user','password':'api_password'})defget_current_user(credentials:HTTPAuthorizationCredentials=Depends(security)):"""Get current user from API key."""api_key=credentials.credentialsuser_info=api.validate_api_key(api_key)ifnotuser_info:raiseHTTPException(status_code=401,detail="Invalid API key")returnuser_info@app.get("/api/v1/users")asyncdefget_users(limit:int=100,offset:int=0,current_user:dict=Depends(get_current_user)):"""Get all users."""returnapi.get_users(limit,offset)@app.get("/api/v1/users/{user_id}")asyncdefget_user(user_id:int,current_user:dict=Depends(get_current_user)):"""Get user by ID."""returnapi.get_user(user_id)@app.post("/api/v1/users")asyncdefcreate_user(user_data:dict,current_user:dict=Depends(get_current_user)):"""Create new user."""returnapi.create_user(user_data)@app.put("/api/v1/users/{user_id}")asyncdefupdate_user(user_id:int,user_data:dict,current_user:dict=Depends(get_current_user)):"""Update user."""returnapi.update_user(user_id,user_data)@app.delete("/api/v1/users/{user_id}")asyncdefdelete_user(user_id:int,current_user:dict=Depends(get_current_user)):"""Delete user."""returnapi.delete_user(user_id)
-- Create rate limiting tableCREATETABLEapi_rate_limits(idSERIALPRIMARYKEY,api_key_hashVARCHAR(64)NOTNULL,endpoint_pathVARCHAR(200)NOTNULL,request_countINTEGERDEFAULT1,window_startTIMESTAMPTZDEFAULTCURRENT_TIMESTAMP,created_atTIMESTAMPTZDEFAULTCURRENT_TIMESTAMP);-- Create function to check rate limitCREATEORREPLACEFUNCTIONcheck_rate_limit(p_api_key_hashVARCHAR(64),p_endpoint_pathVARCHAR(200),p_rate_limit_per_minuteINTEGERDEFAULT100)RETURNSBOOLEANAS$$DECLAREcurrent_countINTEGER;window_startTIMESTAMPTZ;BEGIN-- Get current window startwindow_start:=date_trunc('minute',CURRENT_TIMESTAMP);-- Get current request countSELECTCOALESCE(SUM(request_count),0)INTOcurrent_countFROMapi_rate_limitsWHEREapi_key_hash=p_api_key_hashANDendpoint_path=p_endpoint_pathANDwindow_start>=window_start;-- Check if limit exceededIFcurrent_count>=p_rate_limit_per_minuteTHENRETURNFALSE;ENDIF;-- Record requestINSERTINTOapi_rate_limits(api_key_hash,endpoint_path,window_start)VALUES(p_api_key_hash,p_endpoint_path,window_start)ONCONFLICT(api_key_hash,endpoint_path,window_start)DOUPDATESETrequest_count=api_rate_limits.request_count+1;RETURNTRUE;END;$$LANGUAGEplpgsql;
-- Create function to validate inputCREATEORREPLACEFUNCTIONvalidate_api_input(p_input_dataJSONB,p_validation_schemaJSONB)RETURNSBOOLEANAS$$DECLARErequired_fieldsTEXT[];field_nameTEXT;field_valueJSONB;BEGIN-- Check required fieldsrequired_fields:=ARRAY(SELECTjsonb_array_elements_text(p_validation_schema->'required'));FORfield_nameINSELECTunnest(required_fields)LOOPfield_value:=p_input_data->field_name;IFfield_valueISNULLORfield_value='null'THENRAISEEXCEPTION'Required field % is missing',field_name;ENDIF;ENDLOOP;-- Validate field typesIFp_validation_schema?'properties'THENFORfield_name,field_schemaINSELECTkey,valueFROMjsonb_each(p_validation_schema->'properties')LOOPfield_value:=p_input_data->field_name;IFfield_valueISNOTNULLANDfield_value!='null'THEN-- Validate string fieldsIFfield_schema->>'type'='string'ANDjsonb_typeof(field_value)!='string'THENRAISEEXCEPTION'Field % must be a string',field_name;ENDIF;-- Validate integer fieldsIFfield_schema->>'type'='integer'ANDjsonb_typeof(field_value)!='number'THENRAISEEXCEPTION'Field % must be an integer',field_name;ENDIF;-- Validate email formatIFfield_schema->>'format'='email'THENIFNOT(field_value#>>'{}'~*'^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$')THENRAISEEXCEPTION'Field % must be a valid email',field_name;ENDIF;ENDIF;ENDIF;ENDLOOP;ENDIF;RETURNTRUE;END;$$LANGUAGEplpgsql;
# api/openapi_generator.pyimportpsycopg2importjsonfromtypingimportDict,ListclassOpenAPIGenerator:def__init__(self,connection_params):self.conn_params=connection_paramsdefgenerate_openapi_spec(self):"""Generate OpenAPI specification from database."""conn=psycopg2.connect(**self.conn_params)try:withconn.cursor()ascur:# Get API endpointscur.execute(""" SELECT endpoint_path, http_method, description, parameters, response_schema, authentication_required FROM api_endpoints ORDER BY endpoint_path """)endpoints=cur.fetchall()# Generate OpenAPI specopenapi_spec={"openapi":"3.0.0","info":{"title":"PostgreSQL API","version":"1.0.0","description":"API for PostgreSQL database operations"},"servers":[{"url":"https://api.example.com","description":"Production server"}],"security":[{"ApiKeyAuth":[]}],"paths":self.generate_paths(endpoints),"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"Authorization"}}}}returnopenapi_specexceptExceptionase:print(f"Error generating OpenAPI spec: {e}")return{}finally:conn.close()defgenerate_paths(self,endpoints):"""Generate OpenAPI paths from endpoints."""paths={}forendpoint_path,http_method,description,parameters,response_schema,auth_requiredinendpoints:ifendpoint_pathnotinpaths:paths[endpoint_path]={}paths[endpoint_path][http_method.lower()]={"summary":description,"security":[{"ApiKeyAuth":[]}]ifauth_requiredelse[],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":response_schema}}},"401":{"description":"Unauthorized"},"404":{"description":"Not found"},"500":{"description":"Internal server error"}}}returnpaths
-- Create API metrics tableCREATETABLEapi_metrics(idSERIALPRIMARYKEY,endpoint_pathVARCHAR(200)NOTNULL,http_methodVARCHAR(10)NOTNULL,response_time_msINTEGERNOTNULL,status_codeINTEGERNOTNULL,api_key_hashVARCHAR(64),user_idINTEGER,request_size_bytesINTEGER,response_size_bytesINTEGER,created_atTIMESTAMPTZDEFAULTCURRENT_TIMESTAMP);-- Create function to record API metricsCREATEORREPLACEFUNCTIONrecord_api_metrics(p_endpoint_pathVARCHAR(200),p_http_methodVARCHAR(10),p_response_time_msINTEGER,p_status_codeINTEGER,p_api_key_hashVARCHAR(64)DEFAULTNULL,p_user_idINTEGERDEFAULTNULL,p_request_size_bytesINTEGERDEFAULTNULL,p_response_size_bytesINTEGERDEFAULTNULL)RETURNSVOIDAS$$BEGININSERTINTOapi_metrics(endpoint_path,http_method,response_time_ms,status_code,api_key_hash,user_id,request_size_bytes,response_size_bytes)VALUES(p_endpoint_path,p_http_method,p_response_time_ms,p_status_code,p_api_key_hash,p_user_id,p_request_size_bytes,p_response_size_bytes);END;$$LANGUAGEplpgsql;-- Create function to get API metricsCREATEORREPLACEFUNCTIONget_api_metrics(p_start_dateTIMESTAMPTZDEFAULTCURRENT_TIMESTAMP-INTERVAL'1 hour',p_end_dateTIMESTAMPTZDEFAULTCURRENT_TIMESTAMP)RETURNSTABLE(endpoint_pathVARCHAR(200),http_methodVARCHAR(10),request_countBIGINT,avg_response_timeNUMERIC,max_response_timeINTEGER,min_response_timeINTEGER,success_rateNUMERIC,error_countBIGINT)AS$$BEGINRETURNQUERYSELECTam.endpoint_path,am.http_method,COUNT(*)asrequest_count,AVG(am.response_time_ms)asavg_response_time,MAX(am.response_time_ms)asmax_response_time,MIN(am.response_time_ms)asmin_response_time,(COUNT(*)FILTER(WHEREam.status_code<400)::NUMERIC/COUNT(*)::NUMERIC*100)assuccess_rate,COUNT(*)FILTER(WHEREam.status_code>=400)aserror_countFROMapi_metricsamWHEREam.created_atBETWEENp_start_dateANDp_end_dateGROUPBYam.endpoint_path,am.http_methodORDERBYrequest_countDESC;END;$$LANGUAGEplpgsql;
-- 1. Register API endpointsSELECTregister_api_endpoint('/api/v1/users','GET','Get all users');-- 2. Generate API keySELECTgenerate_api_key('my_api_key',1,'{"read": true, "write": true}');-- 3. Validate API keySELECT*FROMvalidate_api_key('your_api_key_here');-- 4. Check rate limitsSELECTcheck_rate_limit('key_hash','/api/v1/users',100);-- 5. Record API metricsSELECTrecord_api_metrics('/api/v1/users','GET',150,200);
# Complete PostgreSQL API development setupdefsetup_postgresql_api_development():# 1. RESTful API design# 2. API authentication# 3. API implementation# 4. API security# 5. Input validation# 6. API documentation# 7. API monitoring# 8. Rate limitingprint("PostgreSQL API development setup complete!")