所有文章 > API使用场景 > 如何使用Astro和Hygraph从外部API获取数据
如何使用Astro和Hygraph从外部API获取数据

如何使用Astro和Hygraph从外部API获取数据

创建电子商务网站需要处理庞大的数据量,涵盖产品图片、描述及价格等信息。若仅依赖手动方式从外部API获取并集成这些数据,不仅会极其耗时,还容易引发错误。所面临的挑战包括:为API请求编写和维护代码、管理API端点、整合来自不同来源的数据,以及确保系统具备无缝的可扩展性和数据一致性。

克服这些挑战的一种解决方案是远程数据获取。远程数据获取允许您从 API 等外部来源提取数据并将它们无缝集成到您的网站中。

在本文中,我们将深入探讨远程数据获取技术,并介绍Hygraph这一工具。Hygraph利用远程数据获取来简化网站和应用程序中的内容管理。我们将逐步指导您如何在Hygraph中设置远程源,配置相应的字段以获取信息,并将这些数据集成到一个基于Astro的项目中,最终目标是创建一个功能上与照片平台素材库Pexels相似的副本。

从外部 API 手动获取数据

从外部 API 获取数据涉及向终端节点发出 HTTP 请求以获取图像或元数据。例如,向 https://api.pexels.com/v1/search?query=nature 发出请求将获取自然图像。下面是一个简单的示例:

  • 我们将使用 query 参数 (query=nature) 向 Pexels API 端点发送请求
  • 我们将收到响应,并且需要解析 JSON 以提取我们需要的图像信息(URL 和 ID)
  • 然后,我们将在我们的应用程序中使用此图像数据

对于小型应用程序而言,处理这些任务可能还算简单,但随着应用程序规模的不断扩大,其复杂性将显著增加。应用程序可能会遭遇可扩展性问题,处理大型数据集时的数据一致性难题,维护上的挑战,以及处理各种API端点、结构和身份验证机制的复杂性,这些因素都极大地增加了出错的风险。

然而,存在更为高效的处理方式。在本教程中,我们将深入探讨无头CMS Hygraph如何作为一个中央管理平台,以更加便捷和易于管理的方式整合并管理外部数据源。

Hygraph 简介

Hygraph是一个无头内容管理系统(CMS),它作为GraphQL原生、API优先的平台,通过其独特的内容联合功能,提供了一种新颖的数据管理和集成方法。Hygraph能够通过API将数据交付到任何前端平台,为应用程序的设计和开发带来了极大的灵活性。

Hygraph同时支持RESTful API和GraphQL API,为各种数据结构提供了一个统一的API接口,避免了处理具有不同结构的单独API调用的繁琐过程。它提供了一个统一的GraphQL终端节点,使得开发人员能够从多个来源查询数据,而无需关心原始数据的格式。Hygraph会自动将这些不同的数据结构转换为通用的GraphQL架构,从而让应用程序能够更轻松地访问和利用这些数据。

Hygraph 具有内置缓存、CDN 集成和强大的基础设施,可实现快速可靠的数据传输。它可以最大限度地减少从多个外部 API 获取数据时的延迟和停机时间。它还具有强大的安全功能,如 API 密钥管理、OAuth 和基于角色的访问控制,以保护数据获取和保护敏感信息。

了解 Hygraph 远程源

Remote Sources 是 Hygraph 的一项功能,用于将来自其他系统的数据集成到您的 Hygraph 项目中。例如,您可以设置远程源,直接从外部 API(如图像和相关数据服务)检索所需内容,从而避免手动添加产品图像等繁琐操作。这样一来,您的所有内容都将在一个集中位置进行管理,确保信息的最新性和平台范围内的连贯性。

Remote Sources 具有几个优点:

  • 支持 RESTful 或 GraphQL API,用于与各种服务集成
  • 提供用户友好的界面,用于配置 Remote Sources,编码经验较少的开发人员可以访问 Remote Sources
  • 允许您将内部 Hygraph 内容与外部数据合并
  • 您可以通过 Hygraph 集中访问,而不是在多个位置管理数据

