// TypeScript interfaces
interface Post {
userId: number;
id: number;
title: string;
body: string;
}
interface EnrichedPost extends Post {
content: string;
analytics: {
wordCount: number;
readingTimeMinutes: number;
characterCount: number;
estimatedViewTime: string;
};
seo: {
slug: string;
metaTitle: string;
metaDescription: string;
canonicalUrl: string;
};
social: {
twitterShareUrl: string;
linkedinShareUrl: string;
hashtags: string[];
};
transformedAt: string;
}
// Main Hub integration handler
export const handler = async (event: any): Promise<any> => {
try {
// First, fetch the original JSONPlaceholder data
const originalResponse = await fetch(event.url);
if (!originalResponse.ok) {
return {
statusCode: originalResponse.status,
body: 'Post not found'
};
}
const originalPost: Post = await originalResponse.json();
// Transform the data with analytics and enrichment
const enrichedPost = enrichPostData(originalPost);
return {
statusCode: 200,
headers: {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*',
'Cache-Control': 'public, max-age=300'
},
body: JSON.stringify(enrichedPost)
};
} catch (error) {
console.error('Post transformation error:', error);
return {
statusCode: 500,
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
error: 'Internal server error',
timestamp: new Date().toISOString()
})
};
}
};
// Data transformation function
function enrichPostData(post: Post): EnrichedPost {
const now = new Date().toISOString();
// Generate slug from title
const slug = post.title.toLowerCase()
.replace(/[^a-z0-9\s]/g, '')
.trim()
.replace(/\s+/g, '-')
.substring(0, 50);
// Calculate content analytics
const wordCount = post.body.split(/\s+/).length;
const readingTimeMinutes = Math.max(1, Math.round(wordCount / 200));
const characterCount = post.body.length;
// Generate meta description (first 155 chars)
const metaDescription = post.body.substring(0, 155) + '...';
// Create share URLs
const encodedTitle = encodeURIComponent(post.title);
const encodedUrl = encodeURIComponent(`https://myblog.com/posts/${slug}`);
return {
...post,
content: post.body,
analytics: {
wordCount,
readingTimeMinutes,
characterCount,
estimatedViewTime: readingTimeMinutes < 2 ? '30 seconds' : `${readingTimeMinutes} minutes`
},
seo: {
slug,
metaTitle: `${post.title} - Blog Post`,
metaDescription,
canonicalUrl: `https://myblog.com/posts/${slug}`
},
social: {
twitterShareUrl: `https://twitter.com/intent/tweet?text=${encodedTitle}&url=${encodedUrl}`,
linkedinShareUrl: `https://linkedin.com/sharing/share-offsite/?url=${encodedUrl}`,
hashtags: ['#blog', '#content', '#reading']
},
transformedAt: now
};
}