API Reference

Scriptlog provides a RESTful API that allows external applications to interact with blog content. The API follows OpenAPI 3.0 specification and returns JSON responses.

Home / Documentation / API Reference
Base URLs
Productionhttp://blogware.site/api/v1
Developmenthttp://localhost/blogware/public_html/api/v1
API Version: 1.1.1 | Format: JSON

Authentication

The API supports two authentication methods:

API Key Authentication

HTTP headers
GET /api/v1/posts HTTP/1.1
Host: blogware.site
X-API-Key: your-api-key-here

Bearer Token Authentication

HTTP headers
GET /api/v1/posts HTTP/1.1
Host: blogware.site
Authorization: Bearer your-bearer-token

Authentication Requirements

Endpoint Type Authentication Required
Read (GET) - Public contentNo
Create/Update/Delete (POST/PUT/DELETE)Yes

API Information

Method Endpoint Auth Description
GET/api/v1/NoGet API metadata and available endpoints

Example Response

JSON response
{
  "success": true,
  "status": 200,
  "message": "Welcome to Blogware RESTful API",
  "data": {
    "name": "Blogware RESTful API",
    "version": "1.1.1",
    "description": "RESTful API for Blogware content management system",
    "base_url": "/api/v1",
    "authentication": {
      "type": "API Key or Bearer Token",
      "header": "X-API-Key or Authorization: Bearer ",
      "required": true
    }
  },
  "_links": {
    "self": { "href": "http://blogware.site/api/v1", "rel": "self", "type": "GET" },
    "posts": { "href": "http://blogware.site/api/v1/posts", "rel": "posts", "type": "GET" },
    "categories": { "href": "http://blogware.site/api/v1/categories", "rel": "categories", "type": "GET" },
    "comments": { "href": "http://blogware.site/api/v1/comments", "rel": "comments", "type": "GET" },
    "archives": { "href": "http://blogware.site/api/v1/archives", "rel": "archives", "type": "GET" },
    "search": { "href": "http://blogware.site/api/v1/search?q={query}", "rel": "search", "type": "GET", "templated": true },
    "openapi": { "href": "http://blogware.site/api/v1/openapi.json", "rel": "service-desc", "type": "application/json" }
  }
}

Permission Levels

Level Create Posts Edit Posts Delete Posts Manage Categories Moderate Comments
administrator
editor
author (own only)
subscriber

Rate Limiting

API requests are rate limited to ensure fair usage and prevent abuse. Rate limiting is applied per-client using IP address, API key, or Bearer token as the identifier.

Endpoint Type Limit Window
Read (GET)60 requests60 seconds
Write (POST/PUT/DELETE/PATCH)20 requests60 seconds
Header Description
X-RateLimit-LimitMaximum requests allowed per window
X-RateLimit-RemainingRemaining requests in current window
X-RateLimit-ResetUnix timestamp when the rate limit resets
Retry-AfterSeconds to wait before retrying (only on 429 responses)
If you exceed the rate limit, you'll receive a 429 Too Many Requests response.

Posts API

Method Endpoint Auth Description
GET/api/v1/postsNoList published posts
GET/api/v1/posts/{id}NoGet single post
GET/api/v1/posts/{id}/commentsNoGet post comments
POST/api/v1/postsYesCreate post
PUT/api/v1/posts/{id}YesUpdate post
PATCH/api/v1/posts/{id}YesPartially update post
DELETE/api/v1/posts/{id}YesDelete post

Query Parameters (List Posts)

Parameter Type Default Description
pageinteger1Page number
per_pageinteger10Items per page (max: 100)
sort_bystringIDSort field (ID, post_date, post_modified, post_title)
sort_orderstringDESCSort direction (ASC, DESC)

Path Parameters (Get Single Post)

Parameter Type Description
idintegerPost ID

Example Paginated Response

JSON response
{
  "success": true,
  "status": 200,
  "data": [...],
  "pagination": {
    "current_page": 1,
    "per_page": 10,
    "total_items": 50,
    "total_pages": 5,
    "has_next_page": true,
    "has_previous_page": false
  },
  "_links": {
    "self": { "href": "http://blogware.site/api/v1/posts?page=1", "rel": "self", "type": "GET" },
    "next": { "href": "http://blogware.site/api/v1/posts?page=2", "rel": "next", "type": "GET" },
    "last": { "href": "http://blogware.site/api/v1/posts?page=5", "rel": "last", "type": "GET" }
  }
}