获取 Pexels API 密钥

接下来,让我们以 Pexels 为例,开始本教程的演示项目。首先,您需要在 Pexels 创建一个新账户,并从其控制面板中获取 API 密钥和端点信息。这些信息对于身份验证以及后续从 Pexels 向 Hygraph 传输数据至关重要,请务必妥善保管。

您可以使用 Postman 向 Pexels 终端节点发出请求,以查看您获取的数据:

https://api.pexels.com/v1/curated

您应该会收到类似于下图的响应:

获取 Pexels API 密钥

上述响应必须转换为架构定义语言 (SDL) 架构,以便 GraphQL 能够理解它。使用 JSON 到 SDL 转换器将 JSON 响应转换为 SDL。然后,复制并粘贴来自 Postman 的响应。

将 AutogeneratedMainType 重命名为 PhotoQuery,将 PhotosResult 重命名为 PhotoResult,并将 photos 字段所在的类型中的列表项类型重命名为 Photo。这将提高架构的可读性。

以下是最终的 SDL 架构:

type Src {
original: String
large2x: String
large: String
medium: String
small: String
portrait: String
landscape: String
tiny: String
}

type Photo {
id: Int
width: Int
height: Int
url: String
photographer: String
photographer_url: String
photographer_id: Int
avg_color: String
liked: Boolean
alt: String
src: Src
}

type PhotosResult {
page: Int
per_page: Int
total_results: Int
next_page: String
photos: [Photo]
}

我们还希望能够搜索照片,而Pexels提供了一个额外的端点用于获取搜索标识符。通过重复之前的Postman过程,我们可以查看该端点的响应。由于该响应的数据格式与之前的格式相同,因此无需再次将JSON转换为SDL。此外,由于这两个终端节点共享相同的基URL,所以我们无需创建新的远程源。具体的搜索端点地址为:https://api.pexels.com/v1/search?query=sport。

使用 Hygraph 集成外部数据

要开始集成外部数据,我们首先要访问 Hygraph 网站并注册。注册后,创建一个新项目,并在表单中填写项目名称、描述和数据存储区域:

注册新的 Hygraph 项目

添加和配置远程源

Hygraph的内容联合功能使用户能够将外部数据源整合进他们的账户,从而能够通过一个单一的GraphQL端点轻松访问所有数据。接下来,本节将展示如何集成Pexels数据源,以便从Hygraph的终端节点获取数据。

为此,请按照以下步骤操作:点击“Schema”>“REMOTE SOURCES”>“Add”,然后填写基本信息,包括远程源的名称和描述。选择“REST”作为源类型,并在相应的字段中输入Pexels端点的基础URL。在“Headers”(标头)部分,添加key和value,这将使管理员能够从GraphQL端点检索Pexels中的所有可用数据。请注意,URL中应包含正确的授权信息,例如https://api.pexels.com/v1/authorization?API_KEY=your_api_key

在 Custom type definition 部分中,添加上面生成的架构:

将远程源添加到 Hygraph 项目

将 API_KEY 替换为您从 Pexels 控制面板获取的密钥。

单击 Add,您的 Remote Source 已准备就绪。

在 Hygraph 中创建和管理模型

模型是数据的基础,它们定义了数据的内容。要在Hygraph中创建远程源模型,请按照以下步骤操作:首先导航到“Schema”>“MODELS”,然后点击“Add”按钮。接下来,填写模型名称(例如“pexels-photo”)并保存。

此模型将用于保存从API接收的照片详细信息。在屏幕的右侧窗格中,向下滚动并从模型的侧边栏中选择“REST”选项。然后,为该REST接口指定一个合适的名称(例如“photosGET”)。接着,添加有关端点的详细信息,包括请求方法(method)和返回类型(return type)。此外,请确保填写输入参数(input argument)部分的相关信息。这里的返回类型可以设置为“PhotosResult”,它代表了从API获取的照片结果。

