使用 Gatsby 函数和 Stripe 将开源软件货币化

已发表: 2022-03-10
快速总结 ↬ Gatsby Functions 为前端开发人员提供了一种编写和使用服务器端代码的方法,而无需维护服务器。 如果您对通过开源赚钱感兴趣并且您的网站不是使用 Gatsby 构建的,那么这种方法很可能就是您正在寻找的答案。

在本文中,我将解释我如何使用 Gatsby Functions 和 Stripe API 来实现安全的“按需付费”贡献,从而帮助资助我的开源项目 MDX Embed。

注意MDX Embed 允许您轻松地将流行的第三方媒体内容(例如 YouTube 视频、推文、Instagram 帖子、Egghead 课程、Spotify、TikTok 等)直接嵌入到您的.mdx - 无需导入。

Gatsby 无服务器函数

Gatsby Functions 为前端开发人员开辟了一个全新的世界,因为它们提供了一种编写和使用服务器端代码的方法,而无需维护服务器。 无服务器函数的用途包括使用 ConvertKit 注册时事通讯、使用 SendGrid 发送电子邮件、将数据保存在像 Fauna 这样的数据库中,或者在这种情况下,使用 Stripe 接受安全支付——坦率地说,这个列表是无穷无尽的!

像上面提到的第三方服务将只接受服务器端发送的请求。 造成这种情况的原因有很多,但使用安全或私钥通常是其中之一。 在服务器端使用这些密钥意味着它们不会暴露给客户端(浏览器)并且不会被滥用,而 Gatsby 的无服务器函数可以在这里提供帮助。

Gatsby 为无服务器函数提供了与页面相同的逻辑方法。 例如,网站页面位于src/pages中,无服务器函数位于src/api中。

当然,还有比这更多的内容,但 Gatsby 的开发人员体验既合乎逻辑又始终如一,我绝对喜欢这一点!

同源函数

在使用无服务器函数时,十有八九会以应有的方式使用它们,例如,您的网站使用自己的函数。 我将这种用法简称为同源函数或 SOF。 在这种情况下,前端和 API 都部署到同一个源,例如 www.my-website.com 和 www.my-website.com/api,并且两者之间的通信都是无缝的,当然,快闪!

这是一个图表来帮助说明它的样子:

同源函数示意图
一个使用自己的无服务器函数的 Gatsby 网站。 (大预览)

跨域函数

然而,我遇到过至少两种情况,我需要我一直称之为“跨源函数”(或简称为 COF)的东西。 我需要 COF 的两种情况如下:

  1. 我需要服务器端功能,但原始网站无法运行无服务器功能。
  2. 无服务器功能被多个来源使用。

注意使用 Gatsby 并不是编写无服务器函数的唯一方法,稍后会详细介绍。

在 Gatsby Functions 发布之前,我于 2020 年 11 月首次尝试使用这种方法,并使用 Netlify Functions 通过 Twitter API 以及我的 Gatsby 博客和商业产品组合提供服务器到服务器的通信。 您可以在此处阅读有关此方法的信息:使用 Netlify 函数和 Twitter API v2 作为 Gatsby 博客的 CMS。

在 2021 年 6 月发布 Gatsby Functions 后,我对上述内容进行了重构以与 Gatsby Functions 一起使用,这里有一些关于我如何使用它以及为什么这样做的更多信息:使用 Gatsby Functions 作为抽象 API。

这是一个图表,可以更好地说明一般方法。

交叉原点函数示意图
两个使用 Gatsby API 的无服务器函数的网站。 (大预览)

在上图中, website-1.com是用 Gatsby 构建的,可以使用无服务器函数(但没有),而website-2.com是使用没有无服务器函数功能的东西构建的。

注意在这两种情况下,它们都需要使用相同的第三方服务,因此将此功能抽象为独立 API 是有意义的。

示例独立 API ( my-api.com ) 也是一个 Gatsby 站点并具有无服务器功能功能,但更重要的是,它允许来自其他来源的网站使用其无服务器功能。

我知道你在想什么:CORS! 好吧,坐稳。 我将很快介绍这一点。

跳跃后更多! 继续往下看↓

将 MDX 嵌入货币化

这就是我在使用 MDX Embed 时遇到的情况。 该项目的文档网站是使用 Storybook 构建的。 Storybook 没有无服务器功能,但我确实需要服务器到服务器的通信。 我的解决方案? 我创建了一个名为 Paulie API 的独立 API。

