{"id":35049905,"url":"https://github.com/getevo/go-pdf","last_synced_at":"2026-05-23T07:04:03.946Z","repository":{"id":321132544,"uuid":"1084612194","full_name":"getevo/go-pdf","owner":"getevo","description":"Generate pdf from html on the fly!","archived":false,"fork":false,"pushed_at":"2025-10-28T00:04:20.000Z","size":34,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-10-28T01:21:59.081Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/getevo.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-10-27T23:16:37.000Z","updated_at":"2025-10-28T00:04:24.000Z","dependencies_parsed_at":"2025-10-28T01:33:20.998Z","dependency_job_id":null,"html_url":"https://github.com/getevo/go-pdf","commit_stats":null,"previous_names":["getevo/go-pdf"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/getevo/go-pdf","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/getevo%2Fgo-pdf","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/getevo%2Fgo-pdf/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/getevo%2Fgo-pdf/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/getevo%2Fgo-pdf/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/getevo","download_url":"https://codeload.github.com/getevo/go-pdf/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/getevo%2Fgo-pdf/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28076675,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-12-27T02:00:05.897Z","response_time":58,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-12-27T09:11:44.902Z","updated_at":"2025-12-27T09:11:46.385Z","avatar_url":"https://github.com/getevo.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# go-pdf Service\n\n[![Build and Publish Docker Image](https://github.com/getevo/go-pdf/actions/workflows/docker-publish.yml/badge.svg)](https://github.com/getevo/go-pdf/actions/workflows/docker-publish.yml)\n[![Docker Image](https://img.shields.io/badge/docker-ghcr.io%2Fgetevo%2Fgo--pdf-blue)](https://ghcr.io/getevo/go-pdf)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nA high-performance, concurrent HTML to PDF conversion service built with Go and the [getevo/evo/v2](https://github.com/getevo/evo) framework. This service provides a simple REST API to convert HTML (with CSS and JavaScript) into PDF documents using wkhtmltopdf.\n\n**Docker Image**: `ghcr.io/getevo/go-pdf:latest`\n\n## Why This Service Matters\n\nImagine you need to generate an invoice or receipt in your application. What do you do?\n\n**Option 1**: Create messy, unreadable code embedded in your application that requires recompiling the entire app for each design change?\n\n**Option 2**: Use an internal service that takes an HTML template and generates PDFs for you?\n\n**This is why go-pdf matters!** It lets you painlessly generate any PDF with your custom style. Just design your document as HTML/CSS (like you would for a webpage), send it to this service, and get back a professional PDF. No more wrestling with complex PDF libraries or maintaining rigid PDF generation code in your main application.\n\n### The Developer Experience\n\n- 🎨 **Design PDFs like webpages**: Use familiar HTML/CSS\n- 🔄 **Iterate quickly**: Change designs without recompiling your app\n- 📦 **Keep it separate**: PDF generation logic stays out of your main codebase\n- 🚀 **Scale independently**: Deploy PDF service separately from your application\n- 🎯 **Reuse templates**: Same HTML template for web display and PDF generation\n\n## Features\n\n- **Fast \u0026 Efficient**: Built with Go for high performance and low memory footprint\n- **Concurrent Processing**: Handles multiple concurrent PDF generation requests\n- **REST API**: Simple POST endpoint for PDF generation with configurable options\n- **Automatic Cleanup**: Automatically removes cached files older than 1 hour\n- **Docker Support**: Multi-stage Dockerfile for minimal image size\n- **No Database Required**: Lightweight service with no database dependencies\n- **Framework-based**: Uses getevo/evo/v2 framework for robust HTTP handling\n- **Flexible Configuration**: Control page size, quality, JavaScript execution, and more via query parameters\n\n## What is go-pdf Service?\n\ngo-pdf is a microservice that converts HTML documents (including CSS and JavaScript) into PDF files. It uses wkhtmltopdf under the hood, which renders HTML using the WebKit engine and generates high-quality PDF output.\n\nThe service temporarily stores HTML files and generated PDFs in a cache directory, then automatically cleans up files older than 1 hour to prevent disk space issues.\n\n### Use Cases\n\n- Generate invoices and receipts from HTML templates\n- Create PDF reports from web content\n- Convert HTML emails to PDF\n- Generate printable documents from web applications\n- Batch PDF generation from dynamic HTML content\n\n## How to Use go-pdf\n\n### API Endpoints\n\n#### **POST /api/v1/generate**\n\nConverts HTML content to PDF and returns the generated PDF file.\n\n#### Request\n\n- **Method**: POST\n- **Content-Type**: text/html\n- **Body**: Raw HTML content (string)\n\n#### Response\n\n- **Content-Type**: application/pdf\n- **Headers**:\n  - `Content-Disposition`: attachment; filename=`{hash}`.pdf\n  - `X-Generated-At`: Timestamp of generation\n- **Body**: PDF file (binary)\n\n#### Query Parameters\n\nAll query parameters are optional and allow you to control the PDF generation behavior:\n\n| Parameter | Type | Default | Max | Description |\n|-----------|------|---------|-----|-------------|\n| `js_delay` | integer | `0` | `5000` | JavaScript delay in milliseconds before rendering. Use this if your HTML contains JavaScript that needs time to execute |\n| `image_dpi` | integer | - | - | Set the DPI for images (e.g., `300` for high quality) |\n| `image_quality` | integer | - | `100` | JPEG image quality (0-100, where 100 is best quality) |\n| `lowquality` | boolean | `false` | - | Use `true` to generate lower quality PDFs (smaller file size) |\n| `page_height` | string | - | - | Page height (e.g., `297mm`, `11.69in`) |\n| `page_width` | string | - | - | Page width (e.g., `210mm`, `8.27in`) |\n| `page_size` | string | - | - | Page size preset (e.g., `A4`, `Letter`, `Legal`) |\n| `enable_forms` | boolean | `false` | - | Use `true` to enable HTML forms in the PDF |\n| `enable_smart_shrinking` | boolean | `false` | - | Use `true` to enable smart content shrinking to fit page |\n| `margin_top` | string | - | - | Top margin (e.g., `10mm`, `0.5in`) |\n| `margin_bottom` | string | - | - | Bottom margin (e.g., `10mm`, `0.5in`) |\n| `margin_left` | string | - | - | Left margin (e.g., `10mm`, `0.5in`) |\n| `margin_right` | string | - | - | Right margin (e.g., `10mm`, `0.5in`) |\n| `orientation` | string | - | - | Page orientation: `portrait` or `landscape` |\n\n**Example with query parameters:**\n\n```bash\n# Generate PDF with JavaScript delay and custom page size\ncurl -X POST \"http://localhost:8080/api/v1/generate?js_delay=2000\u0026page_size=A4\u0026image_quality=95\" \\\n  -H \"Content-Type: text/html\" \\\n  -d '\u003chtml\u003e\u003cbody\u003e\u003ch1\u003eHigh Quality PDF\u003c/h1\u003e\u003c/body\u003e\u003c/html\u003e' \\\n  -o output.pdf\n```\n\n```bash\n# Generate PDF with custom page dimensions\ncurl -X POST \"http://localhost:8080/api/v1/generate?page_width=210mm\u0026page_height=297mm\" \\\n  -H \"Content-Type: text/html\" \\\n  -d '\u003chtml\u003e\u003cbody\u003e\u003ch1\u003eCustom Size PDF\u003c/h1\u003e\u003c/body\u003e\u003c/html\u003e' \\\n  -o custom.pdf\n```\n\n```bash\n# Generate low quality PDF (smaller file size)\ncurl -X POST \"http://localhost:8080/api/v1/generate?lowquality=true\u0026image_quality=50\" \\\n  -H \"Content-Type: text/html\" \\\n  -d '\u003chtml\u003e\u003cbody\u003e\u003ch1\u003eCompressed PDF\u003c/h1\u003e\u003c/body\u003e\u003c/html\u003e' \\\n  -o compressed.pdf\n```\n\n```bash\n# Generate landscape PDF with custom margins\ncurl -X POST \"http://localhost:8080/api/v1/generate?orientation=landscape\u0026margin_top=20mm\u0026margin_bottom=20mm\u0026margin_left=15mm\u0026margin_right=15mm\" \\\n  -H \"Content-Type: text/html\" \\\n  -d '\u003chtml\u003e\u003cbody\u003e\u003ch1\u003eLandscape Report\u003c/h1\u003e\u003cp\u003eThis is a wide format document.\u003c/p\u003e\u003c/body\u003e\u003c/html\u003e' \\\n  -o landscape.pdf\n```\n\n#### Example Usage with curl\n\n```bash\ncurl -X POST http://localhost:8080/api/v1/generate \\\n  -H \"Content-Type: text/html\" \\\n  -d '\u003chtml\u003e\u003cbody\u003e\u003ch1\u003eHello PDF!\u003c/h1\u003e\u003c/body\u003e\u003c/html\u003e' \\\n  -o output.pdf\n```\n\n**With styled HTML:**\n\n```bash\ncurl -X POST http://localhost:8080/api/v1/generate \\\n  -H \"Content-Type: text/html\" \\\n  -d '\u003c!DOCTYPE html\u003e\n\u003chtml\u003e\n\u003chead\u003e\n  \u003ctitle\u003eTest\u003c/title\u003e\n  \u003cstyle\u003e\n    body { font-family: Arial; margin: 40px; }\n    h1 { color: #333; }\n  \u003c/style\u003e\n\u003c/head\u003e\n\u003cbody\u003e\n  \u003ch1\u003eHello PDF!\u003c/h1\u003e\n  \u003cp\u003eThis is a test document.\u003c/p\u003e\n\u003c/body\u003e\n\u003c/html\u003e' \\\n  -o output.pdf\n```\n\n#### Example Usage with JavaScript/Fetch\n\n```javascript\nconst html = `\n\u003c!DOCTYPE html\u003e\n\u003chtml\u003e\n\u003chead\u003e\n    \u003ctitle\u003eInvoice\u003c/title\u003e\n    \u003cstyle\u003e\n        body { font-family: Arial, sans-serif; }\n        .header { background-color: #4CAF50; color: white; padding: 20px; }\n    \u003c/style\u003e\n\u003c/head\u003e\n\u003cbody\u003e\n    \u003cdiv class=\"header\"\u003e\n        \u003ch1\u003eInvoice #12345\u003c/h1\u003e\n    \u003c/div\u003e\n    \u003cp\u003eThank you for your purchase!\u003c/p\u003e\n\u003c/body\u003e\n\u003c/html\u003e\n`;\n\nfetch('http://localhost:8080/api/v1/generate', {\n    method: 'POST',\n    headers: {\n        'Content-Type': 'text/html'\n    },\n    body: html\n})\n.then(response =\u003e response.blob())\n.then(blob =\u003e {\n    const url = window.URL.createObjectURL(blob);\n    const a = document.createElement('a');\n    a.href = url;\n    a.download = 'invoice.pdf';\n    a.click();\n});\n```\n\n#### Example Usage with Python\n\n```python\nimport requests\n\nhtml_content = \"\"\"\n\u003c!DOCTYPE html\u003e\n\u003chtml\u003e\n\u003chead\u003e\n    \u003ctitle\u003eReport\u003c/title\u003e\n    \u003cstyle\u003e\n        body { font-family: Arial, sans-serif; margin: 40px; }\n        h1 { color: #333; }\n    \u003c/style\u003e\n\u003c/head\u003e\n\u003cbody\u003e\n    \u003ch1\u003eMonthly Report\u003c/h1\u003e\n    \u003cp\u003eThis is the monthly report generated on demand.\u003c/p\u003e\n\u003c/body\u003e\n\u003c/html\u003e\n\"\"\"\n\nresponse = requests.post(\n    'http://localhost:8080/api/v1/generate',\n    headers={'Content-Type': 'text/html'},\n    data=html_content\n)\n\nif response.status_code == 200:\n    with open('report.pdf', 'wb') as f:\n        f.write(response.content)\n    print('PDF generated successfully!')\nelse:\n    print(f'Error: {response.status_code}')\n```\n\n#### **GET /api/v1/qrcode**\n\nGenerates QR codes in various formats (SVG by default, or PNG). Supports multiple QR code types including URLs, WiFi networks, contact cards (vCard/MeCard), geographic coordinates, calendar events, and more.\n\n#### Request\n\n- **Method**: GET\n- **Parameters**: All parameters are passed via query string\n\n#### Query Parameters\n\n| Parameter | Type | Required | Default | Description |\n|-----------|------|----------|---------|-------------|\n| `type` | string | No | `text` | QR code type: `text`, `url`, `wifi`, `email`, `sms`, `phone`, `vcard`, `mecard`, `geo`, `event`, `deeplink` |\n| `content` | string | Yes* | - | Main content (varies by type) |\n| `format` | string | No | `svg` | Output format: `png` or `svg` |\n| `size` | integer | No | `256` | Image size in pixels (64-2048, sets both width and height) |\n| `password` | string | No | - | For WiFi type: network password |\n| `latitude` | float | No | - | For geo type: latitude coordinate |\n| `longitude` | float | No | - | For geo type: longitude coordinate |\n| `label` | string | No | - | For geo type: location label/name |\n| `first_name` | string | No | - | For vcard/mecard: first name |\n| `last_name` | string | No | - | For vcard/mecard: last name |\n| `organization` | string | No | - | For vcard/mecard: organization name |\n| `phone` | string | No | - | For vcard/mecard/phone/sms: phone number |\n| `email` | string | No | - | For vcard/mecard/email: email address |\n| `address` | string | No | - | For vcard/mecard: physical address |\n| `website` | string | No | - | For vcard: website URL |\n| `note` | string | No | - | For vcard: additional notes |\n| `summary` | string | No | - | For event: event title |\n| `description` | string | No | - | For event: event description |\n| `location` | string | No | - | For event: event location |\n| `start_time` | string | No | - | For event: start time (RFC3339 or YYYYMMDDTHHMMSS) |\n| `end_time` | string | No | - | For event: end time (RFC3339 or YYYYMMDDTHHMMSS) |\n| `subject` | string | No | - | For email type: email subject (query parameter) |\n| `body` | string | No | - | For email/sms type: message body (query parameter) |\n\n\\* Required for most types, except vcard/mecard (where name fields can be used) and geo (where lat/lng can be used)\n\n#### Response\n\n- **Content-Type**: `image/svg+xml` (default) or `image/png`\n- **Headers**:\n  - `Content-Disposition`: inline; filename=`qrcode-{type}.{format}`\n  - `X-QR-Type`: The QR code type that was generated\n  - `X-QR-Format`: The output format (png or svg)\n  - `X-Generated-At`: Timestamp (RFC3339)\n- **Body**: SVG or PNG image file\n\n#### QR Code Types\n\n1. **Text/Plaintext** (`type=text`): Plain text QR code\n2. **URL** (`type=url`): Web URLs (auto-adds https:// if missing)\n3. **WiFi** (`type=wifi`): WiFi network credentials (requires `content` as SSID, optional `password`)\n4. **Email** (`type=email`): Email addresses (supports `subject` and `body` query parameters)\n5. **SMS** (`type=sms`): SMS messages (supports `body` query parameter)\n6. **Phone** (`type=phone`): Phone numbers for dialing\n7. **vCard** (`type=vcard`): Contact cards in vCard 3.0 format\n8. **MeCard** (`type=mecard`): Simplified contact format\n9. **Geo Coordinates** (`type=geo`): Geographic coordinates (use `latitude`/`longitude` or `content` as \"lat,lng\")\n10. **Event** (`type=event`): Calendar events in iCalendar format\n11. **Deep Link** (`type=deeplink`): App deep links (custom URL schemes)\n\n#### Examples\n\n**SVG QR Code (default):**\n```bash\ncurl \"http://localhost:8080/api/v1/qrcode?type=text\u0026content=Hello%20World\u0026size=256\" \\\n  -o qrcode.svg\n```\n\n**PNG QR Code with custom size:**\n```bash\ncurl \"http://localhost:8080/api/v1/qrcode?type=url\u0026content=https://www.google.com\u0026format=png\u0026size=512\" \\\n  -o qrcode.png\n```\n\n**WiFi QR Code:**\n```bash\ncurl \"http://localhost:8080/api/v1/qrcode?type=wifi\u0026content=MyNetwork\u0026password=MyPassword123\" \\\n  -o wifi-qr.svg\n```\n\n**vCard QR Code:**\n```bash\ncurl \"http://localhost:8080/api/v1/qrcode?type=vcard\u0026first_name=John\u0026last_name=Doe\u0026email=john@example.com\u0026phone=%2B1234567890\u0026organization=Example%20Corp\" \\\n  -o contact.svg\n```\n\n**Geo Coordinates QR Code:**\n```bash\ncurl \"http://localhost:8080/api/v1/qrcode?type=geo\u0026latitude=40.7128\u0026longitude=-74.0060\u0026label=New%20York%20City\" \\\n  -o location.svg\n```\n\n**JavaScript Example:**\n```javascript\n// Generate SVG QR code (default)\nconst url = 'http://localhost:8080/api/v1/qrcode?type=url\u0026content=https://example.com\u0026size=256';\nfetch(url)\n  .then(response =\u003e response.blob())\n  .then(blob =\u003e {\n    const url = window.URL.createObjectURL(blob);\n    const img = document.createElement('img');\n    img.src = url;\n    document.body.appendChild(img);\n  });\n\n// Generate PNG QR code\nconst pngUrl = 'http://localhost:8080/api/v1/qrcode?type=text\u0026content=Hello\u0026format=png\u0026size=512';\nfetch(pngUrl)\n  .then(response =\u003e response.blob())\n  .then(blob =\u003e {\n    const url = window.URL.createObjectURL(blob);\n    const a = document.createElement('a');\n    a.href = url;\n    a.download = 'qrcode.png';\n    a.click();\n  });\n```\n\n**PowerShell Example:**\n```powershell\n# SVG QR code (default)\nInvoke-RestMethod -Uri \"http://localhost:8080/api/v1/qrcode?type=text\u0026content=Hello%20World\u0026size=256\" `\n  -Method Get -OutFile \"qrcode.svg\"\n\n# PNG QR code with size 512\nInvoke-RestMethod -Uri \"http://localhost:8080/api/v1/qrcode?type=url\u0026content=https://example.com\u0026format=png\u0026size=512\" `\n  -Method Get -OutFile \"qrcode.png\"\n```\n\n**Python Example:**\n```python\nimport requests\n\n# SVG QR code (default)\nresponse = requests.get(\n    'http://localhost:8080/api/v1/qrcode',\n    params={\n        'type': 'text',\n        'content': 'Hello World',\n        'size': 256\n    }\n)\nwith open('qrcode.svg', 'wb') as f:\n    f.write(response.content)\n\n# PNG QR code\nresponse = requests.get(\n    'http://localhost:8080/api/v1/qrcode',\n    params={\n        'type': 'url',\n        'content': 'https://example.com',\n        'format': 'png',\n        'size': 512\n    }\n)\nwith open('qrcode.png', 'wb') as f:\n    f.write(response.content)\n```\n\n#### **GET /health**\n\nHealth check endpoint for monitoring service status and readiness.\n\n**Response (HTTP 200 - Healthy):**\n\n```json\n{\n  \"status\": \"healthy\",\n  \"service\": \"go-pdf\",\n  \"wkhtmltopdf\": \"wkhtmltopdf 0.12.6 (with patched qt)\\n\",\n  \"cached_files\": 4,\n  \"timestamp\": \"2025-10-28T00:00:00Z\"\n}\n```\n\n**Response (HTTP 503 - Unhealthy):**\n\n```json\n{\n  \"status\": \"unhealthy\",\n  \"message\": \"wkhtmltopdf is not available\",\n  \"error\": \"exec: \\\"wkhtmltopdf\\\": executable file not found\"\n}\n```\n\n**Example Usage:**\n\n```bash\n# Check service health\ncurl http://localhost:8080/health\n```\n\n```python\n# Python health check\nimport requests\n\nresponse = requests.get('http://localhost:8080/health')\nif response.status_code == 200:\n    print('Service is healthy')\n    print(f\"Cached files: {response.json()['cached_files']}\")\nelse:\n    print('Service is unhealthy')\n```\n\n## How to Install Using Docker\n\n### Prerequisites\n\n- Docker Desktop installed on your PC\n- Docker daemon running\n\n### Method 1: Using Pre-built Image (Recommended)\n\nPull and run the pre-built image from GitHub Container Registry:\n\n```bash\ndocker run -d -p 8080:8080 --name go-pdf ghcr.io/getevo/go-pdf:latest\n```\n\nThat's it! The service will be available at `http://localhost:8080`\n\n**With docker-compose:**\n\n```yaml\nversion: '3.8'\nservices:\n  go-pdf:\n    image: ghcr.io/getevo/go-pdf:latest\n    container_name: go-pdf\n    ports:\n      - \"8080:8080\"\n    restart: unless-stopped\n```\n\nThen run:\n```bash\ndocker-compose up -d\n```\n\n### Method 2: Build from Source\n\n1. **Clone the repository**:\n   ```bash\n   git clone https://github.com/getevo/go-pdf.git\n   cd go-pdf\n   ```\n\n2. **Build the Docker image**:\n   ```bash\n   docker build -t go-pdf:latest .\n   ```\n\n3. **Run the container**:\n   ```bash\n   docker run -d -p 8080:8080 --name go-pdf go-pdf:latest\n   ```\n\n4. **Verify the service is running**:\n   ```bash\n   curl -X POST http://localhost:8080/api/v1/generate \\\n     -H \"Content-Type: text/html\" \\\n     -d '\u003chtml\u003e\u003cbody\u003e\u003ch1\u003eTest\u003c/h1\u003e\u003c/body\u003e\u003c/html\u003e' \\\n     -o test.pdf\n   ```\n\n5. **View logs**:\n   ```bash\n   docker logs go-pdf\n   ```\n\n6. **Stop the container**:\n   ```bash\n   docker stop go-pdf\n   ```\n\n### Method 3: Using Docker Compose (Build from Source)\n\n1. **Clone and start**:\n   ```bash\n   git clone https://github.com/getevo/go-pdf.git\n   cd go-pdf\n   docker-compose up -d\n   ```\n\n2. **View logs**:\n   ```bash\n   docker-compose logs -f\n   ```\n\n3. **Stop the service**:\n   ```bash\n   docker-compose down\n   ```\n\n### Configuration\n\nThe service is configured via `config.yml`. Key settings:\n\n- **HTTP.Port**: 8080 (default) - The port the service listens on\n- **HTTP.BodyLimit**: 50mb - Maximum request body size\n- **HTTP.ReadTimeout**: 30s - Request read timeout\n- **HTTP.WriteTimeout**: 60s - Response write timeout\n- **Database.Enabled**: false - Database is disabled\n\n### Environment Variables\n\nYou can override configuration using environment variables or by modifying the `config.yml` file before building the Docker image.\n\n## Architecture\n\n```\ngo-pdf/\n├── main.go              # Application entry point\n├── config.yml           # Configuration file\n├── apps/\n│   └── pdf/\n│       ├── app.go       # App registration and routing\n│       └── controller.go # PDF generation logic\n├── cache/               # Temporary file storage (auto-created)\n├── Dockerfile           # Multi-stage Docker build\n├── docker-compose.yml   # Docker Compose configuration\n└── README.md            # This file\n```\n\n### How It Works\n\n1. **Request**: Client sends HTML content via POST to `/api/v1/generate`\n2. **Validation**: Service validates the HTML content\n3. **File Creation**: HTML is written to a temporary file in the cache directory\n4. **Conversion**: wkhtmltopdf converts HTML to PDF\n5. **Response**: PDF is read and sent back to the client\n6. **Cleanup**: Files older than 1 hour are automatically deleted every 10 minutes\n\n### Performance Considerations\n\n- **Concurrent Requests**: The service is designed to handle concurrent requests efficiently\n- **File Caching**: Temporary files are cached for 1 hour to balance between reusability and disk space\n- **Memory Usage**: The service uses minimal memory thanks to Go's efficiency and streaming responses\n- **Image Size**: Multi-stage Docker build results in a minimal image size (~400MB including wkhtmltopdf dependencies)\n\n## Troubleshooting\n\n### Container Won't Start\n\nCheck logs:\n```bash\ndocker logs go-pdf\n```\n\n### PDF Generation Fails\n\n1. Verify HTML is valid\n2. Check if wkhtmltopdf is installed in the container:\n   ```bash\n   docker exec go-pdf wkhtmltopdf --version\n   ```\n\n### Port Already in Use\n\nChange the port mapping:\n```bash\ndocker run -d -p 9090:8080 --name go-pdf go-pdf:latest\n```\n\n## Development\n\n### Building Locally\n\n```bash\ngo mod download\ngo build -o go-pdf .\n./go-pdf\n```\n\n### Testing\n\n```bash\n# Create a test HTML file\necho '\u003c!DOCTYPE html\u003e\u003chtml\u003e\u003cbody\u003e\u003ch1\u003eTest\u003c/h1\u003e\u003c/body\u003e\u003c/html\u003e' \u003e test.html\n\n# Generate PDF\ncurl -X POST http://localhost:8080/api/v1/generate \\\n  -H \"Content-Type: application/json\" \\\n  -d \"{\\\"html\\\":\\\"$(cat test.html)\\\"}\" \\\n  -o test.pdf\n```\n\n## License\n\nMIT License - See [LICENSE](LICENSE) file for details.\n\nThis project is released under the MIT License, which is one of the most permissive open-source licenses. You are free to:\n- Use commercially\n- Modify\n- Distribute\n- Use privately\n\nThe only requirement is to include the original copyright and license notice in any copy of the software/source.\n\n## Credits\n\n- Built with [getevo/evo/v2](https://github.com/getevo/evo)\n- Uses [wkhtmltopdf](https://wkhtmltopdf.org/) for HTML to PDF conversion\n- HTTP framework: [Fiber](https://gofiber.io/)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgetevo%2Fgo-pdf","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgetevo%2Fgo-pdf","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgetevo%2Fgo-pdf/lists"}