该表单应如下图所示:

使用 Hygraph Continued 创建远程源模型

最后,创建一个包含单行的文本字段,并将其命名为desc 。模型的仪表板应如下图所示:

Hygraph 仪表板上的 Pexels 项目

我们的搜索数据模型也可以执行相同的操作:

在 Hygraph 中搜索模型数据表单

添加内容

现在,应用程序的数据模型已准备就绪,我们将从 Hygraph 内容菜单向其添加内容,以便向用户显示它们。

在左侧窗格中,点击“Content”选项卡。您应该会在“DEFAULT VIEWS”部分看到您的数据模型。选择它,然后点击右上角的“ADD ENTRY”按钮。在打开的界面中,填写“desc”字段,完成后点击“保存并发布”。对于搜索功能,也请重复上述步骤来添加内容,但请注意填写的内容应与搜索相关,例如“pexels-photo”或“photo”。

在我们的 Hygraph 内容菜单中添加内容

Hygraph 提供了一个 API Playground,我们可以在其中通过尝试查询和更改数据来测试 API 调用。您可以通过导航到 API playground 选项卡来测试它。

设置 Hygraph 权限

现在,我们来设置 Hygraph 权限以访问应用程序中的数据。

Hygraph 提供了必要的终端节点,但默认情况下,除非提供足够的权限,否则无法访问这些终端节点。要使端点可访问,请单击 Project Settings > ACCESS > API Access > Permanent Auth Tokens,然后单击 Add Token。为您的令牌命名,然后单击添加和配置权限。这将为您创建一个经过身份验证的令牌:

Hygraph 中的身份验证令牌

复制令牌并将其保存在安全的地方。稍后我们将需要它来验证数据并将其提取到我们的前端。

Content API 端点是访问数据的主要方法。转到 Content API 部分,然后单击 Add Permission。选择 Read 权限,如下所示,然后保存:

在我们的 Hygraph 设置中更改权限

太棒了!我们已经成功完成了Hygraph的设置。接下来,让我们继续利用Astro来开发前端,并从Hygraph中获取所需的数据。

使用 Astro 构建前端

在本节中,我们将使用从 Hygraph 获得的数据创建我们的 Pexel 克隆应用程序。如果你已经熟悉 Astro,请转到 GitHub 并获取代码。打开终端,运行以下命令,然后选择所需的模板:

npm create astro@latest

在构建我们的应用程序之前,请在我们的根文件夹中创建一个.env文件,并将其粘贴到您的 Hygraph API 端点和永久身份验证令牌中:

PUBLIC_HYGRAPH_PERMANENTAUTH_TOKEN="your auth token"
PUBLIC_HYGRAPH_ENDPOINT="your public content endpoint"

从Hygraph仪表板中获取并替换以下令牌:HYGRAPH_PERMANENT_AUTH_TOKEN 和 HYGRAPH_PUBLIC_CONTENT_ENDPOINT

构建我们的应用程序 UI

在基础层面,您的Pexels克隆应用程序需要具备一个导航栏、一个主图区域,以及能够展示代表照片的卡片的功能。为此,您可以创建一个基本的导航组件,并利用layouts文件夹将其集成到所有页面上。请通过向Layout.astro文件添加相应的代码来进行更新,该文件位于layouts文件夹内。

<! --- components/Layout.astro --->
---
import Navbar from "../components/Navbar.astro"
interface Props {
title: string;
}
const { title } = Astro.props;
---
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="description" content="Astro description" />
<meta name="viewport" content="width=device-width" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<meta name="generator" content={Astro.generator} />
<link rel="stylesheet" href="https://unicons.iconscout.com/release-pro/v4.0.0/css/solid.css">
<title>{title}</title>
</head>
<body>
<Navbar />
<slot />
</body>
</html>

上面的代码很简单,它负责渲染导入的Navbar组件。Navbar组件作为一个占位符,允许在其中插入来自其他组件的内容或嵌套的Astro内容。在本文中,我们不会介绍相关的样式,您可以从GitHub存储库中获取它们。

