Skip to main content

The unofficial Python client for Strapi.

Project description

Strapi Python Client

PyPI version Python License: MIT

The unofficial Python client library to easily interface with Strapi from your Python project.

Installation

pip install strapi-py

Quick Start

from strapi_client import strapi

# Create a client instance
client = strapi(base_url="http://localhost:1337/api")

# Fetch data from a custom endpoint
response = client.fetch('/articles')
data = response.json()
print(data)

Authentication

API Token Authentication

from strapi_client import strapi

# Initialize the client with yor API token
client = strapi(
    base_url="http://localhost:1337/api",
    auth="your-api-token-here"
)

# All requests will include the Authorization header
response = client.fetch('/articles')

Custom Headers

client = strapi(
    base_url="http://localhost:1337/api",
    headers={
        "X-Custom-Header": "value",
        "Accept-Language": "en"
    }
)

Working with Collection Types

Collection types represent multiple entries (e.g., articles, products, users).

Find All Entries

# Get all articles
articles = client.collection('articles')
response = articles.find()
print(response.json())

Find with Filters and Sorting

articles = client.collection('articles')

# Filter and sort
response = articles.find(params={
    'filters': {
        'title': {
            '$contains': 'Python'
        },
        'publishedAt': {
            '$notNull': True
        }
    },
    'sort': ['createdAt:desc'],
    'pagination': {
        'page': 1,
        'pageSize': 10
    },
    'populate': '*'
})

Find One Entry

articles = client.collection('articles')

# Get article with documentId j964065dnjrdr4u89weh79xl
response = articles.find_one("j964065dnjrdr4u89weh79xl", params={
    'populate': ['author', 'comments']
})
print(response.json())

NOTE

Strapi 5 replaces the numeric id used in Strapi 4 with a new 24-character alphanumeric identifier called documentId. When working with Strapi 5, use documentId as the primary resource identifier. This library continues to support the legacy id field for Strapi 4 projects.

Create an Entry

articles = client.collection('articles')

response = articles.create(data={
    'title': 'My New Article',
    'content': 'This is the article content',
    'publishedAt': '2024-01-01T00:00:00.000Z'
})

created_article = response.json()
print(f"Created article with ID: {created_article['data']['documentId']}")

Update an Entry

articles = client.collection('articles')

response = articles.update(1, data={
    'title': 'Updated Article Title',
    'content': 'Updated content'
})

Delete an Entry

articles = client.collection('articles')
response = articles.delete(1)

Working with Single Types

Single types represent a single entry (e.g., homepage, about page, settings).

Find Single Type

homepage = client.single('homepage')
response = homepage.find(params={'populate': '*'})
print(response.json())

Update Single Type

homepage = client.single('homepage')
response = homepage.update(data={
    'title': 'Welcome to My Site',
    'description': 'A brief description'
})

Delete Single Type

homepage = client.single('homepage')
response = homepage.delete()

Working with Plugins

Users & Permissions Plugin

# Access users endpoint
users = client.collection(
    resource='users',
    plugin={'name': 'users-permissions', 'prefix': ''}
)

# Create a new user
response = users.create(data={
    'username': 'johndoe',
    'email': 'john@example.com',
    'password': 'SecurePassword123!'
})

Custom Plugin with Prefix

# Access a custom plugin endpoint
blog_posts = client.collection(
    resource='posts',
    plugin={'name': 'blog', 'prefix': 'blog'}
)
# This will make requests to /blog/posts

response = blog_posts.find()

Custom Plugin without Prefix

# Disable plugin prefix
custom_content = client.collection(
    resource='items',
    plugin={'name': 'custom-plugin', 'prefix': ''}
)
# This will make requests to /items

File Management

Upload a File

# Upload from bytes
with open('image.jpg', 'rb') as f:
    file_data = f.read()

response = client.files.upload(
    file_data=file_data,
    filename='image.jpg',
    mimetype='image/jpeg',
    file_info={
        'alternativeText': 'A sample image',
        'caption': 'My caption'
    }
)

print(response.json())

Upload with File Object

import io

# Upload from file-like object
with open('document.pdf', 'rb') as f:
    response = client.files.upload(
        file_data=f,
        filename='document.pdf',
        mimetype='application/pdf'
    )

List All Files

# Get all files
response = client.files.find()
files = response.json()

# Filter files
response = client.files.find(params={
    'filters': {
        'mime': {'$contains': 'image'}
    },
    'sort': 'createdAt:desc'
})

Get a Specific File

response = client.files.find_one(file_id="clkgylmcc000008lcdd868feh")
file_data = response.json()
print(f"File URL: {file_data['url']}")

Update File Metadata

response = client.files.update(
    file_id="clkgylmcc000008lcdd868feh",
    file_info={
        'name': 'renamed-file.jpg',
        'alternativeText': 'Updated alt text',
        'caption': 'Updated caption'
    }
)

Delete a File

response = client.files.delete(file_id="clkgylmcc000008lcdd868feh")

Custom Paths

You can specify custom API paths for content types:

# Use a custom path instead of the default /articles
custom_articles = client.collection(
    resource='articles',
    path='/v2/custom-articles'
)

response = custom_articles.find()
# Makes request to /v2/custom-articles