Create Post - Request Body

JSON request
{
  "post_title": "My New Post",
  "post_content": "Full content of the post",
  "post_summary": "Optional summary",
  "post_status": "draft",
  "post_visibility": "public",
  "post_tags": "php, api",
  "comment_status": "open",
  "topics": [1, 2]
}
Required Fields
  • post_title (string)
  • post_content (string)
Optional Fields
  • post_summary (string)
  • post_status (string: "publish", "draft")
  • post_visibility (string: "public", "private", "protected")
  • post_tags (string, comma-separated)
  • comment_status (string: "open", "closed")
  • topics (array of integers)

Query Parameters (Get Comments for Post)

Parameter Type Default Description
pageinteger1Page number
per_pageinteger10Items per page

Categories API

Method Endpoint Auth Description
GET/api/v1/categoriesNoList categories
GET/api/v1/categories/{id}NoGet category
GET/api/v1/categories/{id}/postsNoGet posts in category
POST/api/v1/categoriesYesCreate category
PUT/api/v1/categories/{id}YesUpdate category
PATCH/api/v1/categories/{id}YesPartially update category
DELETE/api/v1/categories/{id}YesDelete category

Query Parameters (List Categories)

Parameter Type Default Description
pageinteger1Page number
per_pageinteger10Items per page
sort_bystringIDSort field
sort_orderstringDESCSort direction

Example Response (List Categories)

JSON response
{
  "success": true,
  "status": 200,
  "data": [
    {
      "id": 1,
      "title": "Technology",
      "slug": "technology",
      "status": "Y",
      "post_count": 15,
      "url": "http://blogware.site/category/technology"
    }
  ],
  "pagination": {...}
}

Create Category - Request Body

JSON request
{
  "topic_title": "Category Name",
  "topic_status": "Y"
}

Comments API

Method Endpoint Auth Description
GET/api/v1/commentsNoList approved comments
GET/api/v1/comments/{id}NoGet comment
POST/api/v1/commentsNoSubmit comment
PUT/api/v1/comments/{id}YesUpdate comment
PATCH/api/v1/comments/{id}YesPartially update comment
DELETE/api/v1/comments/{id}YesDelete comment

Query Parameters (List Comments)

Parameter Type Description
post_idintegerFilter by post ID
pageintegerPage number
per_pageintegerItems per page
sort_bystringSort field
sort_orderstringSort direction

Create Comment - Request Body

JSON request
{
  "comment_author_name": "John Doe",
  "comment_author_email": "[email protected]",
  "comment_content": "Great article!",
  "comment_post_id": 1,
  "comment_parent_id": 0
}
Note: Comments are submitted with 'pending' status for moderation.

Archives API

Method Endpoint Auth Description
GET/api/v1/archivesNoList archive dates
GET/api/v1/archives/{year}NoPosts from year
GET/api/v1/archives/{year}/{month}NoPosts from month

Example Response (List Archives)

JSON response
{
  "success": true,
  "status": 200,
  "data": {
    "archives": [
      {
        "year": 2024,
        "months": [
          {
            "month": 6,
            "month_name": "June",
            "post_count": 5
          }
        ],
        "total_posts": 25
      }
    ],
    "total_years": 3
  }
}

Path Parameters

Parameter Type Description
yearintegerYear (e.g., 2024)
monthintegerMonth (1-12)

Search API

Method Endpoint Auth Description
GET/api/v1/searchNoSearch all content (posts + pages)
GET/api/v1/search/postsNoSearch posts only
GET/api/v1/search/pagesNoSearch pages only

Search Parameters

Parameter Type Required Description
qstringYesSearch keyword (min 2, max 100 chars)
typestringNoall, posts, or pages (default: all)

Example Request

HTTP request
GET /api/v1/search?q=cicero&type=all

Query Parameters

All list endpoints support the following parameters:

Parameter Type Default Description
pageinteger1Page number
per_pageinteger10Items per page (max: 100)
sort_bystringIDSort field
sort_orderstringDESCSort direction (ASC/DESC)

Response Format

Success Response

JSON response
{
  "success": true,
  "status": 200,
  "message": "Operation description",
  "data": { ... }
}

Paginated Response

