This is an automated email from the ASF dual-hosted git repository. moonming pushed a commit to branch feat/seo-article-structured-data in repository https://gitbox.apache.org/repos/asf/apisix-website.git
commit b6ff85406a5a24233c10fcb754f8d0d17b5535f5 Author: Ming Wen <[email protected]> AuthorDate: Wed Jun 24 19:13:13 2026 +0800 feat(seo): add Article, FAQPage & BreadcrumbList structured data to Learning Center Learning Center articles previously carried only the site-wide Organization and WebSite JSON-LD — no Article, FAQPage, or BreadcrumbList — leaving them ineligible for article/FAQ/breadcrumb rich results and weaker as AI-overview citation sources, despite several already containing FAQ sections. Add a thin BlogPostPage wrapper (scoped to /learning-center/) that emits: - Article + BreadcrumbList for every article (from post metadata) - FAQPage when the article declares an 'faq' array in front matter Add 'faq' front matter to the two articles with existing FAQ sections (what-is-an-api-gateway: 5 Q&As; open-source-api-gateway-comparison: 4 Q&As), schema answers matching the visible text. Verified against the production SSR build: every article emits Article + BreadcrumbList; FAQ articles add FAQPage with correct Q&A counts; non-FAQ articles omit it. URLs use the canonical trailing-slash form. --- .../open-source-api-gateway-comparison.md | 13 +++ website/learning-center/what-is-an-api-gateway.md | 16 +++ website/src/theme/BlogPostPage/index.tsx | 128 +++++++++++++++++++++ 3 files changed, 157 insertions(+) diff --git a/website/learning-center/open-source-api-gateway-comparison.md b/website/learning-center/open-source-api-gateway-comparison.md index 8e0c02292a1..8a385214e37 100644 --- a/website/learning-center/open-source-api-gateway-comparison.md +++ b/website/learning-center/open-source-api-gateway-comparison.md @@ -5,6 +5,19 @@ slug: open-source-api-gateway-comparison date: 2026-04-14 tags: [comparison, api-gateway, open-source] hide_table_of_contents: false +faq: + - q: "Is Apache APISIX production-ready for enterprise workloads?" + a: >- + Yes. Apache APISIX is an Apache Software Foundation top-level project used in production by organizations worldwide. The etcd-backed architecture provides high availability without single points of failure when deployed with an etcd cluster. + - q: "Can I migrate from Kong to APISIX without downtime?" + a: >- + A zero-downtime migration is achievable using a canary deployment approach: run both gateways in parallel behind a load balancer, gradually shifting traffic from Kong to APISIX as you validate route-by-route equivalence. APISIX supports most Kong plugin equivalents natively, and the Admin API allows automated route provisioning during migration. + - q: "How do open-source API gateways compare to cloud-managed options like AWS API Gateway?" + a: >- + Cloud-managed gateways trade control for convenience. They handle infrastructure operations but impose vendor lock-in, per-request pricing that grows with traffic volume, and limited plugin customization. Open-source gateways like APISIX provide full control over the data plane, support multi-cloud and hybrid deployments, and eliminate per-request platform fees. + - q: "Which gateway has the best Kubernetes support?" + a: >- + All four gateways support Kubernetes, but the depth varies. APISIX and Kong offer dedicated ingress controllers with CRD-based configuration. Envoy integrates through the Kubernetes Gateway API and service mesh deployments. Traefik auto-discovers Kubernetes services natively. The emerging Kubernetes Gateway API standard is supported by all four projects to varying degrees, and is becoming the recommended approach for new deployments. --- An open-source API gateway sits between clients and backend services, handling routing, authentication, rate limiting, and observability. Apache APISIX, Kong, Envoy, and Traefik are among the most widely adopted options, each with distinct architectural decisions that affect performance, extensibility, and operational complexity. diff --git a/website/learning-center/what-is-an-api-gateway.md b/website/learning-center/what-is-an-api-gateway.md index f80c30d82af..f34d8d4ba0d 100644 --- a/website/learning-center/what-is-an-api-gateway.md +++ b/website/learning-center/what-is-an-api-gateway.md @@ -5,6 +5,22 @@ slug: what-is-an-api-gateway date: 2026-04-14 tags: [api-gateway, concepts] hide_table_of_contents: false +faq: + - q: "What is the difference between an API gateway and a load balancer?" + a: >- + A load balancer distributes incoming traffic across multiple server instances using algorithms like round-robin or least connections. It operates at the network or transport layer (L4) or HTTP layer (L7) but does not understand API semantics. An API gateway performs load balancing as one of many functions, and adds API-specific capabilities: authentication, rate limiting, request transformation, caching, and observability. If you only need to distribute traffic, a load balancer suf [...] + - q: "Do I need an API gateway for a monolithic application?" + a: >- + An API gateway is not strictly required for a monolith, but it can still add value. If your monolith exposes APIs consumed by external clients, mobile apps, or third-party integrators, a gateway provides centralized authentication, rate limiting, and monitoring without modifying the application. It also positions your architecture for incremental migration to microservices using the strangler fig pattern. + - q: "How does an API gateway affect latency?" + a: >- + A well-implemented gateway adds minimal latency — typically 0.2ms to 2ms per request depending on the number of active plugins. High-performance gateways like Apache APISIX are optimized for sub-millisecond overhead. The latency tradeoff is almost always worthwhile: the gateway eliminates redundant auth checks, reduces backend calls through caching, and prevents cascading failures through circuit breaking, all of which improve overall system response times. + - q: "Can an API gateway replace a service mesh?" + a: >- + An API gateway and a service mesh serve different layers. The gateway handles north-south traffic (external clients to internal services), while a service mesh manages east-west traffic (service-to-service communication within the cluster). They are complementary, not competing, technologies. Some organizations use APISIX as both a gateway and an ingress controller, bridging the two layers, but a full service mesh (Istio, Linkerd) addresses concerns like mutual TLS between services [...] + - q: "Is an API gateway the same as an API management platform?" + a: >- + No. An API gateway is the runtime component that processes API traffic. An API management platform is a broader category that typically includes a gateway, a developer portal, API documentation tools, lifecycle management, and analytics dashboards. The gateway is the engine; the management platform is the full vehicle. Apache APISIX provides the high-performance gateway layer, and organizations often pair it with additional tooling for the complete API management lifecycle. --- An API gateway is a server that sits between clients and backend services, acting as the single entry point for all API traffic. It accepts incoming requests, applies policies such as authentication, rate limiting, and transformation, then routes each request to the appropriate upstream service and returns the response to the caller. diff --git a/website/src/theme/BlogPostPage/index.tsx b/website/src/theme/BlogPostPage/index.tsx new file mode 100644 index 00000000000..1a1d47c83c1 --- /dev/null +++ b/website/src/theme/BlogPostPage/index.tsx @@ -0,0 +1,128 @@ +import React from 'react'; +import BlogPostPage from '@theme-original/BlogPostPage'; +import Head from '@docusaurus/Head'; +import useDocusaurusContext from '@docusaurus/useDocusaurusContext'; + +/** + * Wraps the default blog post page to add SEO/GEO structured data to Learning + * Center articles: Article + BreadcrumbList for every article, and FAQPage when + * the article declares an `faq` array in its front matter. Other blog instances + * (events, articles) are rendered untouched. + */ + +interface FaqItem { + q: string; + a: string; +} + +interface BlogAuthor { + name: string; + url?: string; +} + +interface BlogPostContent { + metadata: { + permalink: string; + title: string; + description: string; + date: string; + authors: BlogAuthor[]; + }; + frontMatter: { faq?: FaqItem[]; image?: string }; + assets: { image?: string }; +} + +type Props = React.ComponentProps<typeof BlogPostPage>; + +const LEARNING_CENTER_PREFIX = '/learning-center/'; + +const BlogPostPageWrapper = (props: Props): JSX.Element => { + const { siteConfig } = useDocusaurusContext(); + const siteUrl = siteConfig.url.replace(/\/$/, ''); + + const { metadata, frontMatter, assets } = (props as { content: BlogPostContent }).content; + const { + permalink, title, description, date, authors, + } = metadata; + + // Only enrich Learning Center articles; leave other blog instances untouched. + if (!permalink || !permalink.startsWith(LEARNING_CENTER_PREFIX)) { + return <BlogPostPage {...props} />; + } + + // Match the site's canonical form (trailingSlash: true). + const permalinkWithSlash = permalink.endsWith('/') ? permalink : `${permalink}/`; + const url = siteUrl + permalinkWithSlash; + const rawImage = assets.image ?? frontMatter.image; + const image = rawImage + ? (rawImage.startsWith('http') ? rawImage : siteUrl + rawImage) + : undefined; + + const articleSchema = { + '@context': 'https://schema.org', + '@type': 'Article', + headline: title, + description, + datePublished: date, + dateModified: date, + ...(image && { image }), + author: + authors.length > 0 + ? authors.map((author) => ({ + '@type': 'Person', + name: author.name, + ...(author.url && { url: author.url }), + })) + : { '@type': 'Organization', name: 'Apache APISIX', url: siteUrl }, + publisher: { + '@type': 'Organization', + name: 'Apache APISIX', + logo: { '@type': 'ImageObject', url: `${siteUrl}/img/logo2.svg` }, + }, + mainEntityOfPage: { '@type': 'WebPage', '@id': url }, + url, + }; + + const breadcrumbSchema = { + '@context': 'https://schema.org', + '@type': 'BreadcrumbList', + itemListElement: [ + { '@type': 'ListItem', position: 1, name: 'Home', item: `${siteUrl}/` }, + { + '@type': 'ListItem', + position: 2, + name: 'Learning Center', + item: `${siteUrl}${LEARNING_CENTER_PREFIX}`, + }, + { '@type': 'ListItem', position: 3, name: title, item: url }, + ], + }; + + const { faq } = frontMatter; + const faqSchema = Array.isArray(faq) && faq.length > 0 + ? { + '@context': 'https://schema.org', + '@type': 'FAQPage', + mainEntity: faq.map((item) => ({ + '@type': 'Question', + name: item.q, + acceptedAnswer: { '@type': 'Answer', text: item.a }, + })), + } + : null; + + return ( + <> + <Head> + <script type="application/ld+json">{JSON.stringify(articleSchema)}</script> + <script type="application/ld+json">{JSON.stringify(breadcrumbSchema)}</script> + {faqSchema && ( + <script type="application/ld+json">{JSON.stringify(faqSchema)}</script> + )} + </Head> + <BlogPostPage {...props} /> + </> + ); +}; + +export default BlogPostPageWrapper;