接下来,请在components文件夹中创建一个新文件,命名为Navbar.astro,并添加以下代码。

<! --- components/Navbar.astro --->
---
import Searchbar from "./SearchBar"
import "./Navbar.css"
---
<nav class="navbar">
<div class="container">
<div class="left">
<a href="/" class="logo-wrapper">
<img
class="Logo"
src={"/assets/logo.svg"}
alt="logo"
/>
<h2>Pexels-Clone</h2>
</a>
<Searchbar
client:load
/>
</div>
<div class="right">
<div class="dropdown">
<p class="dropbtn">Explore</p>
<div class="dropdown-content">
<a href="#">Discover Photos</a>
<a href="#">Popular Searches</a>
<a href="#">Free Videos</a>
<a href="#">Free Videos</a>
</div>
</div>
<p>License</p>
<button class="join">Join</button>
</div>
</div>
</nav>

您可能会注意到,在Navbar.astro中,我们有一个SearchBar组件。我们也希望在hero部分重用此组件。

为此,请在components文件夹中新建一个文件,命名为SearchBar.tsx,并向其中添加以下代码。

// components/SearchBar.tsx
import { navigate } from "astro:transitions/client";
import React, { useState } from "react";
import "./SearchBar.css";

function Searchbar() {
return (
<form>
<div className="search-box">
<input
type="text"
name="searchTerm"
aria-label="search-img"
placeholder="Search for free photos"
/>
<button type="submit">
<i className="uis uis-search"></i>
</button>
</div>
</form>
);
}
export default Searchbar;

如果你尝试运行服务器,你会得到一个错误,因为 React 还没有在项目中配置。运行以下命令以添加 React:

npx astro add react

在终端上运行命令后,Astro 将更新你的配置文件并安装任何必要的依赖项。

创建主页并显示我们的数据

现在在 components 目录中创建一个组件文件Card.tsx,以显示来自 Hygraph 的照片数据:

// components/Card.tsx
import { useState } from "react";

type TProps = {
src: string,
alt: string,
photographer: string,
original?: string,
};
const Card = ({ src, photographer, alt, original }: TProps) => {
return (
<>
<li className="card">
<img src={src} alt={alt} />
<div className="details">
<div className="photographer">
<i className="uis uis-camera"></i>
<span>{photographer}</span>
</div>
<button>
<span>Download</span>
<i className="uis uis-import"></i>
</button>
</div>
</li>
</>
);
};
export default Card;

pages目录下的主页文件中,您需要连接到Hygraph API,并将获取的数据对象映射到相应的组件上,即PhotosCard组件。

为了从后端获取数据,您将使用fetch函数向Hygraph发送一个POST请求。

<!--- pages/index.astro --->
---
import Card from "../components/Card";
import Layout from "../layouts/Layout.astro";
import type { Photo } from "../types/index";
import Hero from "../components/Hero.astro";

const response = await fetch(import.meta.env.PUBLIC_HYGRAPH_ENDPOINT, {
method: "POST",
headers: {
"Content-Type": "application/json",
Accept: "application/json",
Authorization: `Bearer ${import.meta.env.PUBLIC_HYGRAPH_PERMANENTAUTH_TOKEN}`,
},
body: JSON.stringify({
query: `
query Pexels($perPage: Int) {
pexelsPhotos {
photos(perPage: $perPage) {
photos {
id
alt
photographer
src {
large2x
original
}
}
}
}
}
`,
variables: { perPage: 9 },
}),
});

const data = await response.json();
const results = data?.data?.pexelsPhotos;
---
<Layout title="Hygraph Pexels Clone">
<Hero />
<main class="container">
<section class="gallery">
{results.map((result: any) => (
<ul class="images">
{result.photos.photos.map((photo: Photo) => (
<Card
alt="{photo.alt}"
photographer="{photo.photographer}"
src="{photo.src.large2x}"
original="{photo.src.original}"
client:idle
/>
))}
</ul>
))}
<a href="/photos" class="load-more" style="text-decoration: none"
>Show More</a
>
</section>
</main>
</Layout>