JSON response
{
  "success": true,
  "status": 200,
  "data": [...],
  "pagination": {
    "current_page": 1,
    "per_page": 10,
    "total_items": 50,
    "total_pages": 5,
    "has_next_page": true,
    "has_previous_page": false
  }
}

Error Response

JSON error
{
  "success": false,
  "status": 400,
  "error": {
    "code": "BAD_REQUEST",
    "message": "Error description"
  }
}

HATEOAS (Hypermedia as the Engine of Application State)

All API responses include HATEOAS links following RFC 5988 (Web Linking). This allows clients to discover available actions dynamically without hardcoding URLs.

Common Link Relations

Relation Description
selfThe current resource URL
collectionThe parent collection URL
firstFirst page of paginated results
prevPrevious page of paginated results
nextNext page of paginated results
lastLast page of paginated results
canonicalThe canonical HTML URL for the resource
commentsComments for a post
postThe parent post for a comment
postsPosts in a category
yearYear archive for a month
searchSearch endpoint (templated URL)
service-descOpenAPI specification URL

Example Single Resource with HATEOAS

JSON response
{
  "success": true,
  "status": 200,
  "data": {
    "id": 1,
    "title": "My First Blog Post",
    "slug": "my-first-blog-post"
  },
  "_links": {
    "self": { "href": "http://blogware.site/api/v1/posts/1", "rel": "self", "type": "GET" },
    "comments": { "href": "http://blogware.site/api/v1/posts/1/comments", "rel": "comments", "type": "GET" },
    "canonical": { "href": "http://blogware.site/post/1/my-first-blog-post", "rel": "canonical", "type": "text/html" },
    "collection": { "href": "http://blogware.site/api/v1/posts", "rel": "collection", "type": "GET" }
  }
}

HTTP Status Codes

Code Meaning
200OK
201Created
204No Content
400Bad Request
401Unauthorized
403Forbidden
404Not Found
405Method Not Allowed
409Conflict
422Unprocessable Entity
429Too Many Requests
500Internal Server Error

Error Codes

Code Description
BAD_REQUESTInvalid request parameters
UNAUTHORIZEDAuthentication required
FORBIDDENInsufficient permissions
NOT_FOUNDResource not found
CONFLICTResource already exists
VALIDATION_ERRORValidation failed
RATE_LIMIT_EXCEEDEDToo many requests
INTERNAL_SERVER_ERRORServer error

SDK Examples

JavaScript / Fetch

JavaScript example.js
const baseUrl = 'http://blogware.site/api/v1';

// Get posts
const response = await fetch(`${baseUrl}/posts`);
const data = await response.json();

// Get single post
const post = await fetch(`${baseUrl}/posts/1`);

// Create comment (no auth required)
const comment = await fetch(`${baseUrl}/comments`, {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    comment_author_name: 'John Doe',
    comment_author_email: '[email protected]',
    comment_content: 'Great article!',
    comment_post_id: 1
  })
});

PHP

PHP example.php
$baseUrl = 'http://blogware.site/api/v1';

// Get posts
$response = file_get_contents($baseUrl . '/posts');
$posts = json_decode($response, true);

// Get posts with authentication
$context = stream_context_create([
  'http' => [
    'header' => "X-API-Key: your-api-key\r\n"
  ]
]);
$response = file_get_contents($baseUrl . '/posts', false, $context);

Python

Python example.py
import requests

base_url = 'http://blogware.site/api/v1'

# Get posts
response = requests.get(f'{base_url}/posts')
posts = response.json()

# Get posts with authentication
headers = {'X-API-Key': 'your-api-key'}
response = requests.get(f'{base_url}/posts', headers=headers)

# Create comment
data = {
    'comment_author_name': 'John Doe',
    'comment_author_email': '[email protected]',
    'comment_content': 'Great article!',
    'comment_post_id': 1
}
response = requests.post(f'{base_url}/comments', json=data)

cURL

BASH commands
# Get posts
curl http://blogware.site/api/v1/posts

# Get posts with authentication
curl -H "X-API-Key: your-api-key" http://blogware.site/api/v1/posts

# Create comment
curl -X POST http://blogware.site/api/v1/comments \
  -H "Content-Type: application/json" \
  -d '{
    "comment_author_name": "John Doe",
    "comment_author_email": "[email protected]",
    "comment_content": "Great article!",
    "comment_post_id": 1
  }'