保利 API

Paulie API(如上面提到的示例独立 API)可以接受来自不同来源的网站的请求,并且可以连接到许多不同的第三方服务,其中之一是 Stripe。

为了从 MDX Embed 启用 Stripe 支付,我在 Paulie API 上创建了一个api/make-stripe-payment端点,该端点可以通过其自己的无服务器函数将来自 MDX Embed 的相关信息传递到 Stripe API 以创建“结帐”。 您可以在此处查看 src 代码。

成功创建结帐后,Stripe API 会返回一个 URL。 这个 URL 被传回 MDX Embed,它会在浏览器中打开一个新窗口,“客户”可以在其中安全地在 Stripe 网页上输入他们的付款详细信息……然后繁荣! 你得到报酬!

这是一个图表,可以更好地说明这是如何工作的:

使用 Paulie API 的 MDX 嵌入示意图
MDX Embed 通过 Paulie API 的无服务器函数连接到 Stripe API。 (大预览)

这种方法与上面提到的 https://mdx-embed.com 向 https://paulieapi.gatsbyjs.io 发送请求的方法相同,后者又使用服务器到服务器的通信连接到 Stripe API。 但在我们走得更远之前,有必要解释一下为什么我没有使用react-stripe-js

react-stripe-js

react-stripe-js是一个客户端(浏览器)工具包,允许您在 React 项目中创建 Stripe 签出和元素。 使用 react-stripe-js,您可以设置一种安全地接受付款的方法,而无需服务器端通信,但是……有一个但是。 我想实现“支付你想要的”贡献。 请允许我解释一下。

这是我在 Stripe 仪表板中设置的 MDX Embed“产品”的屏幕截图。 请注意,价格为 1.00 美元。

价格为 1.00 美元的 MDX 嵌入产品的 Stripe 仪表板屏幕截图
条纹仪表板产品部分。 (大预览)

如果我使用 react-stripe-js 来启用付款,所有“客户”都会被要求支付相同的金额。 在这种情况下,它只有 1.00 美元,而且不会支付账单是吧!

要启用“随心所欲支付”(例如,“客户”选择的名义金额),您必须更深入地研究并使用服务器到服务器通信,并使用自定义 HTTP 请求将此金额发送到 Stripe API。 这是我使用 Gatsby 函数的地方,我传入了一个动态值,该值将用于创建“结帐”体验并覆盖我的 Stripe 仪表板中定义的价格。

在 MDX Embed 上,我添加了一个 HTML <input type="number" /> ,它允许“客户”设置金额而不是支付预定义的金额——如果所有电子商务都是这样的话!

这是我制作的一个小视频,展示了 MDX Embed、Paulie API 和 Stripe API 如何协同工作:

MDX Embed、Paulie API 和 Stripe API 如何协同工作以实现“按需付费”。

通过将输入值从 MDX Embed 传递给 Paulie API,后者又连接到 Stripe API,我能够创建“动态”结帐。

注意现在这意味着“客户”可以决定项目对他们的价值并设置适当的贡献金额。