上面的代码定义了一个查询,用于从Hygraph获取照片。在代码中,首先设置了请求的头信息和查询文档,然后通过fetch API向Hygraph端点发送请求。从响应中,代码提取了照片的alt文本、摄影师姓名和图片来源等相关信息,并计划在首页上展示9张照片。

值得注意的是,代码中可能包含了一些传递给组件的属性(props)。Astro提供了一些指令来控制组件在DOM中的加载和执行行为。在这里,使用了client:idle指令,它的作用是告诉Astro等到浏览器处于空闲状态时再下载和初始化与该组件关联的JavaScript。这可以作为一种优化网站性能的有效手段。

接下来,请在components目录中创建一个新文件,命名为Hero.astro,并向其中添加相应的代码。

<! --- components/Hero.astro --->
---
import Searchbar from "./SearchBar"
---
<header class="search">
<img
src="https://images.pexels.com/photos/1629236/pexels-photo-1629236.jpeg?auto=compress&cs=tinysrgb&w=600"
alt="search-img"
/>
<div class="content">
<h1>Pexel Clone Photos Gallery with Astro</h1>
<p>Search, preview and download any images within a second</p>
<div class="header-search">
<Searchbar client:idle />
</div>
</div>
</header>

这是 image 目录的样子:

Pexels 克隆镜像目录

集成搜索功能

接下来,我们打算为应用程序增加一个搜索查询功能,这样用户就能搜索不同的照片了。

请前往components/SearchBar.tsx并使用以下代码对其进行更新。

// components/SearchBar.tsx
import { navigate } from "astro:transitions/client";
import React, { useState } from "react";
import "./SearchBar.css";

function Searchbar() {
const [searchTerm, setSearchTerm] = useState<string>("");

const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
setSearchTerm(event.target.value);
};

const handleSubmit = (event: React.FormEvent<HTMLFormElement>) => {
event.preventDefault();
if (searchTerm.trim()) {
navigate(`/search/${searchTerm}`, history);
} else {
window.alert("input a text");
}
};

return (
<form onSubmit={handleSubmit}>
<div className="search-box">
<input
type="text"
name="searchTerm"
aria-label="search-img"
placeholder="Search for free photos"
value={searchTerm}
onChange={handleChange}
/>
<button type="submit">
<i className="uis uis-search"></i>
</button>
</div>
</form>
);
}
export default Searchbar;

目前,当我们搜索照片时,系统不会有任何反应。为了解决这个问题,我们首先需要在pages目录下设置一个对应的动态路由路径。请在pages目录中新建一个文件,命名为search/[searchTerm].astro,并向其中添加以下代码。

<!--- search/[searchTerm].astro --->
---
import Layout from "../../layouts/Layout.astro";
import Card from "../../components/Card";
import type { Photo } from "../../types";

const { searchTerm } = Astro.params;

