Blog Articles API — Dokumentasi
Versi: 1.0 • Terakhir diperbarui: 2025-11-05 04:19:30 (Asia/Jakarta)
Host API: https://api-sjs.bizpro.my.id
Resource Base Path (diasumsikan): /blog_articles
Catatan: Blueprint
blog_articles_bp = Blueprint('blog_articles', __name__)tidak mendefinisikanurl_prefix. Dokumentasi ini mengasumsikan blueprint dipasang pada path dasar/blog_articles. Jika berbeda di aplikasi Anda, sesuaikan contoh URL di bawah.
Ringkasan
API ini mengelola artikel blog dengan dukungan unggah gambar (multipart form) dan metadata lengkap (slug, excerpt, content, author, category, tags, dsb.).
Fitur utama
- CRUD artikel (list, get by id, create, update, delete)
- Upload file gambar via field
image_file(multipart/form-data) - Alternatif: gunakan
image_urlbila file tidak diunggah - Slug otomatis dari
titlejika tidak dikirim tagsaman diparse denganjson.loads(fallback daftar dipisah koma)- Pembersihan file lama saat update/delete (bila host sesuai domain API)
- Kolom
published_atdapat dikirim manual atau default UTC now di server
Konvensi respons
- Sukses:
{ "success": true, ... } - Gagal:
{ "success": false, "message": "..." }
Skema Tabel
Nama tabel: blog_articles
| Kolom | Tipe | Keterangan |
|---|---|---|
| id | INT UNSIGNED (PK) | Auto increment |
| title | VARCHAR(255) | Wajib |
| slug | VARCHAR(255) UNIQUE | Default: dari title (lower().replace(' ', '-')) jika tidak dikirim |
| excerpt | TEXT | Ringkasan (opsional) |
| content | LONGTEXT | Konten HTML/Markdown (opsional) |
| image_url | VARCHAR(255) | URL gambar (opsional; diisi saat upload sukses) |
| image_alt | VARCHAR(255) | Alt text (opsional) |
| author | VARCHAR(100) | Nama penulis (opsional) |
| published_at | DATETIME | Waktu terbit (opsional) |
| is_featured | TINYINT(1) | 1=unggulan; default 0 |
| is_active | TINYINT(1) | 1=aktif; default 1 |
| created_at | DATETIME | Otomatis oleh DB |
| updated_at | DATETIME | Otomatis on update |
| detail_url | VARCHAR(255) | Link detail (opsional) |
| category_id | INT | FK ke blog_categories.id (opsional) |
| tags | LONGTEXT (JSON valid) | Disarankan JSON array string; DB memeriksa json_valid(tags) |
Penyimpanan file gambar
- Folder:
Config.UPLOAD_FOLDER_ARTICLES(defaultpublic/img/articles)- Nama file:
uuid4.ext(aman dengansecure_filename)- URL publik dibentuk:
https://api-sjs.bizpro.my.id/public/img/articles/<uuid>.<ext>
Format
tags
- Kirim sebagai JSON string:
["hr", "outsourcing"]- Jika mengirim string biasa
"hr, outsourcing", server akan fallback memisah koma.
Keamanan parsing
- Tidak menggunakan
eval()untuktags; menggunakanjson.loads()(aman).
Endpoints
1) List semua artikel
GET https://api-sjs.bizpro.my.id/blog_articles/
Respons 200
{ "success": true, "data": [ /* array artikel */ ] }
Respons 500
{ "success": false, "message": "penjelasan kesalahan" }
2) Ambil artikel berdasarkan ID
GET https://api-sjs.bizpro.my.id/blog_articles/{id}
Respons 200
{ "success": true, "data": { /* objek artikel */ } }
Respons 404
{ "success": false, "message": "Not found" }
Respons 500
{ "success": false, "message": "penjelasan kesalahan" }
3) Buat artikel baru (multipart form)
POST https://api-sjs.bizpro.my.id/blog_articles/
Tipe konten: multipart/form-data
Field Form (teks)
title(string, wajib)slug(string, opsional; default dari title)excerpt(string, opsional)content(string, opsional)image_alt(string, opsional)author(string, opsional)published_at(string datetime, opsional; default UTC now)is_featured(0/1, opsional; default 0)is_active(0/1, opsional; default 1)detail_url(string, opsional)category_id(int, opsional)tags(string JSON atau daftar dipisah koma; opsional)
Field File (opsional)
image_file(png/jpg/jpeg/gif/webp; maksimal sesuai konfigurasi server)
Alternatif tanpa upload file
- Kirim
image_url(string) sebagai URL gambar publik.
Contoh (upload file)
curl -s -X POST "https://api-sjs.bizpro.my.id/blog_articles/" -H "Accept: application/json" -F "title=Tips Rekrutmen Efisien" -F "excerpt=Ringkasan singkat artikel" -F "content=<h1>Konten</h1><p>...</p>" -F "author=SJS Team" -F "is_active=1" -F "is_featured=1" -F "tags=[\"rekrutmen\", \"outsourcing\"]" -F "image_file=@/path/to/image.webp"
Contoh (pakai image_url)
curl -s -X POST "https://api-sjs.bizpro.my.id/blog_articles/" -H "Accept: application/json" -F "title=Panduan HR 2025" -F "image_url=https://cdn.example.com/img/hr2025.jpg" -F "tags=hr, panduan"
Respons 201
{ "success": true, "id": 38, "message": "Article created successfully" }
Respons 400
{ "success": false, "message": "Title is required" }
Respons 500
{ "success": false, "message": "penjelasan kesalahan" }
4) Perbarui artikel (multipart form)
PUT https://api-sjs.bizpro.my.id/blog_articles/{id}
Tipe konten: multipart/form-data
Catatan penting
titletetap wajib pada update.- Jika mengunggah
image_filebaru danimage_urllama berasal dari domain API, file lama akan dihapus dari storage. - Jika tidak mengunggah file, Anda bisa mengirim
image_urlbaru untuk mengganti tautan gambar.
Contoh (ganti sebagian field + upload gambar baru)
curl -s -X PUT "https://api-sjs.bizpro.my.id/blog_articles/38" -H "Accept: application/json" -F "title=Tips Rekrutmen Efisien (Update)" -F "is_featured=0" -F "tags=[\"rekrutmen\", \"hr\"]" -F "image_file=@/path/to/new-image.jpg"
Contoh (tanpa upload, ganti image_url)
curl -s -X PUT "https://api-sjs.bizpro.my.id/blog_articles/38" -H "Accept: application/json" -F "title=Panduan HR 2025 (Update)" -F "image_url=https://cdn.example.com/img/hr2025-new.jpg"
Respons 200
{ "success": true, "affected": 1, "message": "Article updated successfully" }
Respons 404
{ "success": false, "message": "Not found" }
Respons 400
{ "success": false, "message": "Title is required" }
Respons 500
{ "success": false, "message": "penjelasan kesalahan" }
5) Hapus artikel
DELETE https://api-sjs.bizpro.my.id/blog_articles/{id}
Perilaku tambahan
- Jika
image_urladalah URL di domain API (folder upload default), server mencoba menghapus file terkait.
Contoh
curl -s -X DELETE "https://api-sjs.bizpro.my.id/blog_articles/38"
Respons 200
{ "success": true, "affected": 1, "message": "Article deleted successfully" }
Respons 404
{ "success": false, "message": "Not found" }
Respons 500
{ "success": false, "message": "penjelasan kesalahan" }
Validasi & Batasan
- File type:
png, jpg, jpeg, gif, webp(fieldimage_file) — divalidasi olehallowed_file(). - Slug: wajib unik di DB (index unik). Jika mengirim slug duplikat, insert/update dari layer model akan gagal (tangani pesan error).
- Tags: simpan sebagai JSON valid. Pastikan aplikasi frontend mengirim JSON string atau string dipisah koma dengan benar.
- Category:
category_idadalah FK keblog_categories.id(pastikan id valid).
Praktik Terbaik Produksi
- Batasi ukuran file upload di konfigurasi server (Nginx/Flask) dan validasi ukuran di aplikasi.
- Tambahkan auth (JWT/session) & rate limiting.
- Logging terstruktur untuk audit (request-id, user-id).
- Jika arsitektur CDN, simpan hanya path relatif pada DB, dan bangun URL publik di frontend.
- Sanitasi konten
contentbila HTML (hindari XSS).
Changelog
- v1.0 — Dokumentasi awal berdasarkan
blog_articles_routes.pydan skemablog_articles.