API Reference

Filtering and Search

Advanced filtering, searching, and ordering for ZineCore2 API

The ZineCore2 API provides powerful filtering, search, and ordering capabilities for all list endpoints.

Query Parameters

All list endpoints (/api/zines/, /api/agents/, etc.) support query parameters for filtering and search.

Basic Syntax

GET /api/{endpoint}/?{parameter}={value}

Multiple parameters:

GET /api/{endpoint}/?{param1}={value1}&{param2}={value2}

Field Filtering

Filter by exact field values.

Zines

Filter by subject:

curl "http://localhost:8000/api/zines/?subject=feminism"

Filter by genre:

curl "http://localhost:8000/api/zines/?genre=personal-zine"

Filter by creator:

curl "http://localhost:8000/api/zines/?creator=agent_judith_arcana"

Filter by language:

curl "http://localhost:8000/api/zines/?language=en"

Multiple filters:

curl "http://localhost:8000/api/zines/?subject=feminism&genre=personal-zine&language=en"

Agents

Filter by kind:

curl "http://localhost:8000/api/agents/?kind=Person"

Filter by public status:

curl "http://localhost:8000/api/agents/?public=true"

Holdings

Filter by zine:

curl "http://localhost:8000/api/holdings/?zine_id=zine_mutate_3_1st"

Filter by repository:

curl "http://localhost:8000/api/holdings/?repository_id=repo_barnard_zine_library"

Filter by access status:

curl "http://localhost:8000/api/holdings/?access_status=reading-room-only"

Filter by digital availability:

curl "http://localhost:8000/api/holdings/?digital_available=true"

Repositories

Filter by kind:

curl "http://localhost:8000/api/repositories/?repository_kind=academic-library"

Filter by country:

curl "http://localhost:8000/api/repositories/?country=US"

Filter by status:

curl "http://localhost:8000/api/repositories/?status=active"

Search across multiple text fields using the search parameter.

Searches across: title, abstract, table_of_contents

# Search for "mutate"
curl "http://localhost:8000/api/zines/?search=mutate"

# Search for "abortion"
curl "http://localhost:8000/api/zines/?search=abortion"

# Multi-word search
curl "http://localhost:8000/api/zines/?search=feminist+killjoy"

URL encoding:

  • Spaces: + or %20
  • Special characters: URL-encoded

Examples:

# "feminist killjoy"
curl "http://localhost:8000/api/zines/?search=feminist+killjoy"
curl "http://localhost:8000/api/zines/?search=feminist%20killjoy"

Searches across: display_name, legal_name, biography, alternative_names

# Search for "arcana"
curl "http://localhost:8000/api/agents/?search=arcana"

# Search for "feminist writer"
curl "http://localhost:8000/api/agents/?search=feminist+writer"

Searches across: repository_name, description, alternative_names

# Search for "barnard"
curl "http://localhost:8000/api/repositories/?search=barnard"

# Search for "queer zine"
curl "http://localhost:8000/api/repositories/?search=queer+zine"

Ordering (Sorting)

Sort results by field values using the ordering parameter.

Ascending Order

# Sort zines by title (A-Z)
curl "http://localhost:8000/api/zines/?ordering=title"

# Sort agents by name (A-Z)
curl "http://localhost:8000/api/agents/?ordering=display_name"

# Sort repositories by name (A-Z)
curl "http://localhost:8000/api/repositories/?ordering=repository_name"

Descending Order

Prefix with - for descending order:

# Sort zines by most recent first
curl "http://localhost:8000/api/zines/?ordering=-created_at"

# Sort zines by title (Z-A)
curl "http://localhost:8000/api/zines/?ordering=-title"

# Sort repositories by newest first
curl "http://localhost:8000/api/repositories/?ordering=-created_at"

Common Ordering Fields

Zines:

  • title — Title (alphabetical)
  • created_at — Creation date
  • updated_at — Last modified date

Agents:

  • display_name — Name (alphabetical)
  • created_at — Creation date

Holdings:

  • created_at — Creation date
  • call_number — Call number (alphabetical)

Repositories:

  • repository_name — Name (alphabetical)
  • created_at — Creation date
  • established — Year established

Combining Filters

Combine search, filtering, and ordering:

Example 1: Feminist Zines, Recent First

curl "http://localhost:8000/api/zines/?subject=feminism&ordering=-created_at"

Explanation:

  • Filter: Only zines with subject "feminism"
  • Order: Most recent first

Example 2: Search + Filter

