Examples
Practical examples and tutorials for using the StormyCMS API in real-world applications.
Table of Contents
- Basic Setup
- Building a Blog
- Creating a Landing Page
- Managing Products
- Multi-language Support
- React Integration
- Next.js Integration
- Node.js Backend
Basic Setup
Install Required Packages
npm install graphql-request# oryarn add graphql-requestCreate API Client
import { GraphQLClient } from 'graphql-request';
class StormyCMS { constructor(apiKey, clientId) { this.client = new GraphQLClient('https://api.stormycms.com/graphql', { headers: { 'x-site-api-key': apiKey, 'x-client-id': clientId, }, }); }
async request(query, variables) { try { return await this.client.request(query, variables); } catch (error) { console.error('StormyCMS Error:', error); throw error; } }
// Query methods async getPages(limit = 20, offset = 0) { const query = ` query GetPages($limit: Int, $offset: Int) { pages(limit: $limit, offset: $offset) { id meta { title description keywords } layout_id components { id name text } } } `; return this.request(query, { limit, offset }); }
async getPage(id) { const query = ` query GetPage($id: ID!) { page(id: $id) { id meta { title description keywords } components { id name text props child_ids } } } `; return this.request(query, { id }); }
// Mutation methods async createPage(title, description, keywords = [], layoutId, components = []) { const mutation = ` mutation CreatePage($meta: MetadataInput!, $layoutId: ID!, $components: [ComponentInput!]!) { create_page( meta: $meta layout_id: $layoutId components: $components component_ids: [] ) { id meta { title description } } } `; return this.request(mutation, { meta: { title, description, keywords }, layoutId, components, }); }
async updatePage(id, title, description, keywords = []) { const mutation = ` mutation UpdatePage($id: ID!, $meta: MetadataInput!) { update_page( id: $id meta: $meta components: [] layout_id: "" component_ids: [] ) { id meta { title description } } } `; return this.request(mutation, { id, meta: { title, description, keywords } }); }
async deletePage(id) { const mutation = ` mutation DeletePage($id: ID!) { delete_page(id: $id) { id meta { title } } } `; return this.request(mutation, { id }); }}
export default StormyCMS;Building a Blog
Create Blog Post Structure
import StormyCMS from './stormycms';
const cms = new StormyCMS( process.env.STORMYCMS_API_KEY, process.env.STORMYCMS_CLIENT_ID);
// Create a new blog postexport async function createBlogPost(title, content, excerpt, tags = []) { const components = [ { name: 'BlogHeader', text: [{ locale: 'en', value: title }], props: [ { key: 'className', translations: [{ locale: 'en', value: 'blog-post-header' }] } ] }, { name: 'BlogContent', text: [{ locale: 'en', value: content }], props: [ { key: 'className', translations: [{ locale: 'en', value: 'blog-post-content' }] } ] }, { name: 'BlogExcerpt', text: [{ locale: 'en', value: excerpt }], props: [ { key: 'className', translations: [{ locale: 'en', value: 'blog-post-excerpt' }] } ] } ];
return await cms.createPage( title, excerpt, tags, 'blog-layout', // Your blog layout ID components );}
// Get all blog postsexport async function getBlogPosts(limit = 10, offset = 0) { const pages = await cms.getPages(limit, offset); return pages.pages.filter(page => page.layout_id === 'blog-layout' );}
// Get a single blog postexport async function getBlogPost(id) { return await cms.getPage(id);}Display Blog Posts
import React, { useState, useEffect } from 'react';import { getBlogPosts } from '../src/blog';
function BlogList() { const [posts, setPosts] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(null);
useEffect(() => { async function loadPosts() { try { const data = await getBlogPosts(); setPosts(data); } catch (err) { setError(err.message); } finally { setLoading(false); } }
loadPosts(); }, []);
if (loading) return <div>Loading posts...</div>; if (error) return <div>Error: {error}</div>;
return ( <div className="blog-list"> {posts.map(post => ( <article key={post.id} className="blog-post-preview"> <h2>{post.meta.title}</h2> <p>{post.meta.description}</p> <a href={`/blog/${post.id}`}>Read more</a> </article> ))} </div> );}
export default BlogList;Creating a Landing Page
import StormyCMS from './stormycms';
const cms = new StormyCMS( process.env.STORMYCMS_API_KEY, process.env.STORMYCMS_CLIENT_ID);
export async function createLandingPage(data) { const components = [ { name: 'HeroSection', text: [{ locale: 'en', value: data.headline }], props: [ { key: 'subheadline', translations: [{ locale: 'en', value: data.subheadline }] }, { key: 'ctaText', translations: [{ locale: 'en', value: data.ctaText }] }, { key: 'backgroundImage', translations: [{ locale: 'en', value: data.backgroundImage }] } ] }, { name: 'FeatureSection', text: [{ locale: 'en', value: data.featuresTitle }], props: [ { key: 'features', translations: [{ locale: 'en', value: JSON.stringify(data.features) }] } ] }, { name: 'TestimonialSection', text: [{ locale: 'en', value: data.testimonialsTitle }], props: [ { key: 'testimonials', translations: [{ locale: 'en', value: JSON.stringify(data.testimonials) }] } ] }, { name: 'FooterSection', text: [{ locale: 'en', value: data.footerText }], props: [ { key: 'links', translations: [{ locale: 'en', value: JSON.stringify(data.footerLinks) }] } ] } ];
return await cms.createPage( data.title, data.description, data.keywords, 'landing-layout', components );}
// Usageconst landingData = { title: 'Welcome to Our Product', description: 'The best solution for your needs', keywords: ['product', 'solution', 'innovation'], headline: 'Transform Your Business Today', subheadline: 'Join thousands of satisfied customers', ctaText: 'Get Started Free', backgroundImage: '/images/hero-bg.jpg', featuresTitle: 'Why Choose Us', features: [ { title: 'Fast', description: 'Lightning quick performance' }, { title: 'Secure', description: 'Enterprise-grade security' }, { title: 'Scalable', description: 'Grows with your business' } ], testimonialsTitle: 'What Our Customers Say', testimonials: [ { name: 'John Doe', text: 'Amazing product!', company: 'Tech Corp' }, { name: 'Jane Smith', text: 'Changed everything', company: 'Design Inc' } ], footerText: '© 2024 Your Company', footerLinks: [ { text: 'About', url: '/about' }, { text: 'Contact', url: '/contact' } ]};
createLandingPage(landingData);Managing Products
import StormyCMS from './stormycms';
const cms = new StormyCMS( process.env.STORMYCMS_API_KEY, process.env.STORMYCMS_CLIENT_ID);
export async function createProduct(product) { const components = [ { name: 'ProductHeader', text: [{ locale: 'en', value: product.name }], props: [ { key: 'price', translations: [{ locale: 'en', value: product.price.toString() }] }, { key: 'currency', translations: [{ locale: 'en', value: product.currency }] }, { key: 'sku', translations: [{ locale: 'en', value: product.sku }] } ] }, { name: 'ProductDescription', text: [{ locale: 'en', value: product.description }], props: [ { key: 'shortDescription', translations: [{ locale: 'en', value: product.shortDescription }] } ] }, { name: 'ProductImages', props: [ { key: 'images', translations: [{ locale: 'en', value: JSON.stringify(product.images) }] }, { key: 'thumbnail', translations: [{ locale: 'en', value: product.thumbnail }] } ] }, { name: 'ProductSpecs', props: [ { key: 'specifications', translations: [{ locale: 'en', value: JSON.stringify(product.specifications) }] } ] } ];
return await cms.createPage( product.name, product.shortDescription, product.tags, 'product-layout', components );}
// Example productconst newProduct = { name: 'Premium Widget', price: 99.99, currency: 'USD', sku: 'WIDGET-001', description: 'This is a detailed description of our premium widget...', shortDescription: 'High-quality widget for all your needs', images: [ '/images/widget-1.jpg', '/images/widget-2.jpg', '/images/widget-3.jpg' ], thumbnail: '/images/widget-thumb.jpg', specifications: { weight: '2.5 lbs', dimensions: '10x8x6 inches', material: 'Aluminum', warranty: '2 years' }, tags: ['widget', 'premium', 'aluminum']};
createProduct(newProduct);Multi-language Support
import StormyCMS from './stormycms';
const cms = new StormyCMS( process.env.STORMYCMS_API_KEY, process.env.STORMYCMS_CLIENT_ID);
export async function createMultiLanguagePage(data) { const components = [ { name: 'MultiLangContent', text: [ { locale: 'en', value: data.content.en }, { locale: 'es', value: data.content.es }, { locale: 'fr', value: data.content.fr } ], props: [ { key: 'title', translations: [ { locale: 'en', value: data.title.en }, { locale: 'es', value: data.title.es }, { locale: 'fr', value: data.title.fr } ] } ] } ];
const meta = { title: data.title.en, // Primary language description: data.description.en, keywords: data.keywords.en };
return await cms.createPage( meta.title, meta.description, meta.keywords, 'multilang-layout', components );}
// Usageconst multiLangData = { title: { en: 'Welcome', es: 'Bienvenido', fr: 'Bienvenue' }, content: { en: 'Welcome to our website!', es: '¡Bienvenido a nuestro sitio web!', fr: 'Bienvenue sur notre site web!' }, description: { en: 'A multi-language website', es: 'Un sitio web multiidioma', fr: 'Un site web multilingue' }, keywords: { en: ['welcome', 'website'], es: ['bienvenido', 'sitio web'], fr: ['bienvenue', 'site web'] }};
createMultiLanguagePage(multiLangData);React Integration
import { useState, useEffect } from 'react';import StormyCMS from '../stormycms';
export function useStormyPages(limit = 20, offset = 0) { const [pages, setPages] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(null);
useEffect(() => { const cms = new StormyCMS( process.env.REACT_APP_STORMYCMS_API_KEY, process.env.REACT_APP_STORMYCMS_CLIENT_ID );
async function loadPages() { try { const data = await cms.getPages(limit, offset); setPages(data.pages); } catch (err) { setError(err.message); } finally { setLoading(false); } }
loadPages(); }, [limit, offset]);
return { pages, loading, error };}
export function useStormyPage(id) { const [page, setPage] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null);
useEffect(() => { if (!id) return;
const cms = new StormyCMS( process.env.REACT_APP_STORMYCMS_API_KEY, process.env.REACT_APP_STORMYCMS_CLIENT_ID );
async function loadPage() { try { const data = await cms.getPage(id); setPage(data.page); } catch (err) { setError(err.message); } finally { setLoading(false); } }
loadPage(); }, [id]);
return { page, loading, error };}Next.js Integration
import { GraphQLClient } from 'graphql-request';
const client = new GraphQLClient('https://api.stormycms.com/graphql', { headers: { 'x-site-api-key': process.env.STORMYCMS_API_KEY, 'x-client-id': process.env.STORMYCMS_CLIENT_ID, },});
export async function getPages(limit = 20, offset = 0) { const query = ` query GetPages($limit: Int, $offset: Int) { pages(limit: $limit, offset: $offset) { id meta { title description } slug } } `;
const data = await client.request(query, { limit, offset }); return data.pages;}
export async function getPage(id) { const query = ` query GetPage($id: ID!) { page(id: $id) { id meta { title description } components { id name text props } } } `;
const data = await client.request(query, { id }); return data.page;}
// pages/blog/index.jsexport async function getStaticProps() { const posts = await getPages(20, 0);
return { props: { posts, }, revalidate: 60, // Revalidate every minute };}
export default function Blog({ posts }) { return ( <div> <h1>Blog Posts</h1> {posts.map(post => ( <article key={post.id}> <h2>{post.meta.title}</h2> <p>{post.meta.description}</p> <Link href={`/blog/${post.id}`}>Read more</Link> </article> ))} </div> );}Node.js Backend
import express from 'express';import StormyCMS from './stormycms';
const app = express();app.use(express.json());
const cms = new StormyCMS( process.env.STORMYCMS_API_KEY, process.env.STORMYCMS_CLIENT_ID);
// API Routesapp.get('/api/pages', async (req, res) => { try { const { limit = 20, offset = 0 } = req.query; const pages = await cms.getPages(parseInt(limit), parseInt(offset)); res.json(pages); } catch (error) { res.status(500).json({ error: error.message }); }});
app.get('/api/pages/:id', async (req, res) => { try { const page = await cms.getPage(req.params.id); res.json(page); } catch (error) { res.status(404).json({ error: 'Page not found' }); }});
app.post('/api/pages', async (req, res) => { try { const { title, description, keywords, layoutId, components } = req.body; const page = await cms.createPage(title, description, keywords, layoutId, components); res.status(201).json(page); } catch (error) { res.status(400).json({ error: error.message }); }});
app.put('/api/pages/:id', async (req, res) => { try { const { title, description, keywords } = req.body; const page = await cms.updatePage(req.params.id, title, description, keywords); res.json(page); } catch (error) { res.status(400).json({ error: error.message }); }});
app.delete('/api/pages/:id', async (req, res) => { try { await cms.deletePage(req.params.id); res.status(204).send(); } catch (error) { res.status(400).json({ error: error.message }); }});
app.listen(3000, () => { console.log('Server running on port 3000');});Best Practices
- Environment Variables: Never hardcode API keys
- Error Handling: Always wrap API calls in try-catch
- Caching: Implement caching for frequently accessed data
- Pagination: Use pagination for large datasets
- Validation: Validate data before sending mutations
- Rate Limiting: Respect API rate limits
- Type Safety: Use TypeScript for better development experience
Next Steps
- Getting Started - Set up your account
- GraphQL Queries - Learn to fetch data
- GraphQL Mutations - Learn to modify data
- API Reference - Complete API documentation
Last updated: 2/27/26, 3:48 AM