HTTP API¶
Want to use Quiver as a service? The built-in HTTP API has you covered! Let's explore how to set up and use Quiver's API to sling vectors over the network. 🌐
Setting Up the API Server¶
Basic Setup¶
Setting up the Quiver API server is straightforward:
package main
import (
"github.com/TFMV/quiver"
"github.com/TFMV/quiver/api"
"go.uber.org/zap"
)
func main() {
// Create a logger
logger, _ := zap.NewDevelopment()
// Initialize Quiver
idx, _ := quiver.New(quiver.Config{
Dimension: 128,
StoragePath: "./data",
}, logger)
defer idx.Close()
// Create the API server
server := api.NewServer(api.ServerOptions{
Port: "8080",
Prefork: false,
}, idx, logger)
// Start the server
server.Start()
}
This starts an HTTP server on port 8080 that exposes Quiver's functionality via REST endpoints.
Advanced Configuration¶
For production use, you'll want more configuration:
// Create the API server with advanced options
server := api.NewServer(api.ServerOptions{
Host: "0.0.0.0", // Listen on all interfaces
Port: "8080",
Prefork: true, // Use multiple processes for better performance
// Authentication
Auth: api.AuthOptions{
Enabled: true,
Username: "admin",
Password: "secure-password",
},
// Rate limiting
RateLimit: api.RateLimitOptions{
Enabled: true,
MaxRequests: 100,
TimeWindow: time.Minute,
},
// CORS
CORS: api.CORSOptions{
Enabled: true,
AllowOrigins: []string{"https://yourdomain.com"},
},
}, idx, logger)
TLS/HTTPS¶
For secure communication, enable TLS:
This ensures all API traffic is encrypted.
API Endpoints¶
Vector Operations¶
Add Vector¶
Add a vector to the index:
POST /vectors
Content-Type: application/json
{
"id": 1,
"vector": [0.1, 0.2, 0.3, ...],
"metadata": {
"category": "science",
"name": "black hole",
"tags": ["astronomy", "physics"]
}
}
Response:
Search¶
Search for similar vectors:
POST /search
Content-Type: application/json
{
"vector": [0.1, 0.2, 0.3, ...],
"k": 10,
"page": 1,
"pageSize": 10
}
Response:
{
"results": [
{
"id": 1,
"distance": 0.0,
"metadata": {
"category": "science",
"name": "black hole",
"tags": ["astronomy", "physics"]
}
},
// More results...
]
}
Hybrid Search¶
Search with metadata filtering:
POST /search/hybrid
Content-Type: application/json
{
"vector": [0.1, 0.2, 0.3, ...],
"k": 10,
"filter": "category = 'science' AND json_array_contains(tags, 'physics')"
}
Response:
{
"results": [
{
"id": 1,
"distance": 0.0,
"metadata": {
"category": "science",
"name": "black hole",
"tags": ["astronomy", "physics"]
}
},
// More results...
]
}
Metadata Operations¶
Query Metadata¶
Query metadata directly:
POST /metadata/query
Content-Type: application/json
{
"query": "SELECT * FROM metadata WHERE category = 'science' ORDER BY created_at DESC LIMIT 10"
}
Response:
{
"results": [
{
"category": "science",
"name": "black hole",
"tags": ["astronomy", "physics"]
},
// More results...
]
}
Management Operations¶
Health Check¶
Check if the server is healthy:
Response:
Metrics¶
Get server metrics:
Response:
{
"vector_count": 10000,
"memory_usage_mb": 256,
"search_latency_ms": 0.5,
"queries_per_second": 120
}
Using the API¶
cURL Examples¶
Add a Vector¶
curl -X POST http://localhost:8080/vectors \
-H "Content-Type: application/json" \
-d '{
"id": 1,
"vector": [0.1, 0.2, 0.3],
"metadata": {
"category": "example",
"name": "test vector"
}
}'
Search¶
curl -X POST http://localhost:8080/search \
-H "Content-Type: application/json" \
-d '{
"vector": [0.1, 0.2, 0.3],
"k": 5
}'
Python Client¶
Here's a simple Python client for the Quiver API:
import requests
import numpy as np
class QuiverClient:
def __init__(self, base_url, username=None, password=None):
self.base_url = base_url
self.auth = None
if username and password:
self.auth = (username, password)
def add_vector(self, id, vector, metadata):
response = requests.post(
f"{self.base_url}/vectors",
json={
"id": id,
"vector": vector.tolist() if isinstance(vector, np.ndarray) else vector,
"metadata": metadata
},
auth=self.auth
)
return response.json()
def search(self, vector, k=10, page=1, page_size=10):
response = requests.post(
f"{self.base_url}/search",
json={
"vector": vector.tolist() if isinstance(vector, np.ndarray) else vector,
"k": k,
"page": page,
"pageSize": page_size
},
auth=self.auth
)
return response.json()
def hybrid_search(self, vector, k=10, filter=None):
response = requests.post(
f"{self.base_url}/search/hybrid",
json={
"vector": vector.tolist() if isinstance(vector, np.ndarray) else vector,
"k": k,
"filter": filter
},
auth=self.auth
)
return response.json()
# Usage
client = QuiverClient("http://localhost:8080", "admin", "password")
# Add a vector
client.add_vector(
id=1,
vector=[0.1, 0.2, 0.3],
metadata={"category": "example", "name": "test vector"}
)
# Search
results = client.search([0.1, 0.2, 0.3], k=5)
print(results)
JavaScript Client¶
And here's a JavaScript client:
class QuiverClient {
constructor(baseUrl, username = null, password = null) {
this.baseUrl = baseUrl;
this.headers = {
'Content-Type': 'application/json'
};
if (username && password) {
this.headers['Authorization'] = 'Basic ' +
btoa(`${username}:${password}`);
}
}
async addVector(id, vector, metadata) {
const response = await fetch(`${this.baseUrl}/vectors`, {
method: 'POST',
headers: this.headers,
body: JSON.stringify({
id,
vector,
metadata
})
});
return response.json();
}
async search(vector, k = 10, page = 1, pageSize = 10) {
const response = await fetch(`${this.baseUrl}/search`, {
method: 'POST',
headers: this.headers,
body: JSON.stringify({
vector,
k,
page,
pageSize
})
});
return response.json();
}
async hybridSearch(vector, k = 10, filter = null) {
const response = await fetch(`${this.baseUrl}/search/hybrid`, {
method: 'POST',
headers: this.headers,
body: JSON.stringify({
vector,
k,
filter
})
});
return response.json();
}
}
// Usage
const client = new QuiverClient('http://localhost:8080', 'admin', 'password');
// Add a vector
client.addVector(
1,
[0.1, 0.2, 0.3],
{category: 'example', name: 'test vector'}
).then(result => console.log(result));
// Search
client.search([0.1, 0.2, 0.3], 5)
.then(results => console.log(results));
Performance Considerations¶
Server Configuration¶
For optimal performance:
- Enable
Prefork
mode for multi-core utilization - Use a reverse proxy like Nginx for SSL termination
- Configure appropriate timeouts for your use case
- Monitor server resources and scale as needed
Client Best Practices¶
- Reuse HTTP connections (connection pooling)
- Batch vector additions when possible
- Use appropriate timeout settings
- Implement retry logic for transient failures
Next Steps¶
Now that you've learned how to use Quiver's HTTP API, check out:
- Go Library - Use Quiver as a library
- Examples - See more usage examples
- Performance Tuning - Optimize Quiver for your needs