curl "http://localhost:8000/api/zines/?search=abortion&subject=reproductive-rights&genre=personal-zine"

Explanation:

  • Search: Contains "abortion" in title or abstract
  • Filter: Subject is "reproductive-rights"
  • Filter: Genre is "personal-zine"

Example 3: Digital Holdings for a Zine

curl "http://localhost:8000/api/holdings/?zine_id=zine_mutate_3_1st&digital_available=true"

Explanation:

  • Filter: Holdings of specific zine
  • Filter: Only digital versions

Example 4: Active US Libraries

curl "http://localhost:8000/api/repositories/?country=US&repository_kind=academic-library&status=active&ordering=repository_name"

Explanation:

  • Filter: Country is US
  • Filter: Kind is academic library
  • Filter: Status is active
  • Order: Alphabetically by name

Pagination

All list endpoints are paginated (25 items per page by default).

Default Pagination

Response:

{
  "count": 142,
  "next": "http://localhost:8000/api/zines/?page=2",
  "previous": null,
  "results": [...]
}

Fields:

  • count — Total number of results
  • next — URL to next page (null if last page)
  • previous — URL to previous page (null if first page)
  • results — Array of resources

Page 1 (default):

curl "http://localhost:8000/api/zines/"

Page 2:

curl "http://localhost:8000/api/zines/?page=2"

Page 3:

curl "http://localhost:8000/api/zines/?page=3"

Custom Page Size

50 items per page:

curl "http://localhost:8000/api/zines/?page_size=50"

100 items per page (max):

curl "http://localhost:8000/api/zines/?page_size=100"

Combine with filters:

curl "http://localhost:8000/api/zines/?subject=feminism&page_size=50&page=2"

Advanced Filtering Patterns

Array Field Filtering (Contains)

For ArrayField fields (creator, subject, genre, etc.), the filter checks if the array contains the value.

Example:

Zine record:

{
  "zine_id": "zine_mutate_3",
  "creator": ["agent_judith_arcana", "agent_jane_doe"],
  "subject": ["feminism", "reproductive-rights", "personal-narratives"]
}

Queries that match:

# Matches (creator contains "agent_judith_arcana")
curl "http://localhost:8000/api/zines/?creator=agent_judith_arcana"

# Matches (creator contains "agent_jane_doe")
curl "http://localhost:8000/api/zines/?creator=agent_jane_doe"

# Matches (subject contains "feminism")
curl "http://localhost:8000/api/zines/?subject=feminism"

# Matches (subject contains "reproductive-rights")
curl "http://localhost:8000/api/zines/?subject=reproductive-rights"

Queries that don't match:

# Doesn't match (creator doesn't contain "agent_other")
curl "http://localhost:8000/api/zines/?creator=agent_other"

# Doesn't match (subject doesn't contain "punk")
curl "http://localhost:8000/api/zines/?subject=punk"

Multiple Values for Same Field

NOT supported directly. Use separate requests instead:

# Get zines with subject "feminism"
curl "http://localhost:8000/api/zines/?subject=feminism"

# Get zines with subject "punk"
curl "http://localhost:8000/api/zines/?subject=punk"

# Then combine results client-side

Workaround: Use search instead:

curl "http://localhost:8000/api/zines/?search=feminism+punk"

Case Sensitivity

Search: Case-insensitive

# These are equivalent:
curl "http://localhost:8000/api/zines/?search=feminism"
curl "http://localhost:8000/api/zines/?search=Feminism"
curl "http://localhost:8000/api/zines/?search=FEMINISM"

Field filtering: Case-sensitive

# These are NOT equivalent:
curl "http://localhost:8000/api/zines/?subject=feminism"  # Works
curl "http://localhost:8000/api/zines/?subject=Feminism"  # Doesn't work (case mismatch)

Best practice: Use exact vocabulary codes for filtering.


Response Examples

Filtered Response

Request:

curl "http://localhost:8000/api/zines/?subject=feminism&ordering=-created_at&page_size=2"

Response:

{
  "count": 42,
  "next": "http://localhost:8000/api/zines/?subject=feminism&ordering=-created_at&page_size=2&page=2",
  "previous": null,
  "results": [
    {
      "zine_id": "zine_mutate_3_1st",
      "title": "Mutate Zine #3: Abortion Stories",
      "subject": [
        {
          "code": "feminism",
          "label": "Feminism",
          "uri": "https://zinecore.org/v2/subjects#feminism"
        }
      ],
      "created_at": "2024-02-25T10:30:00Z"
    },
    {
      "zine_id": "zine_feminist_killjoy_1",
      "title": "Feminist Killjoy #1",
      "subject": [
        {
          "code": "feminism",
          "label": "Feminism",
          "uri": "https://zinecore.org/v2/subjects#feminism"
        }
      ],
      "created_at": "2024-02-24T14:00:00Z"
    }
  ]
}

