Skip to content

API Reference

Version: 0.6.0

The PBI-Scope REST API provides a lightweight interface for querying the phage-host database without loading the full pbi package locally. It runs as a separate Docker service (api) and communicates with the same data volume as the analysis container.

Quick Start

# Start the API
docker compose up api

# Test connection
curl http://localhost:8000/health
from pbi import APIClient

client = APIClient("http://localhost:8000")

# Get database stats
stats = client.get_stats()
print(f"Phages: {stats['database']['phages']:,}")

# Query metadata
phages = client.get_phage_metadata(limit=10)
print(phages.head())

client.close()

When to Use API vs Package

Task API (APIClient) Package (SequenceRetriever)
Quick metadata lookup ✅ Recommended ✅ Works
Filtered queries ✅ Recommended ✅ Works
Single sequence retrieval ✅ Works ✅ Works
GFF3 annotations ✅ Works ✅ Recommended
BLAST similarity search ✅ Works ✅ Recommended
Bulk downloads ❌ Not supported ✅ Recommended
ML dataset preparation ❌ Not supported ✅ Recommended
Host genome streaming ❌ Not supported ✅ Required
SQL exploration ✅ Recommended ✅ Works
Shared access (multiple users) ✅ Recommended ❌ Single instance

Recommendation: Use the API for quick exploration and metadata lookups. Use the pbi package for bulk operations, ML workflows, and when you need full control over data access.


Endpoints

Health & Stats

Method Endpoint Description
GET /health Health check
GET /stats Database statistics (row counts for all tables)
GET /tables List all tables and views

Metadata Queries

Method Endpoint Description
GET /phage-metadata Phage metadata with optional WHERE clause
GET /host-metadata Host metadata with optional WHERE clause
GET /phage-host-metadata Combined phage-host metadata
GET /phage-host-pairs Phage-host pair IDs
GET /protein-metadata Protein metadata

Sequence Retrieval

Method Endpoint Description
GET /phage/{id}/sequence Single phage DNA sequence
GET /phage/{id}/genome Phage genome (concat or list)
GET /host/{id}/genome Host genome with contig options
GET /host/{id}/genome-stats Host genome statistics

GFF3 Annotations

Method Endpoint Description
GET /phage/{id}/gff3 Raw GFF3 annotations for a phage
GET /gff3/stats GFF3 index statistics
GET /gff3/sources List source databases in GFF3 index
Method Endpoint Description
POST /blast/search Search a sequence against a BLAST database
GET /blast/databases List BLAST databases and their build status
GET /blast/status BLAST installation and database status

Available databases: phages, proteins, hosts, private, combined. Available programs: blastn, blastp, blastx, tblastn, tblastx (database auto-selected when omitted). Searches return tabular hits as JSON records.

SQL Queries

Method Endpoint Description
POST /query Arbitrary SQL (SELECT only)

Common Workflows

Explore phages by source

from pbi import APIClient

client = APIClient("http://localhost:8000")

# Get phages from RefSeq
phages = client.get_phage_metadata(
    where_clause="Source_DB = 'RefSeq'",
    limit=100
)
print(f"Found {len(phages)} RefSeq phages")

# Get phages longer than 50kb
large_phages = client.get_phage_metadata(
    where_clause="Length > 50000",
    limit=50
)
print(f"Found {len(large_phages)} large phages")

Get host genome for a phage

# First get phage metadata
phages = client.get_phage_metadata(limit=1)
phage_id = phages['Phage_ID'].iloc[0]

# Then get host associations
pairs = client.get_phage_host_metadata(
    where_clause=f"Phage_ID = '{phage_id}'"
)
print(pairs[['Host_Species', 'Host_Assembly_Level']])

SQL exploration

# Source database distribution
source_dist = client.query("""
    SELECT
        Source_DB,
        COUNT(*) AS phage_count,
        ROUND(AVG(Length), 0) AS avg_length
    FROM fact_phages
    GROUP BY Source_DB
    ORDER BY phage_count DESC
""")
print(source_dist)

Get phage sequence

# Get a single phage sequence
seq = client.get_phage_sequence("NC_001330.1")
print(f"Sequence length: {len(seq):,} bp")

# Get genome (concatenated contigs)
genome = client.get_phage_genome("NC_001330.1", mode="concat")
print(f"Genome length: {len(genome):,} bp")

BLAST search

# Check which BLAST databases are built
print(client.blast_status())
print(client.list_blast_databases())

# Search a DNA sequence against the phage database
hits = client.blast_search(
    sequence="ATGCGTTTACG...",
    program="blastn",
    db="phages",
    max_hits=10,
)
print(hits.head())

Usage Examples

cURL

# Health check
curl http://localhost:8000/health

# Database stats
curl http://localhost:8000/stats

# Get phage metadata (limited)
curl "http://localhost:8000/phage-metadata?limit=10"

# Filtered phage metadata
curl "http://localhost:8000/phage-metadata?where=Source_DB%20%3D%20%27RefSeq%27&limit=50"

# Single phage sequence
curl http://localhost:8000/phage/NC_001330.1/sequence

# Phage genome (concatenated)
curl "http://localhost:8000/phage/NC_001330.1/genome?mode=concat"

# Host genome stats
curl http://localhost:8000/host/GCF_000005845/genome-stats

# GFF3 annotations
curl http://localhost:8000/phage/NC_001330.1/gff3

# GFF3 stats
curl http://localhost:8000/gff3/stats

# BLAST databases and status
curl http://localhost:8000/blast/databases
curl http://localhost:8000/blast/status

# BLAST search
curl -X POST http://localhost:8000/blast/search \
  -H "Content-Type: application/json" \
  -d '{"sequence": "ATGCGTTTACG...", "program": "blastn", "db": "phages", "max_hits": 10}'

