News Articles API
Overviewβ
The News Articles API provides comprehensive access to Ring Platform's news and content management system. This endpoint supports advanced filtering, pagination, search capabilities, and content creation for administrators.
Endpoint Detailsβ
- URL:
/api/news
- Methods:
GET
,POST
- Authentication: GET (Optional), POST (Required - Admin only)
- Rate Limit: 120 requests per minute for GET, 30 for POST
Ring Platform News Systemβ
Content Strategyβ
Ring Platform's news system is designed for professional networking and industry insights:
Content Categoriesβ
- Product Updates: Platform feature announcements
- Industry News: Technology and business insights
- Company Spotlights: Entity and member highlights
- Event Coverage: Conference and meetup reports
- Technical Articles: Development and engineering content
Visibility & Access Controlβ
- Public: Open access articles for general audience
- Member: Exclusive content for verified members
- Confidential: Premium insights for confidential-tier users
Content Management Featuresβ
- SEO Optimization: Meta titles, descriptions, keywords
- Rich Media: Featured images and gallery support
- Social Integration: Sharing and engagement features
- Analytics: View counts and engagement metrics
GET - List News Articlesβ
Query Parametersβ
Parameter | Type | Description | Default |
---|---|---|---|
category | string | Filter by news category | - |
status | string | Filter by status (draft, published, archived) | published |
visibility | string | Filter by visibility (public, member, confidential) | - |
featured | boolean | Filter featured articles only | - |
authorId | string | Filter by author ID | - |
search | string | Search in title, excerpt, content, tags | - |
tags | string | Comma-separated list of tags | - |
limit | number | Number of articles per page | 10 |
offset | number | Number of articles to skip | 0 |
sortBy | string | Sort field (publishedAt, title, views) | publishedAt |
sortOrder | string | Sort direction (asc, desc) | desc |
Request Formatβ
GET /api/news?category=product-updates&limit=20&featured=true
Response Formatβ
Success Response (200 OK)β
{
"success": true,
"data": [
{
"id": "news_123456789",
"title": "Ring Platform Launches Advanced Entity Management",
"slug": "ring-platform-launches-advanced-entity-management",
"excerpt": "Discover the new features that make managing your organization profile easier than ever",
"content": "We're excited to announce the launch of our enhanced entity management system...",
"authorId": "user_987654321",
"authorName": "Ring Platform Team",
"category": "product-updates",
"tags": ["platform", "entities", "features", "management"],
"featuredImage": "https://storage.ring.ck.ua/news/entity-management-hero.jpg",
"gallery": [
"https://storage.ring.ck.ua/news/gallery/screenshot1.jpg",
"https://storage.ring.ck.ua/news/gallery/screenshot2.jpg"
],
"status": "published",
"visibility": "public",
"featured": true,
"views": 1247,
"likes": 89,
"comments": 23,
"publishedAt": "2025-01-14T10:00:00Z",
"createdAt": "2025-01-14T09:30:00Z",
"updatedAt": "2025-01-14T17:20:00Z",
"seo": {
"metaTitle": "Ring Platform Launches Advanced Entity Management",
"metaDescription": "Discover the new features that make managing your organization profile easier than ever",
"keywords": ["ring platform", "entity management", "features"]
}
}
],
"pagination": {
"limit": 20,
"offset": 0,
"total": 1
},
"filters": {
"category": "product-updates",
"status": "published",
"featured": true,
"limit": 20,
"offset": 0,
"sortBy": "publishedAt",
"sortOrder": "desc"
}
}
Code Examplesβ
JavaScript/TypeScriptβ
interface NewsArticle {
id: string;
title: string;
slug: string;
excerpt: string;
content: string;
authorId: string;
authorName: string;
category: string;
tags: string[];
featuredImage?: string;
gallery: string[];
status: 'draft' | 'published' | 'archived';
visibility: 'public' | 'member' | 'confidential';
featured: boolean;
views: number;
likes: number;
comments: number;
publishedAt: string;
createdAt: string;
updatedAt: string;
seo?: {
metaTitle: string;
metaDescription: string;
keywords: string[];
};
}
interface NewsFilters {
category?: string;
status?: 'draft' | 'published' | 'archived';
visibility?: 'public' | 'member' | 'confidential';
featured?: boolean;
authorId?: string;
search?: string;
tags?: string[];
limit?: number;
offset?: number;
sortBy?: 'publishedAt' | 'title' | 'views';
sortOrder?: 'asc' | 'desc';
}
async function getNewsArticles(filters: NewsFilters = {}): Promise<{
data: NewsArticle[];
pagination: { limit: number; offset: number; total: number };
filters: NewsFilters;
}> {
const params = new URLSearchParams();
Object.entries(filters).forEach(([key, value]) => {
if (value !== undefined) {
if (Array.isArray(value)) {
params.append(key, value.join(','));
} else {
params.append(key, String(value));
}
}
});
const response = await fetch(`/api/news?${params.toString()}`);
if (!response.ok) {
const error = await response.json();
throw new Error(error.error || 'Failed to fetch news articles');
}
return response.json();
}
// Usage examples
try {
// Get featured articles
const featured = await getNewsArticles({ featured: true, limit: 5 });
// Search articles
const searchResults = await getNewsArticles({
search: 'blockchain',
category: 'technology'
});
// Get articles by tags
const taggedArticles = await getNewsArticles({
tags: ['platform', 'features'],
sortBy: 'views',
sortOrder: 'desc'
});
console.log('Featured articles:', featured.data.length);
} catch (error) {
console.error('Error:', error.message);
}
React Hook Exampleβ
import { useState, useEffect } from 'react';
interface UseNewsArticlesResult {
articles: NewsArticle[];
loading: boolean;
error: string | null;
pagination: { limit: number; offset: number; total: number };
loadMore: () => void;
refresh: () => void;
}
function useNewsArticles(filters: NewsFilters = {}): UseNewsArticlesResult {
const [articles, setArticles] = useState<NewsArticle[]>([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
const [pagination, setPagination] = useState({ limit: 10, offset: 0, total: 0 });
const fetchArticles = async (append = false) => {
try {
setLoading(true);
setError(null);
const currentOffset = append ? articles.length : 0;
const result = await getNewsArticles({
...filters,
offset: currentOffset
});
setArticles(prev => append ? [...prev, ...result.data] : result.data);
setPagination(result.pagination);
} catch (err) {
setError(err instanceof Error ? err.message : 'Unknown error');
} finally {
setLoading(false);
}
};
useEffect(() => {
fetchArticles();
}, [JSON.stringify(filters)]);
const loadMore = () => {
if (!loading && articles.length < pagination.total) {
fetchArticles(true);
}
};
const refresh = () => {
fetchArticles();
};
return { articles, loading, error, pagination, loadMore, refresh };
}
// Usage in component
function NewsListPage() {
const [filters, setFilters] = useState<NewsFilters>({
status: 'published',
limit: 12
});
const { articles, loading, error, pagination, loadMore } = useNewsArticles(filters);
const handleCategoryFilter = (category: string) => {
setFilters(prev => ({ ...prev, category, offset: 0 }));
};
const handleSearch = (search: string) => {
setFilters(prev => ({ ...prev, search, offset: 0 }));
};
if (loading && articles.length === 0) {
return <div>Loading news articles...</div>;
}
if (error) {
return <div>Error: {error}</div>;
}
return (
<div className="news-list">
<header>
<h1>Ring Platform News</h1>
<div className="filters">
<input
type="text"
placeholder="Search articles..."
onChange={(e) => handleSearch(e.target.value)}
/>
<select onChange={(e) => handleCategoryFilter(e.target.value)}>
<option value="">All Categories</option>
<option value="product-updates">Product Updates</option>
<option value="industry-news">Industry News</option>
<option value="company-spotlights">Company Spotlights</option>
</select>
</div>
</header>
<div className="articles-grid">
{articles.map(article => (
<article key={article.id} className="article-card">
{article.featuredImage && (
<img src={article.featuredImage} alt={article.title} />
)}
<div className="article-content">
<h2>{article.title}</h2>
<p>{article.excerpt}</p>
<div className="article-meta">
<span>By {article.authorName}</span>
<span>{new Date(article.publishedAt).toLocaleDateString()}</span>
<span>{article.views} views</span>
</div>
<div className="article-tags">
{article.tags.map(tag => (
<span key={tag} className="tag">#{tag}</span>
))}
</div>
</div>
</article>
))}
</div>
{articles.length < pagination.total && (
<button onClick={loadMore} disabled={loading}>
{loading ? 'Loading...' : 'Load More'}
</button>
)}
</div>
);
}
cURL Examplesβ
# Get all published articles
curl "https://ring.ck.ua/api/news?status=published&limit=10"
# Get featured articles
curl "https://ring.ck.ua/api/news?featured=true"
# Search articles
curl "https://ring.ck.ua/api/news?search=blockchain&category=technology"
# Get articles by tags
curl "https://ring.ck.ua/api/news?tags=platform,features&sortBy=views&sortOrder=desc"
# Get articles with pagination
curl "https://ring.ck.ua/api/news?limit=20&offset=40"
POST - Create News Articleβ
Authentication Requirementsβ
- ADMIN Role: Only administrators can create news articles
Request Formatβ
POST /api/news
Content-Type: application/json
Authorization: Bearer <admin_jwt_token>
Request Body Schemaβ
interface CreateNewsRequest {
title: string; // Required: 1-200 characters
content: string; // Required: Article content
excerpt: string; // Required: 1-500 characters
slug?: string; // Optional: Auto-generated if not provided
category?: string; // Optional: Default 'other'
tags?: string[]; // Optional: Max 10 tags
featuredImage?: string; // Optional: Image URL
gallery?: string[]; // Optional: Gallery image URLs
status?: 'draft' | 'published'; // Optional: Default 'draft'
visibility?: 'public' | 'member' | 'confidential'; // Optional: Default 'public'
featured?: boolean; // Optional: Default false
seo?: {
metaTitle?: string;
metaDescription?: string;
keywords?: string[];
};
}
Example Request Bodyβ
{
"title": "Ring Platform Introduces Advanced Analytics Dashboard",
"content": "We're excited to announce the launch of our new analytics dashboard that provides comprehensive insights into your professional network performance...",
"excerpt": "Discover powerful analytics tools to track your networking success and optimize your professional connections",
"category": "product-updates",
"tags": ["analytics", "dashboard", "insights", "networking"],
"featuredImage": "https://storage.ring.ck.ua/news/analytics-dashboard.jpg",
"status": "published",
"visibility": "public",
"featured": true,
"seo": {
"metaTitle": "Ring Platform Introduces Advanced Analytics Dashboard",
"metaDescription": "Discover powerful analytics tools to track your networking success",
"keywords": ["analytics", "dashboard", "networking", "insights"]
}
}
Response Formatβ
Success Response (200 OK)β
{
"success": true,
"data": {
"id": "news_987654321",
"title": "Ring Platform Introduces Advanced Analytics Dashboard",
"slug": "ring-platform-introduces-advanced-analytics-dashboard",
"content": "We're excited to announce the launch of our new analytics dashboard...",
"excerpt": "Discover powerful analytics tools to track your networking success",
"authorId": "admin_123456789",
"authorName": "Admin User",
"category": "product-updates",
"tags": ["analytics", "dashboard", "insights", "networking"],
"featuredImage": "https://storage.ring.ck.ua/news/analytics-dashboard.jpg",
"status": "published",
"visibility": "public",
"featured": true,
"views": 0,
"likes": 0,
"comments": 0,
"publishedAt": "2025-01-14T18:00:00Z",
"createdAt": "2025-01-14T18:00:00Z",
"updatedAt": "2025-01-14T18:00:00Z",
"seo": {
"metaTitle": "Ring Platform Introduces Advanced Analytics Dashboard",
"metaDescription": "Discover powerful analytics tools to track your networking success",
"keywords": ["analytics", "dashboard", "networking", "insights"]
}
},
"message": "News article created successfully"
}
Error Responsesβ
// 401 Unauthorized
{
"success": false,
"error": "Authentication required"
}
// 403 Forbidden
{
"success": false,
"error": "Admin access required"
}
// 400 Bad Request - Missing required fields
{
"success": false,
"error": "Title, content, and excerpt are required"
}
// 400 Bad Request - Duplicate slug
{
"success": false,
"error": "Article with this slug already exists"
}
Code Examplesβ
JavaScript/TypeScriptβ
async function createNewsArticle(articleData: CreateNewsRequest): Promise<NewsArticle> {
const response = await fetch('/api/news', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${getAdminToken()}`
},
body: JSON.stringify(articleData)
});
if (!response.ok) {
const error = await response.json();
throw new Error(error.error || 'Failed to create news article');
}
const result = await response.json();
return result.data;
}
// Usage
try {
const newArticle = await createNewsArticle({
title: 'New Platform Feature Announcement',
content: 'We are excited to introduce...',
excerpt: 'Learn about our latest platform improvements',
category: 'product-updates',
tags: ['features', 'announcement'],
status: 'published',
featured: true
});
console.log('Article created:', newArticle.id);
} catch (error) {
console.error('Creation failed:', error.message);
}
React Admin Form Exampleβ
import { useState } from 'react';
function CreateNewsForm() {
const [formData, setFormData] = useState<CreateNewsRequest>({
title: '',
content: '',
excerpt: '',
category: 'other',
tags: [],
status: 'draft',
visibility: 'public',
featured: false
});
const [loading, setLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
setLoading(true);
setError(null);
try {
const article = await createNewsArticle(formData);
alert('Article created successfully!');
// Reset form or redirect
setFormData({
title: '',
content: '',
excerpt: '',
category: 'other',
tags: [],
status: 'draft',
visibility: 'public',
featured: false
});
} catch (err) {
setError(err instanceof Error ? err.message : 'Unknown error');
} finally {
setLoading(false);
}
};
return (
<form onSubmit={handleSubmit} className="create-news-form">
<h2>Create News Article</h2>
<div className="form-group">
<label htmlFor="title">Title *</label>
<input
id="title"
type="text"
value={formData.title}
onChange={(e) => setFormData(prev => ({ ...prev, title: e.target.value }))}
required
maxLength={200}
/>
</div>
<div className="form-group">
<label htmlFor="excerpt">Excerpt *</label>
<textarea
id="excerpt"
value={formData.excerpt}
onChange={(e) => setFormData(prev => ({ ...prev, excerpt: e.target.value }))}
required
maxLength={500}
rows={3}
/>
</div>
<div className="form-group">
<label htmlFor="content">Content *</label>
<textarea
id="content"
value={formData.content}
onChange={(e) => setFormData(prev => ({ ...prev, content: e.target.value }))}
required
rows={10}
/>
</div>
<div className="form-row">
<div className="form-group">
<label htmlFor="category">Category</label>
<select
id="category"
value={formData.category}
onChange={(e) => setFormData(prev => ({ ...prev, category: e.target.value }))}
>
<option value="other">Other</option>
<option value="product-updates">Product Updates</option>
<option value="industry-news">Industry News</option>
<option value="company-spotlights">Company Spotlights</option>
<option value="technical">Technical</option>
</select>
</div>
<div className="form-group">
<label htmlFor="status">Status</label>
<select
id="status"
value={formData.status}
onChange={(e) => setFormData(prev => ({ ...prev, status: e.target.value as any }))}
>
<option value="draft">Draft</option>
<option value="published">Published</option>
</select>
</div>
</div>
<div className="form-group">
<label>
<input
type="checkbox"
checked={formData.featured}
onChange={(e) => setFormData(prev => ({ ...prev, featured: e.target.checked }))}
/>
Featured Article
</label>
</div>
{error && <div className="error">{error}</div>}
<button type="submit" disabled={loading}>
{loading ? 'Creating...' : 'Create Article'}
</button>
</form>
);
}
Advanced Filteringβ
Search Functionalityβ
The search parameter performs full-text search across:
- Article title
- Excerpt content
- Full article content
- Tags
Tag Filteringβ
Multiple tags can be specified using comma separation:
/api/news?tags=blockchain,defi,ethereum
Combined Filtersβ
Filters can be combined for precise results:
/api/news?category=technology&featured=true&search=blockchain&limit=5
Pagination Strategyβ
Offset-Based Paginationβ
// Page 1 (first 10 articles)
const page1 = await getNewsArticles({ limit: 10, offset: 0 });
// Page 2 (next 10 articles)
const page2 = await getNewsArticles({ limit: 10, offset: 10 });
// Page 3 (next 10 articles)
const page3 = await getNewsArticles({ limit: 10, offset: 20 });
Infinite Scroll Implementationβ
function useInfiniteNews(filters: NewsFilters) {
const [allArticles, setAllArticles] = useState<NewsArticle[]>([]);
const [hasMore, setHasMore] = useState(true);
const loadMore = async () => {
const result = await getNewsArticles({
...filters,
offset: allArticles.length
});
setAllArticles(prev => [...prev, ...result.data]);
setHasMore(allArticles.length + result.data.length < result.pagination.total);
};
return { articles: allArticles, loadMore, hasMore };
}
SEO Optimizationβ
Automatic Slug Generationβ
If no slug is provided, the system automatically generates one:
const slug = title
.toLowerCase()
.replace(/[^a-z0-9 -]/g, '')
.replace(/\s+/g, '-')
.replace(/-+/g, '-')
.trim();
SEO Best Practicesβ
- Meta Titles: 50-60 characters for optimal display
- Meta Descriptions: 150-160 characters for search snippets
- Keywords: 5-10 relevant keywords for content categorization
- Featured Images: Optimized for social media sharing
Security Considerationsβ
- Admin-Only Creation: Only administrators can create/edit articles
- Input Validation: All content is validated and sanitized
- XSS Prevention: Content is properly escaped for display
- Rate Limiting: Prevents abuse with appropriate request limits
- Slug Uniqueness: Prevents URL conflicts and duplicate content
Related Endpointsβ
- News Article by ID - Get/update/delete specific article
- News Categories - Category management
- File Upload - Upload featured images and gallery
Changelogβ
- v1.0.0 - Initial implementation with basic listing and creation
- v1.1.0 - Added advanced filtering and search capabilities
- v1.2.0 - Enhanced SEO support and meta data
- v1.3.0 - Added pagination and infinite scroll support
- v1.4.0 - Improved security and admin controls