Empty Results

Request:

curl "http://localhost:8000/api/zines/?subject=nonexistent"

Response:

{
  "count": 0,
  "next": null,
  "previous": null,
  "results": []
}

Code Examples

Python

import requests

API_BASE = "http://localhost:8000/api"

# Search zines
params = {
    "search": "feminist",
    "subject": "feminism",
    "ordering": "-created_at",
    "page_size": 50
}

response = requests.get(f"{API_BASE}/zines/", params=params)
data = response.json()

print(f"Found {data['count']} zines")
for zine in data['results']:
    print(f"  - {zine['title']}")

# Paginate through all results
url = f"{API_BASE}/zines/?subject=feminism"
while url:
    response = requests.get(url)
    data = response.json()

    for zine in data['results']:
        print(zine['title'])

    url = data['next']  # Next page URL (or None if last page)

JavaScript

const API_BASE = "http://localhost:8000/api";

// Search zines
const params = new URLSearchParams({
  search: "feminist",
  subject: "feminism",
  ordering: "-created_at",
  page_size: 50
});

const response = await fetch(`${API_BASE}/zines/?${params}`);
const data = await response.json();

console.log(`Found ${data.count} zines`);
data.results.forEach(zine => {
  console.log(`  - ${zine.title}`);
});

// Paginate through all results
let url = `${API_BASE}/zines/?subject=feminism`;
while (url) {
  const response = await fetch(url);
  const data = await response.json();

  data.results.forEach(zine => {
    console.log(zine.title);
  });

  url = data.next;  // Next page URL (or null if last page)
}

cURL

# Search with multiple filters
curl -G "http://localhost:8000/api/zines/" \
  --data-urlencode "search=feminist" \
  --data-urlencode "subject=feminism" \
  --data-urlencode "genre=personal-zine" \
  --data-urlencode "ordering=-created_at" \
  --data-urlencode "page_size=50"

# Filter holdings by zine
curl "http://localhost:8000/api/holdings/?zine_id=zine_mutate_3_1st"

# Filter repositories by country
curl "http://localhost:8000/api/repositories/?country=US&status=active"

Performance Considerations

Indexed Fields

The following fields are indexed for fast filtering:

Zines:

  • zine_id (unique index)
  • title (btree index)
  • creator (GIN index for array)
  • subject (GIN index for array)
  • genre (GIN index for array)
  • created_at (btree index)

Agents:

  • agent_id (unique index)
  • display_name (btree index)
  • kind (btree index)
  • public (btree index)

Holdings:

  • holding_id (unique index)
  • zine_id (foreign key index)
  • repository_id (foreign key index)
  • (zine_id, repository_id) (composite index)

Repositories:

  • repo_id (unique index)
  • repository_name (btree index)
  • repository_kind (btree index)
  • country (btree index)

Optimization Tips

Fast queries:

  • Filter by indexed fields
  • Use exact matches for IDs
  • Limit page size (smaller = faster)

Slower queries:

  • Full-text search (scans text fields)
  • Ordering by non-indexed fields
  • Very large page sizes

Best practices:

  • Use filters when possible (faster than search)
  • Order by indexed fields (created_at, not abstract)
  • Keep page size reasonable (25-100 items)

Troubleshooting

No Results

Problem: Query returns no results

Possible causes:

  • Typo in filter value
  • Case mismatch (field filtering is case-sensitive)
  • Invalid vocabulary code
  • No records match criteria

Solutions:

  • Check filter values for typos
  • Use exact vocabulary codes (check /api/vocabularies/)
  • Try broader search instead of exact filtering
  • Remove filters one at a time to identify issue

Too Many Results

Problem: Query returns too many results

Solutions:

  • Add more filters
  • Use search instead of broad filtering
  • Increase specificity

Pagination Not Working

Problem: next and previous URLs not working

Possible causes:

  • Invalid page number
  • Page size too large (max 100)

Solutions:

  • Check page number is valid (>= 1, <= total pages)
  • Reduce page size to 100 or less

Next Steps

Copyright ©2026 ZineCore2 Contributors,