Error Handling

The library provides detailed error messages from Strapi, making debugging much easier. When an error occurs, you'll see:

  • Error type/name (e.g., ValidationError, ApplicationError)
  • Clear error message from Strapi
  • Detailed field-level validation errors with paths
  • Access to the original response for debugging

Basic Error Handling

from strapi_client import (
    strapi,
    StrapiHTTPError,
    StrapiHTTPNotFoundError,
    StrapiHTTPUnauthorizedError,
    StrapiHTTPBadRequestError,
    StrapiValidationError
)

try:
    client = strapi(base_url="http://localhost:1337/api")
    articles = client.collection('articles')
    response = articles.find_one(999)
except StrapiHTTPNotFoundError as e:
    print(f"Article not found: {e}")
    print(f"Status code: {e.response.status_code}")
except StrapiHTTPUnauthorizedError as e:
    print(f"Authentication failed: {e}")
except StrapiHTTPBadRequestError as e:
    print(f"Bad request: {e}")
    print(f"Full error: {e.response.json()}")
except StrapiHTTPError as e:
    print(f"HTTP error occurred: {e}")
    print(f"Response: {e.response.text}")
except StrapiValidationError as e:
    print(f"Validation error: {e}")

Detailed Validation Errors

When you have validation errors (e.g., in dynamic zones or complex fields), the error message will show exactly which fields are problematic:

try:
    blog = client.collection('blogs')
    response = blog.create(data={
        'title': '',  # Invalid: too short
        'blocks': [
            {
                # Missing __component field
                'body': 'Some content'
            }
        ]
    })
except StrapiHTTPBadRequestError as e:
    print(e)
    # Output:
    # Strapi API Error (400): [ValidationError] Invalid data provided
    # Validation errors:
    #   - title: title must be at least 1 characters
    #   - blocks.0.__component: component is required

Accessing Response Details

All HTTP errors preserve the original response, allowing you to access additional details:

try:
    response = client.collection('articles').create(data={...})
except StrapiHTTPBadRequestError as e:
    # Get status code
    print(f"Status: {e.response.status_code}")
    
    # Get full error details
    error_details = e.response.json()
    print(f"Error name: {error_details['error']['name']}")
    print(f"Error details: {error_details['error']['details']}")
    
    # Get request Url
    print(f"Request URL: {e.response.request.url}")

Available Error Types

  • StrapiError - Base error class
  • StrapiValidationError - Invalid input or configuration
  • StrapiHTTPError - Base HTTP error (non-2xx responses)
  • StrapiHTTPBadRequestError - 400 Bad Request (validation errors, malformed requests)
  • StrapiHTTPUnauthorizedError - 401 Unauthorized (authentication required)
  • StrapiHTTPForbiddenError - 403 Forbidden (insufficient permissions)
  • StrapiHTTPNotFoundError - 404 Not Found (resource doesn't exist)
  • StrapiHTTPTimeoutError - 408 Request Timeout
  • StrapiHTTPInternalServerError - 500 Internal Server Error

Advanced Usage

Locale Support

articles = client.collection('articles')

# Fetch French content
response = articles.find(params={'locale': 'fr'})

# Fetch specific entry in Spanish
response = articles.find_one(1, params={'locale': 'es'})

Population

articles = client.collection('articles')

# Populate all relations
response = articles.find(params={'populate': '*'})

# Populate specific relations
response = articles.find(params={
    'populate': ['author', 'categories', 'cover']
})

# Deep population
response = articles.find(params={
    'populate': {
        'author': {
            'populate': ['avatar']
        },
        'categories': '*'
    }
})

Field Selection

articles = client.collection('articles')

# Select specific fields only
response = articles.find(params={
    'fields': ['title', 'description', 'publishedAt']
})

Requirements

  • Python >= 3.10
  • httpx >= 0.27.0

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

License

MIT License - see LICENSE file for details.

Links

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

strapi_py-0.1.1.tar.gz (17.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

strapi_py-0.1.1-py3-none-any.whl (25.0 kB view details)

Uploaded Python 3

File details

Details for the file strapi_py-0.1.1.tar.gz.

File metadata

  • Download URL: strapi_py-0.1.1.tar.gz
  • Upload date:
  • Size: 17.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.0

File hashes

Hashes for strapi_py-0.1.1.tar.gz
Algorithm Hash digest
SHA256 46c21ba374673187dbab530075759603f20fb6b5b065b77bac7387dc4b55da50
MD5 2e715f4803320aac16b1593490dec2e6
BLAKE2b-256 6f6e0d894e78718fa0fa72e1ba0ae1a5fc8f363d36e7621b6d2ddad1b73f4f01

See more details on using hashes here.

File details

Details for the file strapi_py-0.1.1-py3-none-any.whl.

File metadata

  • Download URL: strapi_py-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 25.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.0

File hashes

Hashes for strapi_py-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 a17a93c7e823ae0b67a9553921984ce817097b1d6955c047c768c9534ca20821
MD5 6af324490eda8da117fe09a2e4a62dbd
BLAKE2b-256 662a3ad0f6e8df7a55289fe6efcd0f5c14b0358c34d88ba213e0748bdace6bc8

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page