Framework Examples
This page provides ready-to-use code examples for popular frameworks and libraries. Copy these snippets to quickly integrate SheetsJSON into your projects.
React
Basic Data Fetching with Hooks
import { useState, useEffect } from 'react';
// Custom hook for fetching sheet data
function useSheetsJSON(accountSlug, sheetSlug, options = {}) {
const [data, setData] = useState([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
const fetchData = async () => {
setLoading(true);
setError(null);
try {
const url = new URL(
`https://api.sheetsjson.com/api/sheets/${accountSlug}/${sheetSlug}`
);
// Add query parameters
if (options.limit) url.searchParams.set('limit', options.limit);
if (options.offset) url.searchParams.set('offset', options.offset);
if (options.sort) url.searchParams.set('sort', options.sort);
// Add filters
if (options.filters) {
Object.entries(options.filters).forEach(([key, value]) => {
url.searchParams.set(`filter[${key}]`, value);
});
}
const response = await fetch(url, {
headers: options.apiKey
? { 'Authorization': `Bearer ${options.apiKey}` }
: {}
});
if (!response.ok) {
throw new Error(`HTTP error: ${response.status}`);
}
const result = await response.json();
setData(result.data || []);
} catch (err) {
setError(err.message);
} finally {
setLoading(false);
}
};
fetchData();
}, [accountSlug, sheetSlug, JSON.stringify(options)]);
return { data, loading, error };
}
// Example usage in a component
function ProductList() {
const { data: products, loading, error } = useSheetsJSON(
'my-account',
'products',
{
apiKey: process.env.REACT_APP_SHEETSJSON_API_KEY,
sort: '-price',
filters: { in_stock: 'true' }
}
);
if (loading) return <div>Loading...</div>;
if (error) return <div>Error: {error}</div>;
return (
<div className="grid grid-cols-3 gap-4">
{products.map((product) => (
<div key={product.id} className="border rounded-lg p-4">
<h3 className="font-bold">{product.name}</h3>
<p className="text-gray-600">{product.description}</p>
<p className="text-xl font-bold mt-2">${product.price}</p>
</div>
))}
</div>
);
}
export default ProductList;
React with TanStack Query (React Query)
For more advanced data fetching with caching, refetching, and mutations:
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
const API_BASE = 'https://api.sheetsjson.com/api/sheets';
const ACCOUNT = 'my-account';
const SHEET = 'products';
const API_KEY = process.env.REACT_APP_SHEETSJSON_API_KEY;
// Fetch function
async function fetchProducts(filters = {}) {
const url = new URL(`${API_BASE}/${ACCOUNT}/${SHEET}`);
Object.entries(filters).forEach(([key, value]) => {
if (value) url.searchParams.set(key, value);
});
const response = await fetch(url, {
headers: { 'Authorization': `Bearer ${API_KEY}` }
});
if (!response.ok) {
throw new Error('Failed to fetch products');
}
return response.json();
}
// Create function (Write API)
async function createProduct(productData) {
const response = await fetch(`${API_BASE}/${ACCOUNT}/${SHEET}`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify(productData)
});
if (!response.ok) {
const error = await response.json();
throw new Error(error.error || 'Failed to create product');
}
return response.json();
}
// Component using React Query
function ProductManager() {
const queryClient = useQueryClient();
// Query for fetching products
const { data, isLoading, error } = useQuery({
queryKey: ['products'],
queryFn: () => fetchProducts({ sort: 'name' }),
staleTime: 60000, // Consider data fresh for 1 minute
});
// Mutation for creating products
const createMutation = useMutation({
mutationFn: createProduct,
onSuccess: () => {
// Invalidate and refetch products after creating
queryClient.invalidateQueries({ queryKey: ['products'] });
},
});
const handleAddProduct = () => {
createMutation.mutate({
name: 'New Product',
price: '29.99',
category: 'Electronics'
});
};
if (isLoading) return <div>Loading...</div>;
if (error) return <div>Error: {error.message}</div>;
return (
<div>
<button
onClick={handleAddProduct}
disabled={createMutation.isPending}
className="bg-blue-600 text-white px-4 py-2 rounded mb-4"
>
{createMutation.isPending ? 'Adding...' : 'Add Product'}
</button>
{createMutation.isError && (
<div className="text-red-600 mb-4">
Error: {createMutation.error.message}
</div>
)}
<div className="grid grid-cols-3 gap-4">
{data?.data?.map((product) => (
<div key={product.id} className="border rounded p-4">
<h3>{product.name}</h3>
<p>${product.price}</p>
</div>
))}
</div>
</div>
);
}
export default ProductManager;
Vue.js
Vue 3 Composition API
<template>
<div>
<!-- Loading State -->
<div v-if="loading" class="text-center py-8">
<p>Loading products...</p>
</div>
<!-- Error State -->
<div v-else-if="error" class="text-red-600 p-4 bg-red-50 rounded">
{{ error }}
</div>
<!-- Products Grid -->
<div v-else class="grid grid-cols-3 gap-4">
<div
v-for="product in products"
:key="product.id"
class="border rounded-lg p-4 hover:shadow-lg transition-shadow"
>
<img
:src="product.image_url"
:alt="product.name"
class="w-full h-48 object-cover rounded mb-4"
>
<h3 class="font-bold text-lg">{{ product.name }}</h3>
<p class="text-gray-600 text-sm mt-1">{{ product.description }}</p>
<p class="text-xl font-bold mt-2">${{ product.price }}</p>
<button
@click="addToCart(product)"
class="w-full mt-4 bg-blue-600 text-white py-2 rounded hover:bg-blue-700"
>
Add to Cart
</button>
</div>
</div>
</div>
</template>
<script setup>
import { ref, onMounted, computed } from 'vue';
// Configuration
const API_BASE = 'https://api.sheetsjson.com/api/sheets';
const ACCOUNT_SLUG = 'my-account';
const SHEET_SLUG = 'products';
const API_KEY = import.meta.env.VITE_SHEETSJSON_API_KEY;
// State
const products = ref([]);
const loading = ref(true);
const error = ref(null);
// Fetch products
async function fetchProducts(params = {}) {
loading.value = true;
error.value = null;
try {
const url = new URL(`${API_BASE}/${ACCOUNT_SLUG}/${SHEET_SLUG}`);
// Add query parameters
Object.entries(params).forEach(([key, value]) => {
if (value) url.searchParams.set(key, value);
});
const response = await fetch(url, {
headers: API_KEY ? { 'Authorization': `Bearer ${API_KEY}` } : {}
});
if (!response.ok) {
throw new Error(`HTTP error: ${response.status}`);
}
const data = await response.json();
products.value = data.data || [];
} catch (err) {
error.value = err.message;
console.error('Failed to fetch products:', err);
} finally {
loading.value = false;
}
}
// Add to cart
function addToCart(product) {
console.log('Added to cart:', product);
// Implement your cart logic here
}
// Lifecycle
onMounted(() => {
fetchProducts({ sort: '-price', 'filter[in_stock]': 'true' });
});
</script>
Vue 3 Composable (Reusable)
Create a composable for reusable data fetching:
// composables/useSheetsJSON.js
import { ref, watch } from 'vue';
export function useSheetsJSON(accountSlug, sheetSlug, options = {}) {
const data = ref([]);
const loading = ref(false);
const error = ref(null);
const meta = ref(null);
const API_BASE = 'https://api.sheetsjson.com/api/sheets';
async function fetchData(params = {}) {
loading.value = true;
error.value = null;
try {
const url = new URL(`${API_BASE}/${accountSlug}/${sheetSlug}`);
// Merge default options with params
const allParams = { ...options, ...params };
Object.entries(allParams).forEach(([key, value]) => {
if (value !== undefined && value !== null && key !== 'apiKey') {
url.searchParams.set(key, value);
}
});
const headers = {};
if (options.apiKey) {
headers['Authorization'] = `Bearer ${options.apiKey}`;
}
const response = await fetch(url, { headers });
if (!response.ok) {
const errorData = await response.json();
throw new Error(errorData.error || `HTTP error: ${response.status}`);
}
const result = await response.json();
data.value = result.data || [];
meta.value = result.meta || null;
return result;
} catch (err) {
error.value = err.message;
throw err;
} finally {
loading.value = false;
}
}
async function createRow(rowData) {
loading.value = true;
error.value = null;
try {
const response = await fetch(`${API_BASE}/${accountSlug}/${sheetSlug}`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${options.apiKey}`,
'Content-Type': 'application/json'
},
body: JSON.stringify(rowData)
});
if (!response.ok) {
const errorData = await response.json();
throw new Error(errorData.error || 'Failed to create row');
}
// Refresh data after creation
await fetchData();
return response.json();
} catch (err) {
error.value = err.message;
throw err;
} finally {
loading.value = false;
}
}
return {
data,
loading,
error,
meta,
fetchData,
createRow,
refresh: fetchData
};
}
Usage in a component:
<script setup>
import { onMounted } from 'vue';
import { useSheetsJSON } from '@/composables/useSheetsJSON';
const { data: products, loading, error, fetchData, createRow } = useSheetsJSON(
'my-account',
'products',
{ apiKey: import.meta.env.VITE_SHEETSJSON_API_KEY }
);
onMounted(() => {
fetchData({ sort: 'name' });
});
async function handleAddProduct() {
await createRow({
name: 'New Product',
price: '19.99',
category: 'General'
});
}
</script>
Node.js
Express.js API Proxy
Create a secure backend proxy to protect your API key:
// server.js
const express = require('express');
const cors = require('cors');
const app = express();
app.use(cors());
app.use(express.json());
const SHEETSJSON_API_KEY = process.env.SHEETSJSON_API_KEY;
const SHEETSJSON_ACCOUNT = process.env.SHEETSJSON_ACCOUNT;
const API_BASE = 'https://api.sheetsjson.com/api/sheets';
// Proxy GET requests
app.get('/api/sheets/:sheet', async (req, res) => {
try {
const { sheet } = req.params;
const url = new URL(`${API_BASE}/${SHEETSJSON_ACCOUNT}/${sheet}`);
// Forward query parameters
Object.entries(req.query).forEach(([key, value]) => {
url.searchParams.set(key, value);
});
const response = await fetch(url, {
headers: {
'Authorization': `Bearer ${SHEETSJSON_API_KEY}`
}
});
const data = await response.json();
if (!response.ok) {
return res.status(response.status).json(data);
}
res.json(data);
} catch (error) {
console.error('Proxy error:', error);
res.status(500).json({ error: 'Internal server error' });
}
});
// Proxy POST requests (Write API)
app.post('/api/sheets/:sheet', async (req, res) => {
try {
const { sheet } = req.params;
const response = await fetch(`${API_BASE}/${SHEETSJSON_ACCOUNT}/${sheet}`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${SHEETSJSON_API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify(req.body)
});
const data = await response.json();
if (!response.ok) {
return res.status(response.status).json(data);
}
res.status(201).json(data);
} catch (error) {
console.error('Proxy error:', error);
res.status(500).json({ error: 'Internal server error' });
}
});
// Proxy PUT requests
app.put('/api/sheets/:sheet/:row', async (req, res) => {
try {
const { sheet, row } = req.params;
const response = await fetch(`${API_BASE}/${SHEETSJSON_ACCOUNT}/${sheet}/${row}`, {
method: 'PUT',
headers: {
'Authorization': `Bearer ${SHEETSJSON_API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify(req.body)
});
const data = await response.json();
if (!response.ok) {
return res.status(response.status).json(data);
}
res.json(data);
} catch (error) {
console.error('Proxy error:', error);
res.status(500).json({ error: 'Internal server error' });
}
});
// Proxy DELETE requests
app.delete('/api/sheets/:sheet/:row', async (req, res) => {
try {
const { sheet, row } = req.params;
const response = await fetch(`${API_BASE}/${SHEETSJSON_ACCOUNT}/${sheet}/${row}`, {
method: 'DELETE',
headers: {
'Authorization': `Bearer ${SHEETSJSON_API_KEY}`
}
});
const data = await response.json();
if (!response.ok) {
return res.status(response.status).json(data);
}
res.json(data);
} catch (error) {
console.error('Proxy error:', error);
res.status(500).json({ error: 'Internal server error' });
}
});
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});
Node.js Client Library
Create a reusable client for your Node.js applications:
// lib/sheetsjson-client.js
class SheetsJSONClient {
constructor(config) {
this.apiBase = 'https://api.sheetsjson.com/api/sheets';
this.accountSlug = config.accountSlug;
this.apiKey = config.apiKey;
}
async _request(method, path, body = null) {
const url = `${this.apiBase}/${this.accountSlug}${path}`;
const options = {
method,
headers: {
'Authorization': `Bearer ${this.apiKey}`
}
};
if (body) {
options.headers['Content-Type'] = 'application/json';
options.body = JSON.stringify(body);
}
const response = await fetch(url, options);
const data = await response.json();
if (!response.ok) {
const error = new Error(data.error || `HTTP error: ${response.status}`);
error.code = data.code;
error.status = response.status;
throw error;
}
return data;
}
// Read operations
async getRows(sheetSlug, params = {}) {
const url = new URL(`${this.apiBase}/${this.accountSlug}/${sheetSlug}`);
Object.entries(params).forEach(([key, value]) => {
if (value !== undefined && value !== null) {
url.searchParams.set(key, value);
}
});
const response = await fetch(url, {
headers: { 'Authorization': `Bearer ${this.apiKey}` }
});
const data = await response.json();
if (!response.ok) {
const error = new Error(data.error || `HTTP error: ${response.status}`);
error.code = data.code;
error.status = response.status;
throw error;
}
return data;
}
async getRow(sheetSlug, filter) {
const result = await this.getRows(sheetSlug, {
...Object.fromEntries(
Object.entries(filter).map(([k, v]) => [`filter[${k}]`, v])
),
limit: 1
});
return result.data?.[0] || null;
}
// Write operations
async createRow(sheetSlug, data) {
return this._request('POST', `/${sheetSlug}`, data);
}
async createRows(sheetSlug, rows) {
return this._request('POST', `/${sheetSlug}`, rows);
}
async updateRow(sheetSlug, rowNumber, data) {
return this._request('PUT', `/${sheetSlug}/${rowNumber}`, data);
}
async deleteRow(sheetSlug, rowNumber) {
return this._request('DELETE', `/${sheetSlug}/${rowNumber}`);
}
}
module.exports = SheetsJSONClient;
Usage:
const SheetsJSONClient = require('./lib/sheetsjson-client');
const client = new SheetsJSONClient({
accountSlug: 'my-account',
apiKey: process.env.SHEETSJSON_API_KEY
});
// Get all products
async function getProducts() {
const result = await client.getRows('products', {
sort: '-price',
limit: 10
});
console.log('Products:', result.data);
}
// Get a single product
async function getProduct(id) {
const product = await client.getRow('products', { id });
console.log('Product:', product);
}
// Create a product
async function createProduct() {
const result = await client.createRow('products', {
name: 'New Product',
price: '49.99',
category: 'Electronics'
});
console.log('Created:', result);
}
// Update a product
async function updateProduct(rowNumber) {
const result = await client.updateRow('products', rowNumber, {
price: '39.99'
});
console.log('Updated:', result);
}
// Delete a product
async function deleteProduct(rowNumber) {
const result = await client.deleteRow('products', rowNumber);
console.log('Deleted:', result);
}
Next.js
API Routes (App Router)
// app/api/products/route.ts
import { NextResponse } from 'next/server';
const API_BASE = 'https://api.sheetsjson.com/api/sheets';
const ACCOUNT = process.env.SHEETSJSON_ACCOUNT!;
const API_KEY = process.env.SHEETSJSON_API_KEY!;
export async function GET(request: Request) {
const { searchParams } = new URL(request.url);
const url = new URL(`${API_BASE}/${ACCOUNT}/products`);
// Forward search params
searchParams.forEach((value, key) => {
url.searchParams.set(key, value);
});
const response = await fetch(url, {
headers: { 'Authorization': `Bearer ${API_KEY}` },
next: { revalidate: 60 } // Cache for 60 seconds
});
const data = await response.json();
if (!response.ok) {
return NextResponse.json(data, { status: response.status });
}
return NextResponse.json(data);
}
export async function POST(request: Request) {
const body = await request.json();
const response = await fetch(`${API_BASE}/${ACCOUNT}/products`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify(body)
});
const data = await response.json();
if (!response.ok) {
return NextResponse.json(data, { status: response.status });
}
return NextResponse.json(data, { status: 201 });
}
Server Component
// app/products/page.tsx
async function getProducts() {
const res = await fetch(
`https://api.sheetsjson.com/api/sheets/${process.env.SHEETSJSON_ACCOUNT}/products`,
{
headers: {
'Authorization': `Bearer ${process.env.SHEETSJSON_API_KEY}`
},
next: { revalidate: 60 }
}
);
if (!res.ok) {
throw new Error('Failed to fetch products');
}
return res.json();
}
export default async function ProductsPage() {
const { data: products } = await getProducts();
return (
<div className="grid grid-cols-3 gap-4 p-8">
{products.map((product: any) => (
<div key={product.id} className="border rounded-lg p-4">
<h3 className="font-bold">{product.name}</h3>
<p className="text-gray-600">{product.description}</p>
<p className="text-xl font-bold mt-2">${product.price}</p>
</div>
))}
</div>
);
}
Python (Flask)
# app.py
from flask import Flask, jsonify, request
import requests
import os
app = Flask(__name__)
API_BASE = 'https://api.sheetsjson.com/api/sheets'
ACCOUNT = os.environ.get('SHEETSJSON_ACCOUNT')
API_KEY = os.environ.get('SHEETSJSON_API_KEY')
def get_headers():
return {'Authorization': f'Bearer {API_KEY}'}
@app.route('/api/products', methods=['GET'])
def get_products():
url = f'{API_BASE}/{ACCOUNT}/products'
params = dict(request.args)
response = requests.get(url, headers=get_headers(), params=params)
return jsonify(response.json()), response.status_code
@app.route('/api/products', methods=['POST'])
def create_product():
url = f'{API_BASE}/{ACCOUNT}/products'
response = requests.post(
url,
headers={**get_headers(), 'Content-Type': 'application/json'},
json=request.json
)
return jsonify(response.json()), response.status_code
@app.route('/api/products/<int:row>', methods=['PUT'])
def update_product(row):
url = f'{API_BASE}/{ACCOUNT}/products/{row}'
response = requests.put(
url,
headers={**get_headers(), 'Content-Type': 'application/json'},
json=request.json
)
return jsonify(response.json()), response.status_code
@app.route('/api/products/<int:row>', methods=['DELETE'])
def delete_product(row):
url = f'{API_BASE}/{ACCOUNT}/products/{row}'
response = requests.delete(url, headers=get_headers())
return jsonify(response.json()), response.status_code
if __name__ == '__main__':
app.run(debug=True)
Security Best Practices
- Never expose API keys in client-side code — Use a backend proxy
-
Use environment variables — Store keys in
.envfiles - Implement rate limiting — Protect your proxy endpoints
- Validate input — Sanitize data before sending to the API
- Use HTTPS — Always use secure connections
Related Documentation
- API Endpoints — Full API reference
- Write API — Create, update, and delete data
- Error Codes — Handle errors gracefully
- Rate Limits — Understand usage limits