在这一点上,我想提一下 Benedicte Raae,她在她精彩的夏季功能课程中首次向我展示了这种方法。 您可以访问 Raae 女王密码以了解更多信息。 (感谢本尼迪克特,你是最棒的!

让我们谈谈 CORS

默认情况下,由于前端和 API 部署到同一源,因此 CORS 不会阻止 Gatsby Serverless Functions。 但是,在开发跨域函数时,您需要配置您的 API,以便它接受来自与自己不同的来源的请求。

这是一个代码片段,展示了我如何在api/make-stripe-payment端点中处理 CORS:

 // src/api/make-stripe-payment const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY) import Cors from 'cors' const allowedOrigins = [ 'https://www.mdx-embed.com', 'https://paulie.dev', ] const cors = Cors({ origin: (origin, callback) => { if (allowedOrigins.includes(origin)) { callback(null, true) } else { callback(new Error()) } }, }) const runCorsMiddleware = (req, res) => { return new Promise((resolve, reject) => { cors(req, res, (result) => { if (result instanceof Error) { return reject(result) } return resolve(result) }) }) } export default async function handler(req, res) { const { success_url, cancel_url, amount, product } = req.body try { await runCorsMiddleware(req, res) try { const session = await stripe.checkout.sessions.create({ success_url: success_url, cancel_url: cancel_url, payment_method_types: ['card'], line_items: [ { quantity: 1, price_data: { unit_amount: amount * 100, currency: 'usd', product: product, }, }, ], mode: 'payment', }) res.status(200).json({ message: ' Stripe checkout created ok', url: session.url }) } catch (error) { res.status(500).json({ message: ' Stripe checkout error' }) } } catch (error) { res.status(403).json({ message: ' Request blocked by CORS' }) } }

在上面的代码片段中,您应该能够看到我定义了一个allowedOrigins数组,这些是允许使用此端点的唯一来源。 来自任何其他来源的请求将收到状态代码403Request blocked by CORS的消息。

此函数还接受一些正文参数,其中一个是“客户”决定支付的amount ,这是来自 MDX Embed 网站上的 HTML 输入的值。 您还会注意到product参数,这是在我的 Stripe 仪表板中定义的产品 ID,以及 Stripe API 如何创建正确的“结帐”URL。 将此值作为正文参数传递,而不是在函数中对其进行硬编码,这样我就可以将此端点重新用于其他 Stripe 产品。

果汁值得挤压吗?

在此过程中,我已经提到了一些我决定走这条路的原因。 毕竟,使用无服务器函数似乎是一种更复杂的方式,但我有我的理由,我认为这是值得的。 这就是为什么。

Paulie API 既是一个跨域 API 又是一个文档站点。 自然,如果您要编写 API,就必须对其进行记录,对吗?

这就是使用 Gatsby 来支持我的 API 对我有利的地方,因为除了无服务器功能之外,Paulie API 也是一个 Gatsby 网站,而且因为它实际上是一个网站,我可以用内容填充它并让它看起来很漂亮,但等等还有更多…

注意: Paulie API 也是一个交互式 API 游乐场!

每个函数都有一个Run in browser链接。 这会将您带到网站上的一个页面,您可以在其中与该功能进行交互。 它既是我开发函数时有用的测试场,也是演示函数如何工作的简单方法,文档很好,交互式文档更好!

我还使用此 API 为我的其他网站提供类似的服务器端功能。 看看关于页面,我在其中记录了我的哪些站点使用了哪些功能,这里有一个图表来说明它们目前是如何组合在一起的。

Paulie API 的跨域函数示意图
Paulie API 跨域功能能力。 (大预览)

您应该从上图中看到 https://paulie.dev 也使用了 Stripe 端点。 我使用与 MDX Embed 相同的方法来启用“按需付费”功能。 这是一件小事,但由于make-stripe-payment端点已经编写并可以工作,我可以重复使用它并避免重复此功能。

https://paulie.dev 网站也有自己的 Gatsby 无服务器功能,我用它来发布用户对 Fauna 的反应并捕获新闻通讯注册。 这个功能是这个网站独有的,所以我还没有抽象出来。 但是,如果我想在 https://www.pauliescanlon.io 上注册时事通讯,这就是我将功能迁移到 Paulie API 的地方。

paulie.dev “Pay what you want”用户界面的屏幕截图
paulie.dev 的“支付你想要的”部分。 (大预览)

抽象

这似乎是抽象无服务器函数的倒退。 毕竟,使用无服务器最酷的事情之一就是您的前端和后端代码都在同一个地方。 正如我所展示的,有时候抽象是有意义的——无论如何对我来说。

我肯定会从使用这种方法中受益,并计划进一步开发我的 API 以为我自己的许多网站提供更多功能,但是如果你对从开源中赚钱感兴趣并且你的网站不是使用 Gatsby 构建的,这种方法很可能是您正在寻找的答案。

想开始使用 Gatsby 函数吗? 查看 Gatsby Functions 文档以开始工作!

延伸阅读

如果您有兴趣了解有关无服务器功能的更多信息,我建议您:

  • Swizec Teller 的书,“前端工程师的无服务器手册”
  • 本尼迪克特的夏季功能课程
  • ……当然还有盖茨比文档

功能果酱

从 8 月 17 日到 9 月 30 日,盖茨比兄弟举办了一场社区竞赛,有一些绝对是超级大奖等你来赢取。 如果还有时间,请访问 FuncJam 并加入。另外,请查看这篇博文的字节大小部分; 它包含有用的视频和指向许多示例函数的链接。

感谢阅读,如果您想讨论本文中提到的任何内容,请在下方发表评论或在 Twitter 上找到我。