Dnes se chystáme vytvořit aplikaci Twitter Post Scheduler. Říkejme tomu Twitter.
Nástroje
Než začneme, ujistěte se, že máte
- Uzel a NPM ve vašem počítači. Oba si můžete stáhnout na nodejs.org.
- 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:
- Uživatelé napíší tweet, zvolí čas, kdy jej chtějí naplánovat, a kliknou na odeslat.
- Tweet se dostane do databáze a tam se uloží.
Serverová část:
- NodeJS volá databázi každou minutu, aby načetl všechny tweety, které je třeba v tu chvíli odeslat.
- 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:
- Přejděte na https://developer.twitter.com/en/apply-for-access
-
Klikněte na tlačítko „Požádat o účet vývojáře“
-
Vyberte, proč chcete získat přístup k Twitter API (zvolil jsem prozkoumat)
-
Proveďte všechny následující kroky, odpovězte na otázky a odešlete přihlášku.
-
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í)
-
Poté, co tým Twitteru vaši žádost schválí, přejděte na svůj řídicí panel a vytvořte nový projekt.
-
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.
- Přihlaste se nebo se zaregistrujte na svém účtu Fauna zde.
-
Klikněte na „Vytvořit databázi.“
-
Vyberte jméno a region
-
Klikněte na „Nová kolekce.“
-
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:
-
Přejděte na kartu „Zabezpečení“ a klikněte na „Nový klíč“.
-
Zadejte název klíče a klikněte na „Uložit“
-
Náš klíč API byl vygenerován.
-
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.