OpenAPI Specification

The complete OpenAPI 3.0 specification is available for download:

Use these files to generate client SDKs, validate API responses, import into API testing tools (Postman, Swagger UI), or auto-generate documentation.

Using with Swagger UI

To view the API documentation in Swagger UI:

  1. Copy the API_OPENAPI.json file to a web server
  2. Navigate to Swagger Editor
  3. Paste the JSON content
  4. Explore the interactive API documentation

Using with Postman

To import into Postman:

  1. Open Postman
  2. Click Import
  3. Select "Import from link"
  4. Enter: http://blogware.site/docs/API_OPENAPI.json

Creating API Controllers

Step 1: Create Controller

PHP lib/controller/api/MyResourceApiController.php
<?php
class MyResourceApiController extends ApiController
{
    private $resourceDao;
    
    public function __construct()
    {
        parent::__construct();
        $this->resourceDao = new MyResourceDao();
    }
    
    public function index($params = [])
    {
        $this->requiresAuth = false;
        $pagination = $this->getPagination($params);
        
        try {
            $resources = $this->resourceDao->findAll($pagination);
            $total = $this->resourceDao->count();
            ApiResponse::paginated($resources, $pagination['page'], $pagination['per_page'], $total);
        } catch (\Throwable $e) {
            ApiResponse::error($e->getMessage(), 500, 'FETCH_ERROR');
        }
    }
    
    public function show($params = [])
    {
        $id = isset($params[0]) ? (int)$params[0] : 0;
        
        if (!$id) {
            ApiResponse::badRequest('ID is required');
            return;
        }
        
        $resource = $this->resourceDao->findById($id);
        
        if (!$resource) {
            ApiResponse::notFound('Resource not found');
            return;
        }
        
        ApiResponse::success($resource);
    }
    
    public function store($params = [])
    {
        $this->requiresAuth = true;
        
        if (!$this->hasPermission(['administrator'])) {
            ApiResponse::forbidden('Permission denied');
            return;
        }
        
        $validationErrors = $this->validateRequired($this->requestData, ['name']);
        
        if ($validationErrors) {
            ApiResponse::unprocessableEntity('Validation failed', $validationErrors);
            return;
        }
        
        $id = $this->resourceDao->create($this->requestData);
        ApiResponse::created(['id' => $id], 'Created successfully');
    }
}

Step 2: Register Routes

PHP api/index.php
$router->get('resources', 'MyResourceApiController@index');
$router->get('resources/([0-9]+)', 'MyResourceApiController@show');
$router->post('resources', 'MyResourceApiController@store');
$router->put('resources/([0-9]+)', 'MyResourceApiController@update');
$router->delete('resources/([0-9]+)', 'MyResourceApiController@destroy');

Support

For issues and questions:

Changelog

Version 1.1.1 (2026-04-04)

  • Caching: GET responses are now cacheable with Cache-Control: public, max-age=300
  • ETag header for entity tag cache validation
  • Last-Modified header for timestamp-based validation
  • 304 Not Modified response for conditional requests
  • Vary: Accept, Accept-Encoding, X-API-Key header for proper cache keying
  • HTTP Compliance:
    • Location header on all 201 Created responses
    • 204 No Content for DELETE operations (was 200 OK)
    • 406 Not Acceptable for unsupported Accept header values
    • PATCH method support for partial updates
    • Allow header on 405 Method Not Allowed responses
  • Changed POST /languages/{code}/default to PUT (proper state change semantics)

Version 1.1.0 (2026-04-04)

  • Rate Limiting: Implemented file-based rate limiting with sliding window
  • 60 requests/minute for read operations (GET)
  • 20 requests/minute for write operations (POST/PUT/DELETE/PATCH)
  • Per-client tracking by API key, Bearer token, or IP address
  • Standard rate limit headers
  • HATEOAS: Added Hypermedia as the Engine of Application State to all responses
  • _links object in every response following RFC 5988
  • Pagination links (self, first, prev, next, last)
  • Resource links (self, collection, canonical, comments, post)
  • Root API links for endpoint discovery
  • Templated search URL support

Version 1.0.0 (2024-01-15)

  • Initial release
  • Posts CRUD operations
  • Categories CRUD operations
  • Comments CRUD operations
  • Archives by date
  • API Key and Bearer Token authentication
  • OpenAPI 3.0 specification