Framework guides

Python

Query the delivery API from Python with requests.

The delivery API is plain GraphQL over HTTPS, so all Python needs is requests. This guide builds a tiny client you can drop into a script, a Flask app or a data pipeline. Using Django? There's a Django guide too.

  1. Install requests

    bash
    pip install requests
  2. Add your key

    Create a delivery key on your project's API page in PMKIN and export it, or put it in your .env.

    bash
    export PMKIN_API_KEY=your_delivery_key
  3. Write the client

    One function that sends a query, gives up after 10 seconds and turns every failure into an exception with a clear message.

    pmkin.py
    import os
    import requests
    ENDPOINT = "https://content.pmkin.io/graphql"
    API_KEY = os.environ["PMKIN_API_KEY"]
    session = requests.Session()
    session.headers.update({"Authorization": f"Bearer {API_KEY}"})
    class PmkinError(Exception):
    pass
    def query(document: str, variables: dict | None = None) -> dict:
    """Runs a GraphQL query and returns its data."""
    response = session.post(
    ENDPOINT,
    json={"query": document, "variables": variables or {}},
    timeout=10,
    )
    if response.status_code == 401:
    raise PmkinError("The delivery key is wrong or revoked. Check PMKIN_API_KEY.")
    if response.status_code == 429:
    raise PmkinError("Rate limited. Wait a moment and try again.")
    response.raise_for_status()
    body = response.json()
    if body.get("errors"):
    raise PmkinError(body["errors"][0]["message"])
    return body["data"]
  4. List documents

    list_documents.py
    from pmkin import query
    DOCUMENTS = """
    query Documents {
    documents {
    id
    slug
    title
    excerpt
    publishedAt
    }
    }
    """
    for document in query(DOCUMENTS)["documents"]:
    print(f"{document['title']} → /blog/{document['slug']}")
  5. Fetch a document by slug

    documentBySlug is null when the slug doesn't exist or the document isn't published. That's your cue for a 404.

    find_document.py
    from pmkin import query
    DOCUMENT_BY_SLUG = """
    query DocumentBySlug($slug: String!) {
    documentBySlug(slug: $slug) {
    title
    html
    metaTitle
    metaDescription
    }
    }
    """
    def find_document(slug: str) -> dict | None:
    # None when no published document has the slug.
    return query(DOCUMENT_BY_SLUG, {"slug": slug})["documentBySlug"]
    document = find_document("hello-world")
    if document is None:
    print("Not found")
    else:
    print(document["html"])

Every document, page by page#

Lists return at most 100 documents at a time. A generator walks through all of them:

python
from collections.abc import Iterator
from pmkin import query
PAGE = """
query Page($limit: Int, $offset: Int) {
documents(limit: $limit, offset: $offset) {
id
slug
title
}
}
"""
def all_documents(page_size: int = 100) -> Iterator[dict]:
offset = 0
while True:
documents = query(PAGE, {"limit": page_size, "offset": offset})["documents"]
yield from documents
if len(documents) < page_size:
return
offset += page_size

html comes sanitized, ready to put in a page. Prefer markdown if you want to render it yourself, for example with markdown-it-py.

Next steps#