在博客和 Sitio Astro 上集成多个 API:Dev.to 和 Hashnode
如果是的话,可能会在不同的博客平台上写入。在这种情况下,我们可以将 Hashnode 应用于不同的受众。但是,您是否可以在个人情况下发帖?您可以将 ambas API 集成到 Astro 的产品组合中。
艾尔·德萨菲奥
主要回忆录:
初始配置
Primero、有关我们需要的信息的接口定义:
interface BlogPost {
title: string;
brief: string;
slug: string;
dateAdded: string;
rawDate: string;
coverImage: string;
url: string;
source: string;
}
interface HashnodeEdge {
node: {
title: string;
brief: string;
slug: string;
dateAdded: string;
coverImage?: {
url: string;
};
url: string;
};
}整合开发
La API de Dev.to es RESTful y bastante directa。 Aquí está cómo la Implementé:
async function getDevToPosts() {
try {
const params = new URLSearchParams({
username: 'tuUsuario',
per_page: '20',
state: 'all',
sort: 'published_at',
order: 'desc'
});
const headers = {
'Accept': 'application/vnd.forem.api-v1+json'
};
// Agregar API key si está disponible
if (import.meta.env.DEV_TO_API_KEY) {
headers['api-key'] = import.meta.env.DEV_TO_API_KEY;
}
const response = await fetch(`https://dev.to/api/articles?${params}`, { headers });
if (!response.ok) {
throw new Error(`HTTP ${response.status}`);
}
const posts = await response.json();
return posts.map((post: any) => ({
title: post.title,
brief: post.description,
slug: post.slug,
dateAdded: formatDate(post.published_timestamp),
rawDate: post.published_timestamp,
coverImage: post.cover_image || '/images/default-post.png',
url: post.url,
source: 'devto'
}));
} catch (error) {
console.error('Error al obtener posts de Dev.to:', error);
return [];
}
}整合 Hashnode
使用 GraphQL 的 Hashnode,需要不同的配置:
async function getHashnodePosts() {
try {
const query = `
query {
publication(host: "tuBlog.hashnode.dev") {
posts(first: 20) {
edges {
node {
title
brief
slug
dateAdded: publishedAt
coverImage {
url
}
url
}
}
}
}
}
`;
const response = await fetch('https://gql.hashnode.com', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ query })
});
const { data } = await response.json();
return data.publication.posts.edges.map((edge: HashnodeEdge) => ({
title: edge.node.title,
brief: edge.node.brief,
slug: edge.node.slug,
dateAdded: formatDate(edge.node.dateAdded),
rawDate: edge.node.dateAdded,
coverImage: edge.node.coverImage?.url || '/images/default-post.png',
url: edge.node.url,
source: 'hashnode'
}));
} catch (error) {
console.error('Error al obtener posts de Hashnode:', error);
return [];
}
}合并结果
La Magia Ocurre al Combinar y Ordenar los posts:
const hashnodePosts = await getHashnodePosts(); const devtoPosts = await getDevToPosts(); const allBlogPosts = [...hashnodePosts, ...devtoPosts] .sort((a, b) => new Date(b.rawDate).getTime() - new Date(a.rawDate).getTime());
错误率限制
为了限制错误率,实施以下策略:
客户端拉出的缓存:
const CACHE_DURATION = 5 * 60 * 1000; // 5 minutos
let postsCache = {
data: null,
timestamp: 0
};
async function getAllPosts() {
const now = Date.now();
if (postsCache.data && (now - postsCache.timestamp) < CACHE_DURATION) {
return postsCache.data;
}
// Obtener y combinar posts...
postsCache = {
data: allBlogPosts,
timestamp: now
};
return allBlogPosts;
}回退指数的保留:
async function fetchWithRetry(url: string, options: any, retries = 3) {
for (let i = 0; i < retries; i++) {
try {
const response = await fetch(url, options);
if (response.status === 429) { // Rate limit
const retryAfter = response.headers.get('Retry-After') || '60';
await new Promise(resolve => setTimeout(resolve, parseInt(retryAfter) * 1000));
continue;
}
return response;
} catch (error) {
if (i === retries - 1) throw error;
await new Promise(resolve => setTimeout(resolve, Math.pow(2, i) * 1000));
}
}
}Astro 渲染
最后,渲染 los 帖子 en nuestro 组件 Astro:
--- const allBlogPosts = await getAllPosts(); ---{allBlogPosts.map((post) => ())} ![]()
未经允许的整合:
该代码已在 GitHub 上完成。
¿您所在的地方有集成其他博客平台吗? ¡比较经验和评论! 👇