Monetize software de código aberto com funções Gatsby e Stripe
Publicados: 2022-03-10Neste artigo, explicarei como usei o Gatsby Functions e a API Stripe para permitir contribuições seguras “Pague o que quiser” que ajudam a financiar meu projeto de código aberto MDX Embed.
Observação : o MDX Embed permite que você incorpore facilmente conteúdo de mídia popular de terceiros, como vídeos do YouTube, Tweets, postagens do Instagram, lições do Egghead, Spotify, TikTok e muito mais diretamente em seu .mdx
- sem necessidade de importação.
Funções sem servidor Gatsby
As Funções Gatsby abrem um mundo totalmente novo para desenvolvedores front-end, pois fornecem uma maneira de escrever e usar código do lado do servidor sem o incômodo de manter um servidor. Os usos para funções sem servidor variam de inscrições em Newsletter com ConvertKit, envio de um e-mail usando SendGrid, salvamento de dados em um banco de dados como o Fauna ou, neste caso, aceitando pagamentos seguros usando Stripe - a lista é francamente interminável!
Serviços de terceiros como os mencionados acima só aceitarão solicitações enviadas do lado do servidor. Há uma série de razões para isso, mas usar chaves seguras ou privadas normalmente é uma delas. Usar essas chaves no lado do servidor significa que elas não são expostas ao cliente (navegador) e não podem ser abusadas, e é aqui que as Funções Serverless do Gatsby podem ajudar.
Gatsby fornece a mesma abordagem lógica para funções sem servidor que fazem com páginas. Por exemplo, as páginas do site estão localizadas em src/pages
e as funções sem servidor estão localizadas em src/api
.
Naturalmente, há um pouco mais do que isso, mas a experiência de desenvolvedor de Gatsby é lógica e consistente, e eu adoro isso!
Funções da Mesma Origem
Nove em cada dez vezes ao trabalhar com funções sem servidor, você as usará da maneira como deveriam ser usadas, por exemplo, seu site usa suas próprias funções. Eu chamo esse uso de Same Origin Functions ou SOFs para abreviar. Nesse cenário, tanto o Front-end quanto a API são implantados na mesma origem, por exemplo, www.my-website.com e www.my-website.com/api, e a comunicação entre os dois é perfeita e, claro, , muito rápido!
Aqui está um diagrama para ajudar a ilustrar o que parece:
Funções de origem cruzada
Existem, no entanto, pelo menos dois cenários que encontrei em que precisei do que tenho chamado de “Funções de Origem Cruzada” (ou COFs para abreviar). Os dois cenários em que precisei de COFs são os seguintes:
- Preciso de recursos do lado do servidor, mas o site de origem não pode executar funções sem servidor.
- A Função Serverless é usada por mais de uma origem.
Nota : Usar o Gatsby não é a única maneira de escrever funções sem servidor, mas mais sobre isso em breve.
Eu experimentei essa abordagem pela primeira vez em novembro de 2020 antes do lançamento do Gatsby Functions e usei o Netlify Functions para fornecer comunicações de servidor para servidor com a API do Twitter e meu blog Gatsby e portfólio comercial. Você pode ler sobre essa abordagem aqui: Use o Netlify Functions e a API do Twitter v2 como um CMS para seu blog Gatsby.
Após o lançamento do Gatsby Functions em junho de 2021, refatorei o acima para trabalhar com o Gatsby Functions e aqui estão um pouco mais de informações sobre como fiz isso e por quê: Usando o Gatsby Functions como uma API abstrata.
Aqui está um diagrama para ilustrar melhor a abordagem geral.
No diagrama acima, website-1.com
é construído com Gatsby e poderia ter usado funções sem servidor (mas não usa) e website-2.com
é construído usando algo que não possui recursos de função sem servidor.
Observação : em ambos os casos, ambos precisam usar o mesmo serviço de terceiros, portanto, faz sentido abstrair essa funcionalidade em uma API independente.
A API autônoma de exemplo ( my-api.com
) também é um site Gatsby e possui recursos de função sem servidor, mas, mais importante, permite que sites de outras origens usem suas funções sem servidor.
Eu sei o que você está pensando: CORS! Bem, sente-se bem. Vou cobrir isso em breve.
Monetização de incorporação de MDX
Esta foi a situação em que me encontrei com o MDX Embed. O site de documentação para este projeto é construído usando o Storybook. O Storybook não tem recursos sem servidor, mas eu realmente precisava de comunicação de servidor para servidor. Minha solução? Eu criei uma API independente chamada API Paulie.
API Paulie
A API Paulie (como a API autônoma de exemplo mencionada acima) pode aceitar solicitações de sites de diferentes origens e pode se conectar a vários serviços de terceiros diferentes, um dos quais é o Stripe.
Para habilitar pagamentos Stripe do MDX Embed, criei um endpoint api/make-stripe-payment
na API Paulie que pode passar as informações relevantes do MDX Embed por meio de sua própria Função Serverless e para a API Stripe para criar um “checkout”. Você pode ver o código src aqui.
Depois que um checkout for criado com sucesso, a API Stripe retornará um URL. Esse URL é passado de volta para o MDX Embed, que abre uma nova janela no navegador onde os “clientes” podem inserir com segurança seus detalhes de pagamento em uma página da Web do Stripe… e boom! Você é pago!
Aqui está um diagrama que ilustra melhor como isso funciona:
Essa abordagem é a mesma mencionada acima, onde https://mdx-embed.com envia solicitações para https://paulieapi.gatsbyjs.io que, por sua vez, se conecta à API do Stripe usando comunicação de servidor para servidor. Mas antes de irmos muito mais longe, vale a pena explicar por que não usei react-stripe-js
.
react-stripe-js
react-stripe-js
é um kit de ferramentas do lado do cliente (navegador) que permite criar check-outs e elementos do Stripe em seu projeto React. Com react-stripe-js você pode configurar um método para aceitar pagamentos com segurança sem a necessidade de comunicação do lado do servidor, mas... e há um porém. Eu queria implementar contribuições “Pague o que você quiser”. Permita-me explicar.
Aqui está uma captura de tela do “produto” MDX Embed que configurei no meu painel do Stripe. Observe que o preço é de R$ 1,00.
Se eu tivesse usado react-stripe-js para habilitar pagamentos, todos os “clientes” seriam solicitados a pagar o mesmo valor. Neste caso, é apenas $ 1,00 e isso não vai pagar as contas, não é!
Para habilitar “Pague o que quiser” (por exemplo, um valor nominal escolhido por um “cliente”), você precisa se aprofundar um pouco mais e usar a comunicação servidor a servidor e enviar esse valor para a API Stripe usando uma solicitação HTTP personalizada. É aqui que estou usando uma função Gatsby e passo um valor dinâmico que será usado para criar a experiência de “checkout” e substituir o preço definido no meu painel Stripe.
No MDX Embed, adicionei um HTML <input type="number" />
que permite que os “clientes” definam uma quantia em vez de pagar uma quantia predefinida — se todo o comércio eletrônico fosse assim!
Aqui está um pequeno vídeo que fiz que mostra como o MDX Embed, a API Paulie e a API Stripe funcionam juntas:
Ao passar o valor de entrada do MDX Embed para a API Paulie, que por sua vez se conecta à API Stripe, posso criar um checkout “dinâmico”.
Nota : Isso agora significa que os “clientes” podem decidir quanto o projeto vale para eles e definir um valor apropriado para contribuir.
Gostaria de mencionar Benedicte Raae neste momento, que me mostrou essa abordagem pela primeira vez durante seu fabuloso curso de funções de verão . Você pode descobrir mais visitando Códigos da Rainha Raae. ( Obrigado Benedicte, você é o melhor! )
Vamos falar sobre CORS
Por padrão, o Gatsby Serverless Functions não será bloqueado pelo CORS, pois o Front-end e a API são implantados na mesma origem. Ao desenvolver funções de origem cruzada, no entanto, você precisará configurar sua API para que ela aceite solicitações de origens diferentes daquelas próprias.
Aqui está um trecho de código para mostrar como eu lido com CORS no endpoint api/make-stripe-payment
:
// 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' }) } }
No trecho de código acima, você deve poder ver que defini uma matriz de allowedOrigins
, essas são as únicas origens com permissão para usar esse endpoint. Solicitações de qualquer outra origem receberão um código de status 403
e uma mensagem de Request blocked by CORS
.
Esta função também aceita vários parâmetros do corpo, um dos quais é o amount
que o “cliente” decidiu pagar, este é o valor da entrada HTML no site MDX Embed. Você também notará o parâmetro do product
, este é o id do produto definido no meu painel do Stripe e como a API do Stripe cria o URL de “checkout” correto. Passar esse valor como um parâmetro de corpo em vez de codificá-lo na função me permite reutilizar esse ponto de extremidade para outros produtos Stripe.
O suco vale a pena?
Eu mencionei algumas coisas ao longo do caminho por que eu decidi seguir esse caminho. Afinal, pode parecer uma maneira mais complicada de usar Serverless Functions, mas tenho meus motivos e acho que vale a pena. Aqui está o porquê.
A API Paulie é uma API de origem cruzada e um site de documentação. Naturalmente, se você vai escrever uma API, ela precisa ser documentada, certo?
É aqui que funciona a meu favor usar o Gatsby para alimentar minha API porque, juntamente com os recursos Serverless, a API Paulie também é um site Gatsby e, como na verdade é um site, posso preenchê-lo com conteúdo e torná-lo bonito, mas espere, há mais …
Observação: a API Paulie também é um playground de API interativo!
Cada função tem um link Run in browser
. Isso leva você a uma página no site onde você pode interagir com a função. Ele serve como um campo de testes útil enquanto estou desenvolvendo a função e uma maneira fácil de demonstrar como a função funciona, documentos são bons, documentos interativos são melhores!
Eu também uso essa API para fornecer funcionalidade semelhante do lado do servidor para meus outros sites. Dê uma olhada na página Sobre, onde documentei quais dos meus sites usam quais funções, e aqui está um diagrama para ilustrar como tudo isso se encaixa atualmente.
Você deve ver no diagrama acima que https://paulie.dev também usa o endpoint Stripe. Usei a mesma abordagem do MDX Embed para habilitar a funcionalidade “Pague o que quiser”. É uma coisa pequena, mas como o endpoint make-stripe-payment
já está escrito e funcionando, posso reutilizá-lo e evitar duplicar essa funcionalidade.
O site https://paulie.dev também tem suas próprias Funções Gatsby Serverless que eu uso para postar reações de usuários à Fauna e capturar inscrições em Newsletter. Essa funcionalidade é exclusiva deste site, então ainda não a abstraí. No entanto, se eu quisesse inscrições de newsletters em https://www.pauliescanlon.io, este seria o ponto em que eu migraria a função para a API Paulie.
Abstração
Isso pode parecer um passo para trás para abstrair suas funções sem servidor. Afinal, uma das coisas mais legais de ficar sem servidor é que tanto o código do front quanto o do back-end estão ativos no mesmo lugar. Como demonstrei, há momentos em que a abstração faz sentido – pelo menos para mim.
Certamente estou me beneficiando do uso dessa abordagem e pretendo desenvolver ainda mais minha API para fornecer mais funcionalidades a vários dos meus próprios sites, mas se ganhar dinheiro com código aberto for do seu interesse e seu site não for construído usando o Gatsby , essa abordagem pode ser a resposta que você estava procurando.
Quer começar com as Funções Gatsby? Confira os documentos do Gatsby Functions para começar!
Leitura adicional
Se você estiver interessado em aprender mais sobre funções sem servidor, eu recomendo:
- O livro de Swizec Teller, “Manual sem servidor para engenheiros de front-end”
- Curso de funções de verão de Benedict
- … e, claro, os documentos de Gatsby
FuncJamGenericName
De 17 de agosto a 30 de setembro, o pessoal de Gatsby está realizando uma competição da comunidade com alguns prêmios absolutamente mega a serem ganhos. Se ainda houver tempo, vá até o FuncJam e participe. Além disso, confira a seção Byte-size deste post do blog; ele contém vídeos úteis e links para várias funções de exemplo.
Obrigado por ler, e se você quiser discutir qualquer coisa mencionada neste artigo, deixe um comentário abaixo ou me encontre no Twitter.