Spaces:
Sleeping
Sleeping
| title: PDF API | |
| emoji: π | |
| colorFrom: indigo | |
| colorTo: blue | |
| sdk: docker | |
| app_port: 7860 | |
| pinned: false | |
| # PDF API | |
| API sederhana untuk mengubah **HTML atau URL menjadi PDF**, ditenagai Express + Playwright (Chromium). | |
| Tujuan: dijual sebagai API di RapidAPI dengan biaya infra minimal. | |
| ## Endpoint | |
| | Method | Path | Auth | Keterangan | | |
| | ------ | ------------- | ------ | -------------------------------------------- | | |
| | GET | `/health` | publik | Cek status (untuk health check) | | |
| | POST | `/pdf` | ya | PDF dari `html` atau `url` | | |
| | POST | `/screenshot` | ya | Tangkapan layar (PNG/JPEG) dari `html`/`url` | | |
| Auth: kirim header `X-RapidAPI-Proxy-Secret` (lewat RapidAPI) atau `x-api-key`. | |
| Body `POST /pdf` (JSON): | |
| ```json | |
| { "html": "<h1>Halo</h1>", "format": "A4", "landscape": false } | |
| ``` | |
| Body `POST /screenshot` (JSON): | |
| ```json | |
| { "url": "https://example.com", "fullPage": true, "type": "png" } | |
| ``` | |
| Pakai **template + data** (Handlebars) untuk dokumen seperti invoice β pembeli cukup kirim data: | |
| ```json | |
| { | |
| "template": "<h1>Invoice {{number}}</h1>{{#each items}}<p>{{name}}: {{price}}</p>{{/each}}<b>Total: {{total}}</b>", | |
| "data": { "number": "INV-001", "items": [{ "name": "Design", "price": "$50" }], "total": "$50" } | |
| } | |
| ``` | |
| Pilih salah satu dari `html`, `url`, atau `template` (+ `data`) β berlaku untuk `/pdf` dan `/screenshot`. | |
| Atau pakai **template bawaan** (`templateName`) β pembeli cukup kirim `data`, tanpa menyusun HTML. Tersedia: `invoice`. | |
| ```json | |
| { | |
| "templateName": "invoice", | |
| "data": { | |
| "company": { "name": "Acme Co", "email": "billing@acme.co" }, | |
| "client": { "name": "John Doe" }, | |
| "invoice": { "number": "INV-001", "date": "2026-06-01", "due": "2026-06-15" }, | |
| "items": [{ "description": "Design work", "quantity": 2, "price": "$25", "amount": "$50" }], | |
| "subtotal": "$50", "tax": "$5", "total": "$55", | |
| "notes": "Thank you!" | |
| } | |
| } | |
| ``` | |
| Response: `application/pdf`, atau `image/png` | `image/jpeg` (binary). | |
| ## Jalan lokal | |
| ```bash | |
| npm install | |
| npx playwright install chromium # unduh browser sekali saja | |
| npm start # default http://localhost:8080 | |
| ``` | |
| Tes cepat (hasil tersimpan ke out.pdf): | |
| ```bash | |
| curl -X POST http://localhost:8080/pdf \ | |
| -H "Content-Type: application/json" \ | |
| -d "{\"html\":\"<h1>Halo PDF</h1>\"}" \ | |
| --output out.pdf | |
| ``` | |
| ## Deploy gratis (pilih salah satu) | |
| **Render / Railway / Fly.io / Google Cloud Run** β semuanya membaca `Dockerfile`: | |
| 1. Push repo ini ke GitHub. | |
| 2. Buat service baru dari repo, pilih environment **Docker**. | |
| 3. Set environment variable `API_KEY` dengan nilai rahasia. | |
| Cloud Run cocok karena scale-to-zero (tidak ada tagihan saat sepi) dan free tier besar. | |
| ## Integrasi RapidAPI | |
| 1. Deploy dulu, catat URL publik backend (mis. `https://xxx.onrender.com`). | |
| 2. Di RapidAPI: **Add New API** β arahkan Base URL ke backend Anda. | |
| 3. Aktifkan opsi RapidAPI yang mengirim header rahasia `X-RapidAPI-Proxy-Secret`, | |
| lalu ubah autentikasi backend untuk memverifikasi header itu (lihat catatan keamanan). | |
| 4. Tetapkan paket harga (mis. freemium + bayar per request). | |
| ## Keamanan | |
| Sudah terpasang: | |
| - **Autentikasi:** set `RAPIDAPI_PROXY_SECRET` (diverifikasi dari header | |
| `X-RapidAPI-Proxy-Secret`) agar hanya gateway RapidAPI yang bisa mengakses | |
| backend, dan/atau `API_KEY` (header `x-api-key`) untuk akses langsung. | |
| Perbandingan rahasia memakai constant-time. Jika keduanya kosong, API TERBUKA | |
| (hanya untuk tes lokal) dan server menampilkan peringatan saat start. | |
| - **Proteksi SSRF:** setiap request jaringan yang dibuat halaman (navigasi awal, | |
| redirect, dan sub-resource) divalidasi; alamat privat/loopback/link-local | |
| (termasuk metadata cloud `169.254.169.254`) serta skema non-http(s) seperti | |
| `file:` diblokir. | |
| Disarankan sebelum skala besar: | |
| - **Timeout render** agar tidak mudah di-abuse (body HTML sudah dibatasi 2 MB). | |
| - **DNS rebinding:** validasi saat ini mengecek IP hasil resolve; untuk hardening | |
| penuh, pin IP yang sudah divalidasi saat fetch. | |
| ## Langkah berikutnya | |
| - Tambah opsi margin, ukuran halaman kustom, dan header/footer untuk PDF. | |
| - Tambah timeout render dan rate limiting agar tahan abuse. | |