# SQL query
curl -X POST http://localhost:8000/query \
  -H "Content-Type: application/json" \
  -d '{"query": "SELECT Source_DB, COUNT(*) FROM fact_phages GROUP BY Source_DB"}'

Python (APIClient)

from pbi import APIClient

client = APIClient("http://localhost:8000")

# Health and stats
client.health()
client.get_stats()

# Metadata queries
phages = client.get_phage_metadata(where_clause="Source_DB = 'RefSeq'", limit=50)
hosts = client.get_host_metadata(limit=100)
pairs = client.get_phage_host_metadata(limit=100)

# Sequence retrieval
seq = client.get_phage_sequence("NC_001330.1")
genome = client.get_phage_genome("NC_001330.1", mode="concat")
host_genome = client.get_host_genome("GCF_000005845", mode="concat")

# GFF3 annotations
gff3 = client.get_phage_gff3("NC_001330.1")
print(gff3[:500])  # First 500 chars

# BLAST search
print(client.blast_status())
hits = client.blast_search("ATGCGTTTACG...", program="blastn", db="phages")
print(hits.head())

# SQL query
df = client.query("SELECT Source_DB, COUNT(*) as cnt FROM fact_phages GROUP BY Source_DB")

client.close()

Query Parameters

Metadata Endpoints

Parameter Type Default Description
where string — SQL WHERE clause (validated for safety)
limit int 100 Maximum rows returned

Genome Endpoints

Parameter Type Default Description
mode string concat concat (single string), list (array), dict (contig→seq)
gap int 100 Ns between contigs in concat mode
order string length Contig sort: length, name, or file

Security

  • All queries are read-only (SELECT only)
  • WHERE clauses are validated against injection patterns
  • The API runs inside the Docker network; expose only if needed

Remote Access

You can query the API from your laptop while PBI-Scope runs on a remote server. All data stays on the server — only lightweight queries and results travel over the network.

The simplest and safest approach. No changes to docker-compose.yml required.

1. Start the API on the server:

ssh user@your-server
cd /path/to/PBI-Scope
docker compose up -d api

2. Create an SSH tunnel from your laptop:

ssh -L 8000:localhost:8000 user@your-server

Port forwarding

The local port (8000) must match the API container port (8000). If you changed the API port in docker-compose.yml, update the tunnel accordingly:

ssh -L 8000:localhost:<your-api-port> user@your-server

Quick test

Verify the tunnel works by querying the API stats from your laptop:

python -c "from pbi import APIClient; c = APIClient('http://localhost:8000'); print(c.get_stats()); c.close()"
You should see a dictionary with database statistics (phages, proteins, hosts, etc.).

3. Use it from your laptop:

from pbi import APIClient

client = APIClient("http://localhost:8000")
stats = client.get_stats()
print(f"Phages: {stats['database']['phages']:,}")
client.close()

The tunnel encrypts all traffic. Safe even without API authentication.

Install pbi Locally

The APIClient only needs requests and pandas. Install the package on your laptop:

git clone https://github.com/ThibaultSchowing/PBI-Scope.git
cd PBI-Scope
pip install -e .

Python 3.12+ or conda: 'externally-managed-environment' error

If you see this error, you have two options:

Option A: Use the --break-system-packages flag (safe in conda environments):

pip install -e . --break-system-packages

Option B: Use Python 3.11 (avoids the restriction entirely):

conda create -n pbi_env python=3.11 -y
conda activate pbi_env
pip install -e .

You do not need duckdb, pyfaidx, or the data volume on your laptop. Those are only required for direct database access.

Use from a Notebook

After setting up the SSH tunnel, use the API in any notebook on your laptop:

from pbi import APIClient
import pandas as pd

client = APIClient("http://localhost:8000")

# Metadata queries
phages = client.get_phage_metadata(where_clause="Source_DB = 'RefSeq'", limit=100)
hosts = client.get_host_metadata(limit=50)

# SQL exploration
result = client.query("""
    SELECT Source_DB, COUNT(*) as cnt
    FROM fact_phages
    GROUP BY Source_DB
    ORDER BY cnt DESC
""")
print(result)

# Single sequence retrieval
seq = client.get_phage_sequence("NC_001330.1")
print(f"Sequence length: {len(seq):,} bp")

client.close()

What You Need

Component Where Required
API running Server Yes
SSH tunnel Laptop → Server Yes (unless using reverse proxy)
pbi package Laptop Yes (pip install -e .)
Database + FASTA Server only No (accessed via API)

Reverse Proxy (Optional, Advanced)

For team access or permanent setups, a reverse proxy exposes the API via HTTPS. This requires additional configuration and a security warning.

Security

The API has no built-in authentication. Exposing it directly to the internet allows anyone to query your database. Always add authentication (basic auth, VPN, or firewall rules) before exposing the API.

Caddy example (simplest):

# Add to docker-compose.yml
caddy:
  image: caddy:2-alpine
  ports:
    - "443:443"
    - "80:80"
  volumes:
    - ./Caddyfile:/etc/caddy/Caddyfile
    - caddy_data:/data
  networks:
    - pbi-network
# Caddyfile
api.yourserver.com {
    reverse_proxy pbi-api:8000
}

See the Caddy documentation for TLS configuration and authentication options.

Troubleshooting

Problem Cause Solution
Connection refused API not running or tunnel not active Check docker compose ps on server; verify tunnel is running
Connection timed out Firewall blocking port Open port 8000 on server firewall, or use SSH tunnel
ModuleNotFoundError: pbi Package not installed locally Run pip install -e . from the cloned repo
HTTPError 404 Endpoint doesn't exist Check API docs; ensure you're using the right URL path
HTTPError 500 Server-side error Check API logs: docker compose logs api

See Also