DEV Community

Francis Oyakhire
Francis Oyakhire

Posted on

Postiz Self Host Bluesky Python Client

This week, the AI space saw a surge in open-source enthusiasm, with new tools and libraries capturing developer attention. While the headlines focus on stars and strategic partnerships, we’re diving into the nitty-gritty of how we’ve built a self-hosted Postiz instance using Docker Compose and connected it with a Python client that communicates via the /api/public/v1/posts endpoint.

At Apex Grid Technologies, we’ve been evaluating lightweight, self-hosted social platforms as part of our broader exploration into on-device AI integration. Postiz stood out for its minimalism and open API, which made it a natural fit for our experimentation. We chose to self-host it using Docker Compose to ensure we had full control over the environment and could easily scale or modify it as needed.

Setting up Postiz with Docker Compose was straightforward. We used the official Docker image and configured it with our desired settings, such as database connections and authentication options. Here’s a simplified version of our docker-compose.yml:

version: '3.8'
services:
  postiz:
    image: postiz/postiz:latest
    ports:
      - "8080:8080"
    environment:
      POSTIZ_DB_URL: "postgres://user:password@db:5432/postiz"
      POSTIZ_JWT_SECRET: "supersecretkey"
    depends_on:
      - db
  db:
    image: postgres:15
    environment:
      POSTGRES_USER: user
      POSTGRES_PASSWORD: password
      POSTGRES_DB: postiz
    volumes:
      - postgres_data:/var/lib/postgresql/data
volumes:
  postgres_data:
Enter fullscreen mode Exit fullscreen mode

Once the Postiz instance was up and running, we built a Python client to interact with its API. We focused on the /api/public/v1/posts endpoint, which allows for creating and retrieving posts. The client is built using requests, and we handle both the JSON payload and the response structure carefully.

Here’s how we construct the request:

import requests
import json

headers = {
    "Authorization": "Bearer <your-jwt-token>",
    "Content-Type": "application/json"
}

payload = {
    "text": "This is a test post from the Python client.",
    "visibility": "public"
}

response = requests.post("http://localhost:8080/api/public/v1/posts", headers=headers, json=payload)

if response.status_code == 200:
    result = response.json()
    if isinstance(result, list):
        print("Received a list of posts:", result)
    else:
        print("Received a single post:", result)
else:
    print("Error:", response.status_code, response.text)
Enter fullscreen mode Exit fullscreen mode

We’ve noticed that the /api/public/v1/posts endpoint can return either a single object or a list depending on the context - for example, when creating a new post, it returns the created object, but when fetching all posts, it returns a list. This is a subtle but important detail for any client consuming the API. We handle this by checking the type of the response using isinstance() and processing accordingly.

One tradeoff we’ve made is the lack of advanced features like rate limiting or more granular permissions, which are not exposed through the public API. However, for our use case, this is acceptable, and we can always extend the client or the Postiz setup if needed.

Looking ahead, we’re exploring ways to integrate this setup with our on-device AI models. The idea is to have a local, self-hosted social layer that can interact with AI-generated content in real time, without relying on external cloud services. We’re also looking into ways to make the Python client more robust, including support for async requests and better error handling.

What are your thoughts on self-hosted social platforms and their potential for AI integration?

Top comments (0)