const data = await fetch(import.meta.env.PUBLIC_HYGRAPH_ENDPOINT, {
method: "POST",
headers: {
"Content-Type": "application/json",
Accept: "application/json",
Authorization: `Bearer ${import.meta.env.PUBLIC_HYGRAPH_PERMANENTAUTH_TOKEN}`,
},
body: JSON.stringify({
query: `
query pexels($searchTerm: String) {
searchPhotos {
search(searchTerm: $searchTerm) {
photos {
photographer
id
alt
src {
large2x
original
}
}
}
}
}
`,
variables: { searchTerm },
}),
}).then((response) => response.json());
const results = data?.data?.searchPhotos;
---
<Layout title="`Search" Results for ${searchTerm}`>
<div style="margin: 2rem auto; max-width: 90%; width: 100%">
<h1>free {searchTerm}s photos</h1>
<section class="gallery">
{results.map((result: any) => (
<ul class="images">
{result.search.photos.map((photo: Photo) => (
<Card
alt="{photo.alt}"
photographer="{photo.photographer}"
src="{photo.src.large2x}"
original="{photo.src.original}"
client:idle
/>
))}
</ul>
))}
</section>
</div>
</Layout>

现在,当您运行服务器时,您将遇到以下错误:

getStaticPaths()function 是动态路由所必需的。确保从动态路由中导出函数。getStaticPaths

在Astro中,如果一个页面的文件名包含动态参数(例如[searchTerm]),则该页面组件需要导出一个getStaticPaths函数。这是因为Astro是一个静态网站构建器,它会在构建阶段预先生成网站的所有页面。

然而,有时我们可能希望某些动态页面是可选的,即它们的值是根据用户在构建页面之前搜索的内容来确定的。对于这种情况,getStaticPaths函数可能不是最佳选择,因为它要求我们在构建时就知道所有可能的路径。

幸运的是,Astro提供了按需渲染模式(包括服务器渲染和混合渲染),这允许我们预渲染单个路由,并在需要时按需渲染其他路由。这种模式结合了静态站点和动态应用程序的优点,特别适用于那些需要按需渲染的路由。

现在,如果您想为您的网站启用按需渲染模式,请导航到astro.config.mjs文件,并进行相应的配置切换。在那里,您可以了解更多关于Astro按需渲染输出模式的信息。

// astro.config.mjs
import { defineConfig } from "astro/config";
import react from "@astrojs/react";

// https://astro.build/config
export default defineConfig({
output: "hybrid",
integrations: [react()],
images: {
domains: ["media.graphassets.com"],
},
});

在Astro中,默认的渲染模式是”static”,这意味着在构建时,它会为所有页面路由生成HTML。使用”static”渲染模式,构建过程中src/pages目录中的所有页面都会被预渲染为HTML,从而为每个页面创建静态的HTML文件。

另外,请在[searchTerm].astro文件的顶部添加以下代码行:

// pages/search/[searchTerm].astro
export const prerender = false;

这使得页面服务器呈现,而不是静态 HTML,因为它禁用了预呈现。现在重新运行您的开发服务器并在浏览器中看到以下结果:

具有搜索功能的 Pexels 克隆

结论

在本文中,我们探讨了从网站和应用程序的外部API手动获取数据所面临的挑战。接着,我们介绍了Hygraph CMS及其远程数据获取功能,这些功能简化了从外部来源获取数据并在一个集中位置管理数据的过程。随后,我们通过一个实际示例,展示了如何使用Pexels API设置Hygraph,并结合一个Astro项目,构建了一个功能完备的工作克隆。

利用Hygraph的Remote Sources和模型功能,您可以更加高效地管理数据,确保内容的一致性,并轻松构建集成了来自多个不同来源数据的应用程序。这样一来,您不仅可以节省大量的开发时间,还能将更多精力投入到为用户提供卓越的应用程序体验上。

您是否添加新的 JS 库来构建新功能或提高性能?如果他们反其道而行之呢?

毫无疑问,前端领域的复杂性正日益加剧。在向应用程序添加新的JavaScript库和其他依赖项时,您需要更高的可见性来确保用户不会遭遇任何未知问题。

LogRocket 是一种前端应用程序监控解决方案,可让您重放 JavaScript 错误,就像它们发生在您自己的浏览器中一样,以便您可以更有效地对错误做出反应。

LogRocket能够无缝集成到任何应用程序中,不受框架限制,并且提供了插件来记录来自Redux、Vuex和@ngrx/store的额外上下文信息。您可以聚合并报告问题发生时应用程序的状态,而不是仅凭猜测去推断问题原因。此外,LogRocket还会监控应用程序的性能,提供客户端CPU负载、客户端内存使用情况等关键指标的报告。

原文链接:https://blog.logrocket.com/how-to-fetch-data-external-apis-using-astro-hygraph/

#你可能也喜欢这些API文章!