Vytvoření plánovače příspěvků na Twitteru pomocí React, NodeJS a Fauna (část 1)

Dnes se chystáme vytvořit aplikaci Twitter Post Scheduler. Říkejme tomu Twitter.

Nástroje

Než začneme, ujistěte se, že máte

  1. Uzel a NPM ve vašem počítači. Oba si můžete stáhnout na nodejs.org.
  2. Editor kódu. Preferuji VSCode. Můžete si jej stáhnout na code.visualstudio.com.

Architektura na vysoké úrovni služby Twitter

Zde je rychlý přehled toho, jak bude naše aplikace fungovat.

Klientská část:

  1. Uživatelé napíší tweet, zvolí čas, kdy jej chtějí naplánovat, a kliknou na odeslat.
  2. Tweet se dostane do databáze a tam se uloží.

Serverová část:

  1. NodeJS volá databázi každou minutu, aby načetl všechny tweety, které je třeba v tu chvíli odeslat.
  2. Potom NodeJS tyto tweety zveřejní na Twitteru.

Twittler Tech Stack

K sestavení Twitteru použijeme:

  • NodeJS (na serveru)
  • ReactJS (na klientovi)
  • Fauna (jako naše databáze)

Než se však pustíme do kódu, musíme si nejprve vytvořit účet vývojáře na Twitteru, abychom získali přístup k Twitter API, abyste mohli na Twitteru zveřejňovat příspěvky.

Twitter Developerský účet

Zde je návod, jak vytvořit účet vývojáře na Twitteru:

  1. Přejděte na https://developer.twitter.com/en/apply-for-access
  2. Klikněte na tlačítko „Požádat o účet vývojáře“

  3. Vyberte, proč chcete získat přístup k Twitter API (zvolil jsem prozkoumat)

  4. Proveďte všechny následující kroky, odpovězte na otázky a odešlete přihlášku.

  5. Počkejte, až tým Twitteru dokončí kontrolu vaší aplikace a poskytne vám přístup k rozhraní API (nemusí to trvat déle než několik dní)

  6. Poté, co tým Twitteru vaši žádost schválí, přejděte na svůj řídicí panel a vytvořte nový projekt.

  7. Poté zkopírujte a uložte token nositele. Budeme jej potřebovat pro přístup k Twitter API.

Nyní nastavíme naši databázi.

Fauna

Pro databázi použijeme Faunu. Jedná se o databázi bez serveru, která vám poskytuje všudypřítomný přístup k datům aplikací s nízkou latencí, aniž byste museli obětovat správnost dat.

  1. Přihlaste se nebo se zaregistrujte na svém účtu Fauna zde.
  2. Klikněte na „Vytvořit databázi.“

  3. Vyberte jméno a region

  4. Klikněte na „Nová kolekce.“

  5. Vyberte název sbírky a klikněte na „Uložit.“

Právě jsme vytvořili novou databázi nazvanou „twittler“ a naši kolekci „tweetů“, kam budeme ukládat naše tweety.

Co znamená „sbírka“ pro faunu?

Sbírky jsou soubory datových záznamů, nazývané dokumenty. V našem případě sada tweetů. Pokud jste obeznámeni s relačními databázemi, kolekce jsou analogické tabulkám v nich.

Nyní musíme vygenerovat klíče API a vložit je do naší aplikace, aby náš server mohl přistupovat k databázi a získávat z ní tweety. Zde je návod, jak to udělat:

  1. Přejděte na kartu „Zabezpečení“ a klikněte na „Nový klíč“.

  2. Zadejte název klíče a klikněte na „Uložit“

  3. Náš klíč API byl vygenerován.

  4. Klíč někam uložte. Budeme ho potřebovat později, abychom z naší aplikace měli přístup k fauně.

A poslední věc, kterou bychom měli udělat, je vytvořit index.

Indexy ve Fauně nám umožňují získávat dokumenty podle jiných atributů, než je jejich reference. Fungují jako vyhledávací tabulka, která zlepšuje výkon vyhledávání dokumentů. Namísto čtení každého dokumentu, abyste našli ten (které vás zajímají), se dotazujete na index, abyste tyto dokumenty našli. Index použijeme k získání všech tweetů z určitého časového období.

Chcete-li jej vytvořit, přejděte na kartu „Indexy“:

A vytvořte nový index „tweetsByDate“

Klikněte na tlačítko „Uložit“ a začněme kódovat našeho klienta.

Klient

K vytvoření naší klientské aplikace použijeme ReactJS a můžeme ji rychle nainstalovat pomocí create-react-app.

Otevřete terminál a nainstalujte create-react-app pomocí následujícího příkazu:

npx create-react-app twittler

Poté přejděte do vytvořené složky a inicializujte náš projekt:

cd twittler && npm i

Nyní nainstalujme balíček Fauna, který použijeme v naší aplikaci pro získání přístupu k databázi od našeho klienta:

npm i fauna

A také musíme přidat tajný klíč Fauna, který jsme vytvořili na kartě Zabezpečení Fauna. K tomu bedna .env.local soubor v kořenové složce našeho projektu a vložte tam svůj tajný klíč Fauna:

// .env.local

REACT_APP_FAUNADB_SECRET=your-secret-key

Poslední věc, kterou musíme přidat, je TailwindCSS. Je to framework CSS orientovaný na nástroje, který nám pomáhá rychle navrhnout a postavit naši aplikaci bez psaní jakýchkoli CSS. Chcete-li to provést, přejděte na stránku public/index.html a přidejte odkaz na soubor css TailwindCSS.

// public/index.html

<html lang="en">
 <head>
   <meta charset="utf-8" />
   <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
   <meta name="viewport" content="width=device-width, initial-scale=1" />
   <meta name="theme-color" content="#000000" />
   <meta
     name="description"
     content="Web site created using create-react-app"
   />
   <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
   <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />

   <link href="https://unpkg.com/tailwindcss@^2/dist/tailwind.min.css" rel="stylesheet">
   <title>Twittler</title>
 </head>
 <body>
   <noscript>You need to enable JavaScript to run this app.</noscript>
   <div id="root"></div>
 </body>
</html>

Toto není nejlepší způsob, jak přidat TailwindCSS do aplikací, ale odstraníme dodatečné instalační kroky, které jsou vyžadovány při „správné“ instalaci pomocí npm. V reálných aplikacích bychom Tailwind nainstalovali pomocí npm.

Nyní, když je vše nastaveno, je čas napsat nějaký kód. Začněme vytvořením našeho uživatelského rozhraní.

Otevřete src/App.js a přidejte tento kód:

// src/App.js

import React, {useCallback, useState} from 'react'
import Fauna from 'Fauna'

const currentDate = new Date().toISOString().substr(0, 10)

const FaunaClient = new Fauna.Client({
 secret: process.env.REACT_APP_FAUNADB_SECRET,
})
const q = Fauna.query

function App() {
 const [tweet, setTweet] = useState('')
 const [date, setDate] = useState(currentDate)
 const [time, setTime] = useState(
   new Date().getHours() + ':' + new Date().getMinutes()
 )

 const sendTweet = useCallback(
   async (event) => {
     event.preventDefault()

     console.log(new Date(`${date} ${time}`).getTime())
     console.log(new Date(`${date} ${time}`))

     try {
       FaunaClient.query(
         q.Create(q.Collection('tweets'), {
           data: {
             tweet,
             date: new Date(`${date} ${time}`).getTime(),
           },
         })
       )

       setTweet('')
     } catch (error) {
       console.log(error)
     }
   },
   [date, time, tweet]
 )

 return (
   <form
     onSubmit={sendTweet}
     className="flex flex-col max-w-lg m-auto min-h-screen justify-center"
   >
     <h2 className="mb-6 text-center text-3xl font-extrabold text-gray-900">
       Your Tweet
     </h2>
     <textarea
       required
       maxLength="280"
       rows="5"
       className="mb-6 focus:ring-indigo-500 focus:border-indigo-500 border-2 w-full p-4 sm:text-sm border-gray-300 rounded-md"
       placeholder="I don't understand pineapple pizza"
       value={tweet}
       onChange={(event) => setTweet(event.target.value)}
     />
     <div className="flex items-center mb-8">
       <input
         required
         type="date"
         min={currentDate}
         value={date}
         onChange={(event) => setDate(event.target.value)}
         className="focus:ring-indigo-500 focus:border-indigo-500 border-2 w-full p-4 sm:text-sm border-gray-300 rounded-md mx-4"
       />
       <input
         required
         type="time"
         value={time}
         onChange={(event) => setTime(event.target.value)}
         className="focus:ring-indigo-500 focus:border-indigo-500 border-2 w-full p-4 sm:text-sm border-gray-300 rounded-md mx-4"
       />
     </div>
     <button
       type="submit"
       className="flex justify-center py-4 px-4 border border-transparent font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500"
     >
       Schedule Tweet
     </button>
   </form>
 )
}

export default App

Co se tu tedy děje?

Pomocí Fauna.Client vytvoříme funkci klienta Fauna s tajným klíčem jako parametrem pro přístup k API Fauna.

const FaunaClient = new Fauna.Client({

 secret: process.env.REACT_APP_FAUNADB_SECRET,

})

Pomocí FaunaClient.query , odešleme Fauně požadavek na vytvoření nového dokumentu s tweet a date parametry.

       FaunaClient.query(

         q.Create(q.Collection('tweets'), {

           data: {

             tweet,

             date: new Date(`${date} ${time}`).getTime(),

           },

         })

       )

Chcete-li tento kód sami otestovat, otevřete terminál a zadejte následující příkaz:

