
Integrating with Kantan CMS
Integrating with Kantan CMS: A Complete Guide
This guide will walk you through the process of integrating with the Kantan CMS API to collect data, manage collections, and handle form submissions.
Prerequisites
- Project ID and API Key
- List of required collections
- Form integration page identified
- Storage location (defaults to
./tmp/)
Table of Contents
- API Authentication
- Working with Collections
- Retrieving Records
- Form Integration
- Complete Integration Example
API Authentication
Before accessing any data from the Kantan CMS, you must validate your API key.
const validateApiKey = async (projectId, apiKey) => {
try {
const response = await fetch('/v1/api/api_key/validate', {
method: 'GET',
headers: {
'X-Project-Id': projectId,
'X-API-Key': apiKey
}
});
const data = await response.json();
if (data.status === 200) {
console.log('API key is valid');
return true;
} else {
console.error('API key validation failed');
return false;
}
} catch (error) {
console.error('Error validating API key:', error);
return false;
}
};
Working with Collections
Counting Collections
Before retrieving collections, it's useful to know how many there are:
const countCollections = async (projectId, apiKey) => {
try {
const response = await fetch('/v1/api/collections_count/', {
method: 'GET',
headers: {
'X-Project-Id': projectId,
'X-API-Key': apiKey
}
});
const data = await response.json();
return data.count;
} catch (error) {
console.error('Error counting collections:', error);
return 0;
}
};
Retrieving Collections
You'll need to retrieve all collections and then filter based on your requirements:
const getCollections = async (projectId, apiKey, requiredCollections) => {
try {
const count = await countCollections(projectId, apiKey);
const pageSize = 100;
const pages = Math.ceil(count / pageSize);
let allCollections = [];
for (let page = 1; page <= pages; page++) {
const response = await fetch(`/v1/api/collections/?page_size=${pageSize}&page_num=${page}`, {
method: 'GET',
headers: {
'X-Project-Id': projectId,
'X-API-Key': apiKey
}
});
const data = await response.json();
allCollections = [...allCollections, ...data.collections];
}
// Filter collections based on requirements
if (requiredCollections && requiredCollections.length > 0) {
return allCollections.filter(collection =>
requiredCollections.includes(collection.name)
);
}
return allCollections;
} catch (error) {
console.error('Error retrieving collections:', error);
return [];
}
};
Retrieving Records
Counting Records
First, count the records in a collection:
const countRecords = async (projectId, apiKey, collectionId) => {
try {
const response = await fetch(`/v1/api/collections/${collectionId}/records_count/`, {
method: 'GET',
headers: {
'X-Project-Id': projectId,
'X-API-Key': apiKey
}
});
const data = await response.json();
return data.count;
} catch (error) {
console.error(`Error counting records for collection ${collectionId}:`, error);
return 0;
}
};
Retrieving Records from a Collection
const getRecords = async (projectId, apiKey, collectionId, storagePath = './tmp/') => {
try {
const count = await countRecords(projectId, apiKey, collectionId);
const pageSize = 100;
const pages = Math.ceil(count / pageSize);
let allRecords = [];
for (let page = 1; page <= pages; page++) {
const response = await fetch(`/v1/api/collections/${collectionId}/records/?page_size=${pageSize}&page_num=${page}`, {
method: 'GET',
headers: {
'X-Project-Id': projectId,
'X-API-Key': apiKey
}
});
const data = await response.json();
allRecords = [...allRecords, ...data.records];
}
// Save records to file
const fs = require('fs');
const path = require('path');
// Ensure directory exists
if (!fs.existsSync(storagePath)) {
fs.mkdirSync(storagePath, { recursive: true });
}
// Get collection details to use as filename
const collectionResponse = await fetch(`/v1/api/collections/${collectionId}`, {
method: 'GET',
headers: {
'X-Project-Id': projectId,
'X-API-Key': apiKey
}
});
const collectionData = await collectionResponse.json();
const collectionName = collectionData.collection.name;
// Write to file
fs.writeFileSync(
path.join(storagePath, `${collectionName}.json`),
JSON.stringify(allRecords, null, 2)
);
return allRecords;
} catch (error) {
console.error(`Error retrieving records for collection ${collectionId}:`, error);
return [];
}
};
Form Integration
Getting a Form Token
const getFormToken = async (collectionId) => {
try {
const response = await fetch(`/v1/api/form_token/${collectionId}`, {
method: 'GET'
});
const data = await response.json();
return data.token;
} catch (error) {
console.error('Error getting form token:', error);
return null;
}
};
Form Submission
Here's an example of how to integrate a form submission into your page:
// In your HTML page:
/*
<form id="myForm">
<input type="text" name="name" placeholder="Your Name" required>
<input type="email" name="email" placeholder="Your Email" required>
<textarea name="message" placeholder="Your Message" required></textarea>
<button type="submit">Submit</button>
</form>
*/
const initializeForm = async (formElement, collectionId) => {
// Get form token
const token = await getFormToken(collectionId);
if (!token) {
console.error('Failed to get form token');
return;
}
formElement.addEventListener('submit', async (event) => {
event.preventDefault();
// Collect form data
const formData = new FormData(formElement);
const data = {};
for (let [key, value] of formData.entries()) {
data[key] = value;
}
try {
const response = await fetch(`/v1/api/form/${collectionId}`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
token,
data
})
});
if (response.ok) {
alert('Form submitted successfully!');
formElement.reset();
} else {
alert('Failed to submit form. Please try again.');
}
} catch (error) {
console.error('Error submitting form:', error);
alert('An error occurred. Please try again later.');
}
});
};
// Initialize the form
document.addEventListener('DOMContentLoaded', () => {
const form = document.getElementById('myForm');
const collectionId = 'your-form-collection-id'; // Replace with actual ID
if (form) {
initializeForm(form, collectionId);
}
});
Complete Integration Example
Here's a complete example that puts everything together:
const KantanCMS = {
projectId: 'your-project-id', // Replace with actual ID
apiKey: 'your-api-key', // Replace with actual key
requiredCollections: ['blog', 'products'], // Replace with your required collections
formPageId: 'contact', // Replace with your form page ID
storagePath: './tmp/', // Default storage path
// Initialize the integration
async initialize() {
// Validate API key
const isValid = await this.validateApiKey();
if (!isValid) {
console.error('Failed to authenticate with Kantan CMS');
return false;
}
// Get and process collections
const collections = await this.getCollections();
if (collections.length === 0) {
console.warn('No collections found or matching requirements');
} else {
console.log(`Found ${collections.length} collections`);
// Process each collection
for (const collection of collections) {
await this.getRecords(collection.id);
}
}
// Initialize form if on the correct page
if (window.location.pathname.includes(this.formPageId)) {
const form = document.getElementById('myForm');
if (form) {
// Find the form collection
const formCollection = collections.find(c => c.type === 'form');
if (formCollection) {
await this.initializeForm(form, formCollection.id);
} else {
console.error('No form collection found');
}
}
}
return true;
},
// API validation method
async validateApiKey() {
try {
const response = await fetch('/v1/api/api_key/validate', {
method: 'GET',
headers: {
'X-Project-Id': this.projectId,
'X-API-Key': this.apiKey
}
});
const data = await response.json();
return data.status === 200;
} catch (error) {
console.error('Error validating API key:', error);
return false;
}
},
// Count collections method
async countCollections() {
try {
const response = await fetch('/v1/api/collections_count/', {
method: 'GET',
headers: {
'X-Project-Id': this.projectId,
'X-API-Key': this.apiKey
}
});
const data = await response.json();
return data.count;
} catch (error) {
console.error('Error counting collections:', error);
return 0;
}
},
// Get collections method
async getCollections() {
try {
const count = await this.countCollections();
const pageSize = 100;
const pages = Math.ceil(count / pageSize);
let allCollections = [];
for (let page = 1; page <= pages; page++) {
const response = await fetch(`/v1/api/collections/?page_size=${pageSize}&page_num=${page}`, {
method: 'GET',
headers: {
'X-Project-Id': this.projectId,
'X-API-Key': this.apiKey
}
});
const data = await response.json();
allCollections = [...allCollections, ...data.collections];
}
// Filter collections based on requirements
if (this.requiredCollections && this.requiredCollections.length > 0) {
return allCollections.filter(collection =>
this.requiredCollections.includes(collection.name)
);
}
return allCollections;
} catch (error) {
console.error('Error retrieving collections:', error);
return [];
}
},
// Count records method
async countRecords(collectionId) {
try {
const response = await fetch(`/v1/api/collections/${collectionId}/records_count/`, {
method: 'GET',
headers: {
'X-Project-Id': this.projectId,
'X-API-Key': this.apiKey
}
});
const data = await response.json();
return data.count;
} catch (error) {
console.error(`Error counting records for collection ${collectionId}:`, error);
return 0;
}
},
// Get records method
async getRecords(collectionId) {
try {
const count = await this.countRecords(collectionId);
const pageSize = 100;
const pages = Math.ceil(count / pageSize);
let allRecords = [];
for (let page = 1; page <= pages; page++) {
const response = await fetch(`/v1/api/collections/${collectionId}/records/?page_size=${pageSize}&page_num=${page}`, {
method: 'GET',
headers: {
'X-Project-Id': this.projectId,
'X-API-Key': this.apiKey
}
});
const data = await response.json();
allRecords = [...allRecords, ...data.records];
}
// Save records to file (server-side only)
if (typeof window === 'undefined') {
const fs = require('fs');
const path = require('path');
// Ensure directory exists
if (!fs.existsSync(this.storagePath)) {
fs.mkdirSync(this.storagePath, { recursive: true });
}
// Get collection details to use as filename
const collectionResponse = await fetch(`/v1/api/collections/${collectionId}`, {
method: 'GET',
headers: {
'X-Project-Id': this.projectId,
'X-API-Key': this.apiKey
}
});
const collectionData = await collectionResponse.json();
const collectionName = collectionData.collection.name;
// Write to file
fs.writeFileSync(
path.join(this.storagePath, `${collectionName}.json`),
JSON.stringify(allRecords, null, 2)
);
}
return allRecords;
} catch (error) {
console.error(`Error retrieving records for collection ${collectionId}:`, error);
return [];
}
},
// Get form token method
async getFormToken(collectionId) {
try {
const response = await fetch(`/v1/api/form_token/${collectionId}`, {
method: 'GET'
});
const data = await response.json();
return data.token;
} catch (error) {
console.error('Error getting form token:', error);
return null;
}
},
// Initialize form method
async initializeForm(formElement, collectionId) {
// Get form token
const token = await this.getFormToken(collectionId);
if (!token) {
console.error('Failed to get form token');
return;
}
formElement.addEventListener('submit', async (event) => {
event.preventDefault();
// Collect form data
const formData = new FormData(formElement);
const data = {};
for (let [key, value] of formData.entries()) {
data[key] = value;
}
try {
const response = await fetch(`/v1/api/form/${collectionId}`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
token,
data
})
});
if (response.ok) {
alert('Form submitted successfully!');
formElement.reset();
} else {
alert('Failed to submit form. Please try again.');
}
} catch (error) {
console.error('Error submitting form:', error);
alert('An error occurred. Please try again later.');
}
});
}
};
// Initialize the integration
document.addEventListener('DOMContentLoaded', async () => {
await KantanCMS.initialize();
});
Node.js Server Example
If you're integrating with a Node.js backend, here's an example:
const fetch = require('node-fetch');
const fs = require('fs');
const path = require('path');
class KantanCMSIntegration {
constructor(config) {
this.projectId = config.projectId;
this.apiKey = config.apiKey;
this.requiredCollections = config.requiredCollections || [];
this.storagePath = config.storagePath || './tmp/';
// Create storage directory if it doesn't exist
if (!fs.existsSync(this.storagePath)) {
fs.mkdirSync(this.storagePath, { recursive: true });
}
}
async init() {
// Validate API key
const isValid = await this.validateApiKey();
if (!isValid) {
console.error('Failed to authenticate with Kantan CMS');
return false;
}
// Get and process collections
const collections = await this.getCollections();
if (collections.length === 0) {
console.warn('No collections found or matching requirements');
} else {
console.log(`Found ${collections.length} collections`);
// Process each collection
for (const collection of collections) {
const records = await this.getRecords(collection.id);
console.log(`Retrieved ${records.length} records from collection ${collection.name}`);
}
}
return true;
}
// ... include all methods from the browser example above ...
}
// Usage
const config = {
projectId: 'your-project-id',
apiKey: 'your-api-key',
requiredCollections: ['blog', 'products'],
storagePath: './data/'
};
const kantanCMS = new KantanCMSIntegration(config);
kantanCMS.init()
.then(() => {
console.log('Kantan CMS integration completed successfully');
})
.catch(error => {
console.error('Failed to complete Kantan CMS integration:', error);
});
Bash Commands for API Interaction
If you prefer using the command line or need to script API interactions, here are bash commands using curl for key operations:
Validating the API Key
#!/bin/bash
PROJECT_ID="your-project-id"
API_KEY="your-api-key"
STORAGE_PATH="./tmp"
# Create storage directory if it doesn't exist
mkdir -p "$STORAGE_PATH"
# Validate API key
validate_response=$(curl -s -X GET "/v1/api/api_key/validate" \
-H "X-Project-Id: $PROJECT_ID" \
-H "X-API-Key: $API_KEY")
if [[ "$validate_response" == *"\"status\":200"* ]]; then
echo "API key validation successful"
else
echo "API key validation failed"
exit 1
fi
Get All Collections and Records
#!/bin/bash
PROJECT_ID="your-project-id"
API_KEY="your-api-key"
STORAGE_PATH="./tmp"
REQUIRED_COLLECTIONS=("blog" "products") # Add your required collections
# Get collection count
collection_count_response=$(curl -s -X GET "/v1/api/collections_count/" \
-H "X-Project-Id: $PROJECT_ID" \
-H "X-API-Key: $API_KEY")
collection_count=$(echo "$collection_count_response" | grep -o '"count":[0-9]*' | cut -d ":" -f2)
echo "Total collections: $collection_count"
# Calculate pages needed (100 per page)
page_size=100
pages=$(( (collection_count + page_size - 1) / page_size ))
# Get all collections
all_collections=()
for ((page=1; page<=pages; page++)); do
echo "Fetching collections page $page of $pages..."
collections_response=$(curl -s -X GET "/v1/api/collections/?page_size=$page_size&page_num=$page" \
-H "X-Project-Id: $PROJECT_ID" \
-H "X-API-Key: $API_KEY")
# Save to file for processing
echo "$collections_response" > "$STORAGE_PATH/collections_page_$page.json"
# Extract collection IDs and names (requires jq)
if command -v jq >/dev/null 2>&1; then
collection_data=$(jq -r '.collections[] | "\(.id)|\(.name)"' "$STORAGE_PATH/collections_page_$page.json")
while IFS= read -r line; do
all_collections+=("$line")
done <<< "$collection_data"
fi
done
# Process each collection
for collection in "${all_collections[@]}"; do
IFS='|' read -r id name <<< "$collection"
# Check if this collection is in the required list
if [[ " ${REQUIRED_COLLECTIONS[*]} " == *" $name "* ]]; then
echo "Processing required collection: $name ($id)"
# Get record count for this collection
record_count_response=$(curl -s -X GET "/v1/api/collections/$id/records_count/" \
-H "X-Project-Id: $PROJECT_ID" \
-H "X-API-Key: $API_KEY")
record_count=$(echo "$record_count_response" | grep -o '"count":[0-9]*' | cut -d ":" -f2)
echo "Collection $name has $record_count records"
# Calculate pages needed for records (100 per page)
record_pages=$(( (record_count + page_size - 1) / page_size ))
# Create a file to store all records
echo "[]" > "$STORAGE_PATH/${name}_records.json"
# Get all records
for ((rpage=1; rpage<=record_pages; rpage++)); do
echo "Fetching records page $rpage of $record_pages for $name..."
records_response=$(curl -s -X GET "/v1/api/collections/$id/records/?page_size=$page_size&page_num=$rpage" \
-H "X-Project-Id: $PROJECT_ID" \
-H "X-API-Key: $API_KEY")
# Save to temporary file
echo "$records_response" > "$STORAGE_PATH/${name}_records_page_$rpage.json"
# Merge with main records file (requires jq)
if command -v jq >/dev/null 2>&1; then
jq -s '.[0] + .[1].records' "$STORAGE_PATH/${name}_records.json" "$STORAGE_PATH/${name}_records_page_$rpage.json" > "$STORAGE_PATH/${name}_records_temp.json"
mv "$STORAGE_PATH/${name}_records_temp.json" "$STORAGE_PATH/${name}_records.json"
fi
done
echo "Completed processing collection: $name"
fi
done
echo "All required collections processed and saved to $STORAGE_PATH"
Form Token and Submission Example
#!/bin/bash
COLLECTION_ID="your-form-collection-id"
# Get form token
token_response=$(curl -s -X GET "/v1/api/form_token/$COLLECTION_ID")
token=$(echo "$token_response" | grep -o '"token":"[^"]*"' | cut -d ":" -f2 | tr -d '"')
echo "Form token: $token"
# Submit form data
curl -X POST "/v1/api/form/$COLLECTION_ID" \
-H "Content-Type: application/json" \
-d '{
"token": "'"$token"'",
"data": {
"name": "John Doe",
"email": "john.doe@example.com",
"message": "This is a test message"
}
}'
These bash scripts provide a command-line alternative for interacting with the Kantan CMS API. They use curl for API requests and jq for JSON processing (which should be installed separately if you want to process the JSON responses).
For a simplified all-in-one script that handles the entire process:
#!/bin/bash
# Configuration
PROJECT_ID="your-project-id"
API_KEY="your-api-key"
STORAGE_PATH="./tmp"
REQUIRED_COLLECTIONS=("blog" "products") # Customize as needed
# Create storage directory
mkdir -p "$STORAGE_PATH"
# Validate API key
echo "Validating API key..."
validate_response=$(curl -s -X GET "/v1/api/api_key/validate" \
-H "X-Project-Id: $PROJECT_ID" \
-H "X-API-Key: $API_KEY")
if [[ "$validate_response" != *"\"status\":200"* ]]; then
echo "API key validation failed. Exiting."
exit 1
fi
echo "API key validated successfully."
# Function to download all records from a collection
download_collection_records() {
local collection_id=$1
local collection_name=$2
echo "Processing collection: $collection_name ($collection_id)"
# Get record count
local count_response=$(curl -s -X GET "/v1/api/collections/$collection_id/records_count/" \
-H "X-Project-Id: $PROJECT_ID" \
-H "X-API-Key: $API_KEY")
local record_count=$(echo "$count_response" | grep -o '"count":[0-9]*' | cut -d ":" -f2)
echo "Found $record_count records"
# Create empty file for records
echo "[]" > "$STORAGE_PATH/${collection_name}.json"
# Calculate number of pages (100 per page)
local page_size=100
local pages=$(( (record_count + page_size - 1) / page_size ))
# Download all pages
for ((page=1; page<=pages; page++)); do
echo "Downloading page $page of $pages..."
local records_response=$(curl -s -X GET "/v1/api/collections/$collection_id/records/?page_size=$page_size&page_num=$page" \
-H "X-Project-Id: $PROJECT_ID" \
-H "X-API-Key: $API_KEY")
# Save to temporary file
echo "$records_response" > "$STORAGE_PATH/${collection_name}_page_$page.json"
# If jq is available, merge with main file
if command -v jq >/dev/null 2>&1; then
jq -s '.[0] + .[1].records' "$STORAGE_PATH/${collection_name}.json" "$STORAGE_PATH/${collection_name}_page_$page.json" > "$STORAGE_PATH/${collection_name}_temp.json"
mv "$STORAGE_PATH/${collection_name}_temp.json" "$STORAGE_PATH/${collection_name}.json"
else
# Append to log if jq not available
echo "Downloaded page $page to ${collection_name}_page_$page.json" >> "$STORAGE_PATH/download_log.txt"
fi
done
echo "Completed downloading all records for $collection_name"
}
# Get all collections
echo "Retrieving collections..."
collections_response=$(curl -s -X GET "/v1/api/collections/?page_size=100" \
-H "X-Project-Id: $PROJECT_ID" \
-H "X-API-Key: $API_KEY")
# Save collections to file
echo "$collections_response" > "$STORAGE_PATH/all_collections.json"
# Process each required collection
echo "Processing required collections..."
for collection_name in "${REQUIRED_COLLECTIONS[@]}"; do
# Extract collection ID (basic extraction without jq)
collection_id=$(echo "$collections_response" | grep -o "\"id\":\"[^\"]*\"" | grep -B1 "\"name\":\"$collection_name\"" | head -1 | cut -d ":" -f2 | tr -d '"')
if [[ -n "$collection_id" ]]; then
download_collection_records "$collection_id" "$collection_name"
else
echo "Collection '$collection_name' not found!"
fi
done
echo "Process completed. Data saved to $STORAGE_PATH"
Conclusion
This guide has shown you how to integrate with the Kantan CMS API to:
- Validate your API credentials
- Count and retrieve collections
- Filter collections based on requirements
- Count and retrieve records from collections
- Store records locally
- Integrate forms into your pages
- Use command-line tools for scripting API interactions
The provided code examples should be adapted to your specific project needs. Remember to replace placeholder values with your actual Project ID, API Key, and other configuration details.