CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl-labs/api-documentation

API documentation with OpenAPI/Swagger — endpoint descriptions, request/response

66

1.06x
Quality

57%

Does it follow best practices?

Impact

100%

1.06x

Average score across 3 eval scenarios

SecuritybySnyk

Passed

No known issues

Overview
Quality
Evals
Security
Files

task.mdevals/scenario-3/

Document the Feedback Collection API

Problem Description

A small internal tooling team has a lightweight Python HTTP server that collects product feedback from employees. It was written quickly using Python's standard library (http.server) without any framework, so there is no auto-generated documentation. New developers joining the team, and a third-party tool that needs to integrate with it, are blocked because there is no reference describing how to call the API.

Your job is to write clear, comprehensive API documentation for this service. The documentation should be good enough that a developer who has never seen the code can integrate against it without asking any questions.

Output Specification

Produce a file named API.md containing the full API reference for the service described below.

The documentation should cover every endpoint thoroughly enough to allow a developer to make correct HTTP requests without reading the source code.

Input Files

The following file is provided as input. Extract it before beginning.

=============== FILE: feedback_server.py =============== #!/usr/bin/env python3 """Minimal feedback collection HTTP server (no framework)."""

import json from http.server import BaseHTTPRequestHandler, HTTPServer from urllib.parse import urlparse, parse_qs import uuid from datetime import datetime

FEEDBACKS = {}

class FeedbackHandler(BaseHTTPRequestHandler):

def do_GET(self):
    parsed = urlparse(self.path)
    parts = parsed.path.strip('/').split('/')

    # GET /feedback  - list all feedback, optional ?product=X&limit=N
    if parts == ['feedback']:
        qs = parse_qs(parsed.query)
        product_filter = qs.get('product', [None])[0]
        try:
            limit = int(qs.get('limit', [50])[0])
        except ValueError:
            self._send(400, {"error": "limit must be an integer"})
            return
        items = list(FEEDBACKS.values())
        if product_filter:
            items = [i for i in items if i['product'] == product_filter]
        self._send(200, {"items": items[:limit], "total": len(items)})

    # GET /feedback/{id}  - get a single feedback entry
    elif len(parts) == 2 and parts[0] == 'feedback':
        fid = parts[1]
        entry = FEEDBACKS.get(fid)
        if entry is None:
            self._send(404, {"error": "Feedback entry not found"})
        else:
            self._send(200, entry)

    # GET /health
    elif parts == ['health']:
        self._send(200, {"status": "ok"})

    else:
        self._send(404, {"error": "Not found"})

def do_POST(self):
    parsed = urlparse(self.path)
    parts = parsed.path.strip('/').split('/')

    # POST /feedback  - submit new feedback
    if parts == ['feedback']:
        length = int(self.headers.get('Content-Length', 0))
        if length == 0:
            self._send(400, {"error": "Request body is required"})
            return
        try:
            body = json.loads(self.rfile.read(length))
        except json.JSONDecodeError:
            self._send(400, {"error": "Invalid JSON"})
            return

        product = body.get('product')
        message = body.get('message')
        rating = body.get('rating')         # optional, integer 1-5
        author_email = body.get('author_email')  # optional

        if not product or not message:
            self._send(400, {"error": "product and message are required"})
            return
        if rating is not None:
            if not isinstance(rating, int) or not (1 <= rating <= 5):
                self._send(400, {"error": "rating must be an integer between 1 and 5"})
                return

        entry = {
            "id": str(uuid.uuid4()),
            "product": product,
            "message": message,
            "rating": rating,
            "author_email": author_email,
            "created_at": datetime.utcnow().isoformat() + "Z"
        }
        FEEDBACKS[entry['id']] = entry
        self._send(201, entry)

    # POST /feedback/{id}/resolve  - mark a feedback entry as resolved
    elif len(parts) == 3 and parts[0] == 'feedback' and parts[2] == 'resolve':
        fid = parts[1]
        entry = FEEDBACKS.get(fid)
        if entry is None:
            self._send(404, {"error": "Feedback entry not found"})
            return
        entry['resolved'] = True
        entry['resolved_at'] = datetime.utcnow().isoformat() + "Z"
        self._send(200, entry)

    else:
        self._send(404, {"error": "Not found"})

def do_DELETE(self):
    parsed = urlparse(self.path)
    parts = parsed.path.strip('/').split('/')

    # DELETE /feedback/{id}  - delete a feedback entry
    if len(parts) == 2 and parts[0] == 'feedback':
        fid = parts[1]
        if fid not in FEEDBACKS:
            self._send(404, {"error": "Feedback entry not found"})
            return
        del FEEDBACKS[fid]
        self._send(204, None)
    else:
        self._send(404, {"error": "Not found"})

def _send(self, status, body):
    self.send_response(status)
    self.send_header('Content-Type', 'application/json')
    self.end_headers()
    if body is not None:
        self.wfile.write(json.dumps(body).encode())

def log_message(self, fmt, *args):
    pass  # suppress default logging

if name == 'main': server = HTTPServer(('0.0.0.0', 8080), FeedbackHandler) print("Listening on http://0.0.0.0:8080") server.serve_forever()

evals

tile.json