使用 Gatsby 函數和 Stripe 將開源軟件貨幣化
已發表: 2022-03-10在本文中,我將解釋我如何使用 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,並且兩者之間的通信都是無縫的,當然,快閃!
這是一個圖表來幫助說明它的樣子:
跨域函數
然而,我遇到過至少兩種情況,我需要我一直稱之為“跨源函數”(或簡稱為 COF)的東西。 我需要 COF 的兩種情況如下:
- 我需要服務器端功能,但原始網站無法運行無服務器功能。
- 無服務器功能被多個來源使用。
注意:使用 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。
這是一個圖表,可以更好地說明一般方法。
在上圖中, 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 網頁上輸入他們的付款詳細信息……然後繁榮! 你得到報酬!
這是一個圖表,可以更好地說明這是如何工作的:
這種方法與上面提到的 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 美元。
如果我使用 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,我能夠創建“動態”結帳。
注意:現在這意味著“客戶”可以決定項目對他們的價值並設置適當的貢獻金額。
在這一點上,我想提一下 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
數組,這些是允許使用此端點的唯一來源。 來自任何其他來源的請求將收到狀態代碼403
和Request 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 為我的其他網站提供類似的服務器端功能。 看看關於頁面,我在其中記錄了我的哪些站點使用了哪些功能,這裡有一個圖表來說明它們目前是如何組合在一起的。
您應該從上圖中看到 https://paulie.dev 也使用了 Stripe 端點。 我使用與 MDX Embed 相同的方法來啟用“按需付費”功能。 這是一件小事,但由於make-stripe-payment
端點已經編寫並可以工作,我可以重複使用它並避免重複此功能。
https://paulie.dev 網站也有自己的 Gatsby 無服務器功能,我用它來發布用戶對 Fauna 的反應並捕獲新聞通訊註冊。 這個功能是這個網站獨有的,所以我還沒有抽像出來。 但是,如果我想在 https://www.pauliescanlon.io 上註冊時事通訊,這就是我將功能遷移到 Paulie API 的地方。
抽象
這似乎是抽象無服務器函數的倒退。 畢竟,使用無服務器最酷的事情之一就是您的前端和後端代碼都在同一個地方。 正如我所展示的,有時候抽像是有意義的——無論如何對我來說。
我肯定會從使用這種方法中受益,併計劃進一步開發我的 API 以為我自己的許多網站提供更多功能,但是如果您對從開源中賺錢感興趣並且您的網站不是使用 Gatsby 構建的,這種方法很可能是您正在尋找的答案。
想開始使用 Gatsby 函數嗎? 查看 Gatsby Functions 文檔以開始工作!
延伸閱讀
如果您有興趣了解有關無服務器功能的更多信息,我建議您:
- Swizec Teller 的書,“前端工程師的無服務器手冊”
- 本尼迪克特的夏季功能課程
- ……當然還有蓋茨比文檔
功能果醬
從 8 月 17 日到 9 月 30 日,蓋茨比兄弟舉辦了一場社區競賽,有一些絕對是超級大獎等你來贏取。 如果還有時間,請訪問 FuncJam 並加入。另外,請查看這篇博文的字節大小部分; 它包含有用的視頻和指向許多示例函數的鏈接。
感謝閱讀,如果您想討論本文中提到的任何內容,請在下方發表評論或在 Twitter 上找到我。