npm start

A zkuste napsat tweet jako „Nerozumím ananasové pizze“ (řekni pravdu), vyberte datum, čas a klikněte na tlačítko „Naplánovat tweet“. Pokud požadavek uspěje, vytvořili jste nový dokument v kolekci tweets .

Výsledek si můžete prohlédnout na panelu Fauna:

Klientská část je hotová, nyní napíšeme náš server.

Server

Náš server bude žít v server složku v kořenové složce naší aplikace. Vytvořte složku a umístěte do ní jeden soubor, index.js, ze kterého budeme provozovat náš server.

K vytvoření našeho serveru použijeme populární framework NodeJS ExpressJS (NodeJS jsme mohli použít pouze pro naši aplikaci, ale s ExpressJS vytvoříme trasy API a v budoucnu rozšíříme naši funkcionalitu aplikace).

Chcete-li nainstalovat ExpressJS, spusťte následující příkaz v kořenové složce projektu v terminálu:

npm i express

Poté musíme nainstalovat balíček cron-job, aby náš server mohl každou minutu vyžadovat Faunu. Chcete-li to provést, spusťte ve svém terminálu následující příkaz:

npm i node-cron

Také musíme nainstalovat balíček dotenv. Načte proměnné prostředí z .env.local soubor do process.env. Tímto způsobem můžeme přistupovat k REACT_APP_FAUNADB_SECRET proměnná z kódu našeho serveru.

Chcete-li to provést, spusťte ve svém terminálu následující příkaz:

npm i dotenv

Poslední balíček, který musíme nainstalovat, je twitter-api-v2. Pomůže nám to zveřejňovat tweety na Twitteru.

npm i twitter-api-v2

Než začneme kódovat, musíme přidat token nosiče Twitter API, který jsme uložili v předchozích krocích. Chcete-li to provést, otevřete soubor .env.local a přidejte svůj token nosiče Twitteru pod REACT_APP_FAUNADB_SECRET :

// .env.local

REACT_APP_FAUNADB_SECRET=your-secret-key

TWITTER_BEARER_TOKEN=your-twitter-bearer-token

Nyní napíšeme samotný server. Otevřete server/index.js a přidejte tento kód serveru:

// server/index.js

const express = require('express')
const cron = require('node-cron')
const Fauna = require('Fauna')
const {TwitterApi} = require('twitter-api-v2')

const twitterClient = new TwitterApi(process.env.TWITTER_BEARER_TOKEN)

const q = Fauna.query

const faunaClient = new Fauna.Client({
 secret: process.env.REACT_APP_FAUNADB_SECRET,
})

// run every minute
cron.schedule('* * * * *', async () => {
 const now = new Date()
 now.setSeconds(0)
 now.setMilliseconds(0)

 try {
   // get all tweets from Now - 1 minute to Now
   const {data} = await faunaClient.query(
     q.Map(
       q.Paginate(q.Match(q.Index('tweetsByDate'), now.getTime())),
       q.Lambda(['date', 'ref'], q.Get(q.Var('ref')))
     )
   )

   // post all tweets from date range on twitter
   data.forEach(async ({data: {tweet}}) => {
     try {
       console.log(tweet)
       await twitterClient.v1.tweet(tweet)
     } catch (error) {
       console.log(error)
     }
   })
 } catch (error) {
   console.log(error)
 }
})

const app = express()

app.listen(3001, async () => {
 console.log(`Server listening on ${3001}`)
})

Podívejme se, co se zde děje zajímavého.

cron.schedule volá každou minutu funkci odpovědnou za publikování tweetů na Twitter.

Pomocí faunaClient, dostáváme všechny tweety v rozsahu aktuálního času a o minutu dříve.

   const {data} = await faunaClient.query(
     q.Map(
       q.Paginate(
         q.Range(
           q.Match(q.Index('tweetsByDate')),
           minuteAgo.toISOString(),
           now.toISOString()
         )
       ),
       q.Lambda(['date', 'ref'], q.Get(q.Var('ref')))
     )
   )

A pomocí twitterClient.v1.tweet(tweet) zveřejňujeme je na Twitteru.

Naše aplikace je připravena. Nyní vše otestujeme.

Spustit aplikaci

Nejprve vytvořte skript v package.json soubor, který spustí náš webový server, když spustíme příkaz npm start server v naší konzoli:

// package.json
...

"scripts": {
  "server": "node -r dotenv/config ./server/index.js dotenv_config_path=./.env.local",
  ...
}

Poté otevřete terminál a spusťte npm start server v jednom okně spustíte náš webový server a v dalším okně spusťte npm start ke spuštění našeho klienta.

Aplikace Twitter Post Scheduler je připravena!

Zde můžete najít úložiště s posledním příkladem.

V části 2 nasadíme naši aplikaci do Vercelu.