First Steps
This tutorial walks you through creating your first zine catalog using the ZineCore2 API. You'll create an agent (creator), a repository, a zine, and a holding record.
Prerequisites
- ✅ ZineCore2 server installed and running
- ✅ Superuser account created
- ✅ API accessible at http://localhost:8000
Overview
We'll create records in this order:
- Agent (creator of the zine)
- Repository (where the zine is held)
- Zine (the bibliographic record)
- Holding (linking the zine to the repository)
This order ensures that when we create the zine, we can reference the agent by ID, and when we create the holding, we can reference both the zine and repository.
Step 1: Get an API Token
The API requires authentication for write operations.
Option A: Via curl
curl -X POST http://localhost:8000/api/auth/token/ \
-H "Content-Type: application/json" \
-d '{"username": "admin", "password": "yourpassword"}'
Response:
{
"token": "abc123def456..."
}
Save this token — you'll use it for all write operations.
Option B: Via Browsable API
- Visit http://localhost:8000/api/
- Click "Log in" in the top right
- Enter your superuser credentials
- You're now authenticated for browsable API use
Step 2: Create an Agent (Creator)
Let's create an agent record for the zine creator.
Using curl
curl -X POST http://localhost:8000/api/agents/ \
-H "Content-Type: application/json" \
-H "Authorization: Token YOUR_TOKEN_HERE" \
-d '{
"id": "agent_judith_arcana",
"kind": "Person",
"display_name": "Judith Arcana",
"pronouns": ["she/her"],
"biography": "Feminist writer and activist, creator of reproductive rights zines.",
"website": "https://juditharcana.com",
"roles": ["creator", "editor"],
"public": true
}'
Using Python
import requests
API_BASE = "http://localhost:8000/api"
TOKEN = "YOUR_TOKEN_HERE"
headers = {
"Authorization": f"Token {TOKEN}",
"Content-Type": "application/json"
}
agent_data = {
"id": "agent_judith_arcana",
"kind": "Person",
"display_name": "Judith Arcana",
"pronouns": ["she/her"],
"biography": "Feminist writer and activist, creator of reproductive rights zines.",
"website": "https://juditharcana.com",
"roles": ["creator", "editor"],
"public": True
}
response = requests.post(
f"{API_BASE}/agents/",
headers=headers,
json=agent_data
)
print(response.status_code) # Should be 201 Created
agent = response.json()
print(f"Created agent: {agent['display_name']}")
Using JavaScript
const API_BASE = "http://localhost:8000/api";
const TOKEN = "YOUR_TOKEN_HERE";
const agentData = {
id: "agent_judith_arcana",
kind: "Person",
display_name: "Judith Arcana",
pronouns: ["she/her"],
biography: "Feminist writer and activist, creator of reproductive rights zines.",
website: "https://juditharcana.com",
roles: ["creator", "editor"],
public: true
};
const response = await fetch(`${API_BASE}/agents/`, {
method: "POST",
headers: {
"Authorization": `Token ${TOKEN}`,
"Content-Type": "application/json"
},
body: JSON.stringify(agentData)
});
const agent = await response.json();
console.log(`Created agent: ${agent.display_name}`);
Expected Response (201 Created):
{
"id": "agent_judith_arcana",
"kind": "Person",
"display_name": "Judith Arcana",
"pronouns": ["she/her"],
"biography": "Feminist writer and activist, creator of reproductive rights zines.",
"website": "https://juditharcana.com",
"roles": ["creator", "editor"],
"public": true,
"created_at": "2024-02-25T10:30:00Z",
"updated_at": "2024-02-25T10:30:00Z"
}
Step 3: Create a Repository
Now create a repository record for where the zine will be held.
curl -X POST http://localhost:8000/api/repositories/ \
-H "Content-Type: application/json" \
-H "Authorization: Token YOUR_TOKEN_HERE" \
-d '{
"id": "repo_my_personal_collection",
"repository_name": "My Personal Zine Collection",
"repository_kind": "personal-collection",
"description": "Personal collection of feminist and queer zines.",
"city": "Seattle",
"region": "WA",
"country": "US",
"established": "2020",
"status": "active"
}'
Expected Response (201 Created):
{
"id": "repo_my_personal_collection",
"repository_name": "My Personal Zine Collection",
"repository_kind": "personal-collection",
"description": "Personal collection of feminist and queer zines.",
"city": "Seattle",
"region": "WA",
"country": "US",
"established": "2020",
"status": "active",
"created_at": "2024-02-25T10:31:00Z"
}
Step 4: Create a Zine
Now create the bibliographic record for a zine, referencing the agent we created:
curl -X POST http://localhost:8000/api/zines/ \
-H "Content-Type: application/json" \
-H "Authorization: Token YOUR_TOKEN_HERE" \
-d '{
"id": "zine_mutate_3_1st",
"title": "Mutate Zine #3: Abortion Stories",
"series_title": ["Mutate Zine"],
"issue_designation": "#3",
"creator": ["agent_judith_arcana"],
"subject": ["feminism", "reproductive-rights", "personal-narratives"],
"genre": ["personal-zine"],
"date": ["2024"],
"language": ["en"],
"rights": ["cc-by-4.0"],
"abstract": "Personal narratives and essays about reproductive rights and abortion access.",
"format": ["Photocopy"],
"number_of_pages": "32"
}'
Expected Response (201 Created):
{
"id": "zine_mutate_3_1st",
"title": "Mutate Zine #3: Abortion Stories",
"series_title": ["Mutate Zine"],
"issue_designation": "#3",
"creator": [
{
"id": "agent_judith_arcana",
"display_name": "Judith Arcana",
"kind": "Person"
}
],
"subject": ["feminism", "reproductive-rights", "personal-narratives"],
"genre": ["personal-zine"],
"date": ["2024"],
"language": ["en"],
"rights": ["cc-by-4.0"],
"abstract": "Personal narratives and essays about reproductive rights and abortion access.",
"format": ["Photocopy"],
"number_of_pages": "32",
"created_at": "2024-02-25T10:32:00Z"
}
Note: The response resolves the creator field to full agent objects (read serializer), but you only need to provide agent IDs when creating (write serializer).
Step 5: Create a Holding
Finally, create a holding record linking the zine to your repository:
curl -X POST http://localhost:8000/api/holdings/ \
-H "Content-Type: application/json" \
-H "Authorization: Token YOUR_TOKEN_HERE" \
-d '{
"id": "holding_my_mutate_3",
"repository_id": "repo_my_personal_collection",
"zine_id": "zine_mutate_3_1st",
"location": "Bookshelf 2 - Feminist Zines",
"condition": "Excellent",
"copy_count": 1,
"access_status": "personal-use",
"notes": ["Acquired at Ladyfest 2024"]
}'
Expected Response (201 Created):
{
"id": "holding_my_mutate_3",
"repository": {
"id": "repo_my_personal_collection",
"repository_name": "My Personal Zine Collection"
},
"zine": {
"id": "zine_mutate_3_1st",
"title": "Mutate Zine #3: Abortion Stories"
},
"location": "Bookshelf 2 - Feminist Zines",
"condition": "Excellent",
"copy_count": 1,
"access_status": "personal-use",
"notes": ["Acquired at Ladyfest 2024"],
"created_at": "2024-02-25T10:33:00Z"
}
Step 6: Retrieve Your Records
Now that you've created records, retrieve them via the API.
Get All Zines
curl http://localhost:8000/api/zines/
No authentication needed for read operations!
Get Specific Zine
curl http://localhost:8000/api/zines/zine_mutate_3_1st/
Get Zine in Different Formats
JSON-LD:
curl -H "Accept: application/ld+json" \
http://localhost:8000/api/zines/zine_mutate_3_1st/
CSV:
curl -H "Accept: text/csv" \
http://localhost:8000/api/zines/
BibTeX:
curl -H "Accept: application/x-bibtex" \
http://localhost:8000/api/zines/zine_mutate_3_1st/
Step 7: Update a Record
Update the zine to add more information:
curl -X PATCH http://localhost:8000/api/zines/zine_mutate_3_1st/ \
-H "Content-Type: application/json" \
-H "Authorization: Token YOUR_TOKEN_HERE" \
-d '{
"publisher": ["Feminist Press Collective"],
"place_of_publication": ["Seattle, WA"]
}'
PATCH updates only the fields you provide. PUT replaces the entire record.
Step 8: Search and Filter
Filter Zines 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"
Search by Title
curl "http://localhost:8000/api/zines/?search=Mutate"
Step 9: Browse via Admin Interface
Visit the Django admin at http://localhost:8000/admin/ to:
- View all records in a user-friendly interface
- Edit records with form validation
- Bulk delete or update records
- See relationships between profiles
Complete Example Script
Here's a Python script that creates all four records:
import requests
API_BASE = "http://localhost:8000/api"
TOKEN = "YOUR_TOKEN_HERE"
headers = {
"Authorization": f"Token {TOKEN}",
"Content-Type": "application/json"
}
# 1. Create Agent
agent = requests.post(f"{API_BASE}/agents/", headers=headers, json={
"id": "agent_judith_arcana",
"kind": "Person",
"display_name": "Judith Arcana",
"public": True
}).json()
print(f"✓ Created agent: {agent['display_name']}")
# 2. Create Repository
repo = requests.post(f"{API_BASE}/repositories/", headers=headers, json={
"id": "repo_my_collection",
"repository_name": "My Personal Collection",
"repository_kind": "personal-collection",
"country": "US"
}).json()
print(f"✓ Created repository: {repo['repository_name']}")
# 3. Create Zine
zine = requests.post(f"{API_BASE}/zines/", headers=headers, json={
"id": "zine_mutate_3",
"title": "Mutate Zine #3",
"creator": ["agent_judith_arcana"],
"subject": ["feminism"],
"genre": ["personal-zine"],
"date": ["2024"],
"language": ["en"],
"rights": ["cc-by-4.0"]
}).json()
print(f"✓ Created zine: {zine['title']}")
# 4. Create Holding
holding = requests.post(f"{API_BASE}/holdings/", headers=headers, json={
"id": "holding_001",
"repository_id": "repo_my_collection",
"zine_id": "zine_mutate_3",
"condition": "Excellent"
}).json()
print(f"✓ Created holding at {holding['repository']['repository_name']}")
print("\n✅ Catalog created successfully!")
Validation Errors
If you get validation errors, the API will return details:
Example Error Response (400 Bad Request):
{
"title": ["This field is required."],
"creator": ["This field is required."],
"subject": ["This field must contain at least one item."]
}
Fix the issues and resubmit.
Next Steps
Now that you've created your first records:
- Configuration — Learn about environment variables
- API Reference — Explore all endpoints in detail
- Architecture — Understand models and serializers