Heim >Web-Frontend >js-Tutorial >Integration mehrerer Blog-APIs in eine Astro-Site: Dev.to und Hashnode

Integration mehrerer Blog-APIs in eine Astro-Site: Dev.to und Hashnode

Patricia Arquette
Patricia ArquetteOriginal
2024-12-08 04:59:15794Durchsuche

Integrando Múltiples APIs de Blog en un Sitio Astro: Dev.to y Hashnode

Wenn Sie wie ich sind, schreiben Sie wahrscheinlich auf mehreren Blogging-Plattformen. In meinem Fall verwende ich sowohl Dev.to als auch Hashnode, um unterschiedliche Zielgruppen zu erreichen. Aber was passiert, wenn Sie alle Ihre Beiträge auf Ihrer persönlichen Website anzeigen möchten? Heute zeige ich Ihnen, wie ich beide APIs in mein mit Astro erstelltes Portfolio integriert habe.

Die Herausforderung

Die größte Herausforderung war:

  1. Nachrichten von zwei verschiedenen APIs abrufen
  2. Datenformat vereinheitlichen
  3. Reihen Sie sie chronologisch
  4. Behandeln Sie Fehler und Ratenbegrenzungen
  5. Sicheres Tippen mit TypeScript

Erstkonfiguration

Zuerst definieren wir die Schnittstellen zur Eingabe unserer Daten:

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;
  };
}

Dev.to integrieren

Die Dev.to-API ist RESTful und ziemlich unkompliziert. So habe ich es umgesetzt:

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 integrieren

Hashnode verwendet GraphQL, was einen etwas anderen Ansatz erfordert:

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 [];
  }
}

Kombinieren der Ergebnisse

Die Magie entsteht beim Kombinieren und Ordnen der Beiträge:

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());

Fehlerbehandlung und Ratenbegrenzung

Um mit Ratenbegrenzungen und Fehlern umzugehen, habe ich die folgenden Strategien implementiert:

Clientseitiger Cache:

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;
}

Wiederholungsversuche mit exponentiellem Backoff:

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));
    }
  }
}

In Astro gerendert

Zuletzt rendern wir die Beiträge in unserer Astro-Komponente:

---
const allBlogPosts = waiting getAllPosts();
---

<div>



<p>Diese Integration ermöglicht uns:</p>

  • Behalten Sie eine einzige Quelle der Wahrheit für unsere Beiträge bei
  • Inhalte von mehreren Plattformen anzeigen
  • Gehen Sie elegant mit Fehlern um
  • Behalten Sie einen eingegebenen und sicheren Code bei

Der vollständige Code ist auf meinem GitHub verfügbar.

Haben Sie andere Blogging-Plattformen in Ihre Website integriert? Teilen Sie Ihre Erfahrungen in den Kommentaren! ?

webdev #astro #typescript #api

Das obige ist der detaillierte Inhalt vonIntegration mehrerer Blog-APIs in eine Astro-Site: Dev.to und Hashnode. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn