File size: 6,337 Bytes
d81bb6a f1364d9 e9194d7 097cbf3 d81bb6a 097cbf3 d81bb6a 01ac14b f1364d9 097cbf3 9f255f9 097cbf3 d81bb6a 097cbf3 d81bb6a 097cbf3 f1364d9 097cbf3 d81bb6a 097cbf3 4831f3a 097cbf3 4831f3a 097cbf3 4831f3a 097cbf3 f1364d9 097cbf3 efb2d13 097cbf3 1f44040 f1364d9 e7ff015 f1364d9 e849906 f1364d9 6398b8e f1364d9 09341e0 f1364d9 097cbf3 c39b33d | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 | # -*- coding: utf-8 -*-
import os
import sqlite3
import json
import requests
from flask import Flask, request, jsonify, g
app = Flask(__name__)
@app.after_request
def add_cors_headers(response):
response.headers['Access-Control-Allow-Origin'] = '*'
response.headers['Access-Control-Allow-Methods'] = 'GET,POST,PUT,DELETE,OPTIONS'
response.headers['Access-Control-Allow-Headers'] = 'Content-Type,Authorization'
return response
# ----------------------------------------------------------------------
# Database utilities (unchanged)
# ----------------------------------------------------------------------
DATABASE = os.path.join(os.path.dirname(__file__), "tasks.db")
def get_db():
db = getattr(g, "_database", None)
if db is None:
db = g._database = sqlite3.connect(DATABASE, check_same_thread=False)
db.row_factory = sqlite3.Row
return db
def init_db():
conn = sqlite3.connect(DATABASE)
cursor = conn.cursor()
cursor.execute(
"""
CREATE TABLE IF NOT EXISTS tasks (
id INTEGER PRIMARY KEY AUTOINCREMENT,
title TEXT NOT NULL,
completed INTEGER NOT NULL DEFAULT 0
)
"""
)
conn.commit()
conn.close()
@app.teardown_appcontext
def close_connection(exception):
db = getattr(g, "_database", None)
if db is not None:
db.close()
# ----------------------------------------------------------------------
# Existing task endpoints (unchanged)
# ----------------------------------------------------------------------
@app.route("/tasks", methods=["GET"])
def list_tasks():
db = get_db()
cursor = db.execute("SELECT id, title, completed FROM tasks")
tasks = [
{"id": row["id"], "title": row["title"], "completed": bool(row["completed"])}
for row in cursor.fetchall()
]
return jsonify(tasks)
@app.route("/tasks", methods=["POST"])
def create_task():
data = request.get_json()
title = data.get("title")
if not title:
return jsonify({"error": "title is required"}), 400
db = get_db()
cursor = db.execute(
"INSERT INTO tasks (title, completed) VALUES (?, ?)",
(title, 0),
)
db.commit()
task_id = cursor.lastrowid
return jsonify({"id": task_id, "title": title, "completed": False}), 201
@app.route("/tasks/<int:task_id>", methods=["PUT"])
def update_task(task_id):
data = request.get_json()
title = data.get("title")
completed = data.get("completed")
if title is None and completed is None:
return jsonify({"error": "nothing to update"}), 400
db = get_db()
if title is not None:
db.execute("UPDATE tasks SET title = ? WHERE id = ?", (title, task_id))
if completed is not None:
db.execute(
"UPDATE tasks SET completed = ? WHERE id = ?",
(1 if completed else 0, task_id),
)
db.commit()
return jsonify({"id": task_id, "title": title, "completed": completed})
@app.route("/tasks/<int:task_id>", methods=["DELETE"])
def delete_task(task_id):
db = get_db()
db.execute("DELETE FROM tasks WHERE id = ?", (task_id,))
db.commit()
return "", 204
# ----------------------------------------------------------------------
# Health endpoints (unchanged)
# ----------------------------------------------------------------------
@app.route("/", methods=["GET"])
@app.route("/test", methods=["GET"])
def index():
return "Task API is running."
@app.route("/ping", methods=["GET"])
def ping():
return "pong", 200
# ----------------------------------------------------------------------
# New: Generic API connector
# ----------------------------------------------------------------------
@app.route("/api/connector", methods=["GET", "POST"])
def api_connector():
"""
Expects a JSON payload with the following fields:
{
"url": "https://example.com/endpoint",
"method": "GET|POST|PUT|DELETE|PATCH",
"headers": {"Authorization": "Bearer ...", ...}, # optional
"params": {"q": "search"}, # optional, for query string
"json": {"key": "value"} # optional, for JSON body
}
The endpoint forwards the request to the target API and returns
the raw response (status code, headers and JSON body if possible).
"""
payload = request.get_json()
if not payload:
return jsonify({"error": "invalid json payload"}), 400
url = payload.get("url")
# placeholder replacement removed
method = payload.get("method", "GET").upper()
headers = payload.get("headers", {})
params = payload.get("params", {})
json_body = payload.get("json", None)
if not url:
return jsonify({"error": "url is required"}), 400
# Optional: inject a default API key from environment if not provided
default_key = os.environ.get("DEFAULT_API_KEY")
if default_key and "Authorization" not in headers:
headers["Authorization"] = f"Bearer {default_key}"
try:
response = requests.request(
method=method,
url=url,
headers=headers,
params=params,
json=json_body,
timeout=30
)
# Do not raise for HTTP errors; return the response as is
except requests.RequestException as e:
return jsonify({"error": "request failed", "details": str(e)}), 502
# Try to parse JSON, fallback to raw text
try:
resp_content = response.json()
except ValueError:
resp_content = response.text
result = {
"status_code": response.status_code,
"headers": dict(response.headers),
"content": resp_content
}
return jsonify(result), response.status_code
# ----------------------------------------------------------------------
# Error handling (unchanged)
# ----------------------------------------------------------------------
@app.errorhandler(404)
def not_found(e):
return jsonify({"error": "not found"}), 404
# ----------------------------------------------------------------------
# Main entry point (unchanged)
# ----------------------------------------------------------------------
if __name__ == "__main__":
if not os.path.isfile(DATABASE):
init_db()
app.run(host="0.0.0.0", port=7860) |