Former, Auth och Serverlösa Funktioner på Gatsby och Netlify

0
14

Att abstrahera infrastruktur ligger i vårt DNA. Vägar, skolor, vatten-nätverk—du får idén. Webbutveckling är inget undantag: serverlösa arkitekturer är ett vackert uttryck för detta fenomen. Statiska webbplatser, särskilt vänder sig till dynamiska, rika upplevelser.

Hantering statiska former, autentisering, och backend funktioner på statiskt-som genereras platser är nu en sak. Särskilt med JAMstack pionjär plattform som är Netlify. Nyligen meddelade stöd av AWS Lambda-funktioner på front-end-centrerad webbplatser och appar. Jag har tänkt att dyka in i deras “backend” funktioner sedan.

I dag, jag gör bara att använda en statisk Gatsby webbplats, Netlify Formulär, Identitet och Funktioner funktioner. Denna handledning kommer att visa dig hur du:

  • Lägga till statiska former till din webbplats
  • Lägg till användar-verifiering för lösenordsskyddade innehåll
  • Skapa en AWS Lambda-funktion

Redo att överladda en statisk webbplats med serverlösa funktioner?

Överväga att kolla in Netlify s Reagera-drivna statisk CMS efter detta inlägg! Och här är en tutorial på en hel kommentar arbetsflöde, komplett med ett system för godkännande, med JAMstack.

Statisk webbplats former, auth, och AWS Lambda-funktioner

Innan du dyker in i koden, låt oss närmare våra användningsfall. Jag kommer att använda tre olika Netlify serverlösa funktioner:

1. Identitet

Identitet kommer att användas för att skapa en lösenordsskyddad, gated innehåll avsnitt om Gatsby webbplats. Autentisering utan en backend har länge varit en smärta på statiska webbplatser. Men här fiffiga funktionen löser det elegant, vilket gör att utvecklare till:

Hantera registreringar, inloggningar, lösenord återhämtning och mer — allt utan att rulla dina egna authentication service.

2. Former

Former kommer att användas för att möjliggöra för användaren-in produkt recensioner på sajten. Dynamiska formulär kan ta många former (se vad jag gjorde där?), från enkla kontaktformulär för att kommentera, citera och system för utvärdering av ansluten till intern verktyg.

Det finns en uppsjö av lösningar för att hantera interaktiva former för statiska webbplatser. Men med Former du kan hantera dem direkt i din byggnad och webbhotell (Netlify kärna erbjuder). Inget behov för spam fälla mailto: länkar, konfigurera din egen server, sätta upp serverlösa funktioner, eller att integrera tredje part som Formspree eller FormKeep.

Inget JavaScript, Api: er, eller backend behövs bara en enkel HTML-formulär som är märkta med netlify HTML-attributet.

3. Funktioner

Funktioner kommer att användas för att ställa upp ett omdöme måtta arbetsflöde direkt i Slack. Under den här funktionen huva är AWS Lambda-funktioner—händelse utlöses, skalbara backend-kod som du kan köra utan din egen server. Utbyggnaden av dessa med Netlify är så enkelt som att lägga till en fil till en Git-repo.

Lambda-funktioner är verkligen kraftfull, men de kräver i regel en AWS konto och API-gateway-konfiguration. Som med Former, Funktioner och förenkla ditt liv genom att avlasta rännande att Netlify:

Ditt funktioner är version kontrollerad, byggas och placeras ut tillsammans med resten av din Netlify webbplats, och Netlify API gateway hanterar automatiskt service discovery. Plus, dina funktioner att dra nytta av Distribuera Förhandsvisningar och återställningar.

I ett nötskal, Funktioner gör att du kan förbättra webbplatsen interaktivitet + bridge front-och backend att låta data flöda mellan tjänster.

Serverlösa Gatsby på Netlify: auth, statiska former, och Lambda-funktioner

Jag ska få fart på denna tutorial med hjälp av en avskalad version av en tidigare Gatsby webbplats som vi byggt.

Att lära sig Gatsby grunderna, kolla in den officiella guiden. Vi har också två e-handel självstudier med Gatsby här och här.

Förutsättningar

För denna tutorial, du behöver:

  • En gratis Netlify konto
  • Netlify Former Pro för Slack integration (tillval betalas funktion)

1. Forking den Gatsby projekt

Börja med gaffel att räntan:

Visa på GitHub

Jag föreslår att leka runt med det för att bekanta sig med projektet. Produkter som finns i src/data/products mapp—alla i Wiki-filer. Dessa filer laddas under byggtiden och används för att mata in rätt information i våra mallar. Detta sker inne i gatsby-node.js fil.

2. Lägga till en Identitet för verifiering

Om du öppnat en produkt fil, du såg förmodligen att det är ett område som vi inte brukar använda i Snipcart demonstrationer: en privat egendom. Målet är enkla: visa dessa “exklusiva” produkter endast när en användare är inloggad.

För att hantera detta, jag använde Netlify Identitet widget, ett enkelt sätt att lägga till autentisering till en statisk webbplats.

Du kan installera Identitet paketet genom att köra:

npm install –spara netlify-identitet-widget

Se till att inkludera det i din header! Inuti src/components/Header/index.js fil, jag lade den här raden efter h1 avslutande taggen:

<div data-netlify-identitet-menyn></div>

Du kan sedan importera widgeten överst i din fil med

const netlifyIdentity = require(“netlify-identitet-widget”);

Och förklara componentDidMount funktion som sådan:

componentDidMount(){
netlifyIdentity.init();
}

Identitet widget nu sprutar korrekt inloggning former inuti <div>. Nu när du har en statisk form för att logga in behöver du lämpliga logik för att validera om en användare är inloggad eller inte.

Jag använde denna logik för att visa lämpligt, lösenordsskyddade produkter till inloggade användare. Att göra så har jag skapat en products.js inuti src/sidor-mappen, och definieras på följande komponenter:

importera Reagerar från ‘reagerar’
importera Länk från “gatsby-länk”
importera format från”. /produkter.modulen.css”
const netlifyIdentity = require(“netlify-identitet-widget”);

export standard klass Produkter sträcker sig Reagera.Komponent {
konstruktör(data){
super(data);

detta.state = {
produkter: []
}
}

getProducts(){
tillbaka netlifyIdentity.currentUser() != null
? detta.rekvisita.uppgifter.allMarkdownRemark.kanterna
: detta.rekvisita.uppgifter.allMarkdownRemark.kanterna
.filter(x => !x.nod.frontmatter.privat)
}

updateProducts(){
detta.setState({ produkter: här.getProducts() });
}

componentDidMount(){
netlifyIdentity.på(“login”, user => här.updateProducts());
netlifyIdentity.på(“logga ut”, () => här.updateProducts());
detta.updateProducts();
}

render(){
avkastning (
<div>
<h1>Products</h1>
<p>för Att logga in använder e-post: geeks@snipcart.com med lösenord: admin</p>

<ul className={stilar.itemsList}>
{detta.stat.produkter.karta((o, index) =>
<li key={index} className={stilar.objekt}>
<Länk till={o.nod.frontmatter.loc}>
<bild>
<img className={stilar.bild} src={o.nod.frontmatter.bild} alt={o.nod.frontmatter.namn}></img>
<figcaption className={stilar.figCaption}>Köpa {o.nod.frontmatter.name}</figcaption>
</bild>
</Link>
</li>
)}
</ul>
</div>)
}
}

export const query = graphql`
fråga allProducts {
allMarkdownRemark {
kanterna {
node {
frontmatter {
sku,
loc,
pris,
desc,
privata,
namn
bild
}
}
}
}
`

Jag kommer inte att förklara GraphQL lite här. Om du är intresserad, läs mer här.

Det viktiga att förstå är vad som händer inne i componentDidMountlifecycle funktion. Jag är bindande mig själv för att widgeten på “logga in” och “logga ut” – evenemang för att uppdatera tillgängliga produkter.

Slutresultatet är ganska häftigt:

3. Hantering statiska former för recensioner

För att lägga till produkt recensioner till Gatsby plats, jag använde Netlify Formulär. Du kan inkludera deras Formulär på din egen webbplats genom att lägga till ett ” data-netlify=”true”‘ (eller bara netlify) attribut till en form förklaring. Jag ingår det i min src/components/product.js fil efter den sista avsnitt tag.

Du kommer också att behöva förklara en formId variabel innan återlämnandet av din rendera funktion, till exempel:

render(){
om(detta.rekvisita.uppgifter.markdownRemark.frontmatter.privat
&& !detta.stat.loggedIn){
tillbaka fourOfour();
}

var formId = ” produkt-${detta.rekvisita.uppgifter.markdownRemark.frontmatter.sku}`

const-knappen =.rekvisita.uppgifter.markdownRemark.frontmatter.privat ? (
<button type=”button” className={`${stilar.buyButton}`}>
SÄLJS UT
</button>
) : (
<button type=”button” className={`${stilar.buyButton} snipcart lägga till posten”}
data-item-namn={detta.rekvisita.uppgifter.markdownRemark.frontmatter.name}
data-item-id={detta.rekvisita.uppgifter.markdownRemark.frontmatter.sku}
data-item-image={detta.rekvisita.uppgifter.markdownRemark.frontmatter.bild}
data-artikel-url={`${NETLIFY_URL}${detta.rekvisita.läge.sökväg}`}
data-item-pris={detta.rekvisita.uppgifter.markdownRemark.frontmatter.priset}
data-item-description={detta.rekvisita.uppgifter.markdownRemark.frontmatter.desc}>
Köp den nu för {det här.rekvisita.uppgifter.markdownRemark.frontmatter.priset}$
</button>
);

avkastning (
<div>
<h1>{detta.rekvisita.uppgifter.markdownRemark.frontmatter.name}</h1>
<div className={stilar.smuldeg}>
<Länk till=’/’>Tillbaka till produkter</Link>
</div>
<p>{detta.rekvisita.uppgifter.markdownRemark.frontmatter.desc}</p>

<avsnitt className=”avsnittet__produkt”>
<figur className={stilar.productFigure}>
<img src={detta.rekvisita.uppgifter.markdownRemark.frontmatter.bild} />
</bild>

<artikel>
{detta.rekvisita.uppgifter.markdownRemark.frontmatter.beskrivning}
</article>
<div className={stilar.åtgärder}>
{knappen}
</div>
</section>
<punkt>
<h3 className=”recensioner”>Recensioner</h3>
<div className=”recensioner__list”>
{detta.stat.recensioner.karta (o) =>
<p key={o.antalet}>
<div className=”översyn__namn”>{o.name}</div>
<div>{o.uppgifter.meddelande}</div>
</p>
)}
</div>

<formen className=”översyn__formen” namn={formId} method=”POST” data-netlify-honeypot=”bot-fältet” data-netlify=”true”>
<input type=”hidden” name=”form-namn” value={formId} />
<div className=”field__form”>
<etikett> > NAMN</label>
<input type=”text” name=”namn”></input>
</div>
<div className=”field__form”>
<label>E-post</label>
<input type=”e-post” name=”email”></input>
</div>
<div className=”field__form”>
<label>MEDDELANDE</label>
<textarea name=”message”></textarea>
</div>

<knappen className=”knappen__form” type=”submit”>SKICKA</button>
</form>
</section>
</div>)
}

Boom, statiska former är på din sida!

Men för att visa inlagor som kommer in genom dessa former, behöver du en Netlify funktion för att hämta och återgå användarrecensioner. Att göra så, jag skapade en netlify.toml-fil med följande innehåll:

[bygger]
funktioner = “funktioner”

Jag satte sedan en funktioner mappen direkt i rot-projekt. Inuti den, placerade jag en fetchreviews.js filen med:

const https = require(‘https’);

exporten.handler = function(event, sammanhang, återuppringning) {
var id = evenemanget.queryStringParameters.id;
var token = process.env.netlify_access_token;

om(id == undefined){
återuppringning (“En produkt-id måste anges.’, {
statusCode: 500
})
}

var alt = {
värdnamn: ‘api.netlify.com’,
port: 443,
metod: ‘GET’,
rubriker: {
‘Content-Type”: “application/json’
}
};

var queryToken = `access_token=${token}`;
var opts1 = Objekt.tilldela({}, alternativ, { sökväg: `/api/v1/sites/${processen.env.site_id}/blanketter?${queryToken}`});

var req = https.begäran(opts1, funktion(res) {

res.setEncoding(‘utf8’);
var kroppen = “”;

res.(‘data’, data => {
kroppen += data;
});

res.på (“avsluta”, function () {
kroppen = JSON.parse(kroppen);

var form = kroppen.filter(x => x.namn == `produkt-${id}`)[0];
var opts2 = Objekt.tilldela({}, alternativ, { sökväg: `/api/v1/blanketter/${form.id}/synpunkter?${queryToken}`});

var req2 = https.begäran(opts2, funktion(res2) {
res2.setEncoding(‘utf8’);
var kropp2 = “”;

res2.(“data”, (data) => {
kropp2 += data;
});

res2.på (“avsluta”, function () {
återuppringning(null, {
statusCode: 200,
rubriker: {
“Access-Control-Tillåta-Ursprung” : “*”,
‘Content-Type”: “application/json’
},
kropp: kropp2
})
});
});

req2.end();
});
});

req.end();
}

Funktionen kontrollerar om ett produkt-ID gavs som en frågeparameter. Om det är en ID, den hämtar form med namnet produkt-{produkt-id) för att få alla recensioner från det. På detta sätt kunde jag visa recensioner i fronten.

Jag har lagt två funktioner för att product.js gör så här:

konstruktör(rekvisita){
super(rekvisita);

detta.state = {
recensioner: [],
loggedIn: falskt
}
}

componentDidMount(){
hämta(`https://${NETLIFY_FUNC}/fetchreviews?id=${detta.rekvisita.uppgifter.markdownRemark.frontmatter.sku}`)
.då(x => x.json())
.då(x => {
detta.setState({recensioner: x})
})

om(netlifyIdentity.currentUser() != null){
detta.setState({loggedIn: true});
}

netlifyIdentity.på(“login”, user => här.setState({loggedIn: true}));
netlifyIdentity.på(“logga ut”, () => här.setState({loggedIn: false}));
}

Då, precis innan den översyn form:

{detta.stat.recensioner.karta (o) =>
<p key={o.antalet}>{o.namn}: {o.uppgifter.meddelande}</p>
)}

Ovan, den monterade komponenten hämtar nya funktioner för att få specifik produkt recensioner. Den uppdaterar också staten, och visa dem på sidorna. Du kan också se att vi bestämde oss för att sätta en “Sålt ut” knappen för egna produkter, detta eftersom dessa är privat och kommer inte att passera vår validering om vi bara skulle sätta den aktuella URL: en, kan vi fortfarande göra det, men det skulle krävas lite mer arbete utanför ramen för denna demo.

Om du vill testa dina funktioner utan utbyggnaden av att Netlify, använda netlify-lambda node paket för att göra det lokalt. När du har installerat den (npm install netlify-lambda) kör netlify-lambda tjäna ./ i din projektmapp. Funktionen kommer att köra på http://localhost:9000/fetchreviews.

Du kan uppdatera hämta rutt ovan och får samma beteende som du skulle ha med en värd funktion.

4. Konfigurera en AWS Lambda funktion med Slack

Du kommer att behöva Netlify Former Pro för att aktivera en funktion på formen inlagor.

Sist men inte minst: recensioner måtta arbetsflöde direkt i Slack. Målet är enkelt: skjut granska information och anmälan att Slappa och göra det möjligt att antingen *hålla med* eller *avvisa* gå från Slak.

Att göra så, jag har skapat 2 nya funktioner i funktioner mapp: notifyslack.js och answerslack.js. Den första är anmälda av Netlify är webhook av varje formulär och är ansvarig för att kommunicera detta till Slack med lämpliga åtgärder. Jag skapade ett litet Slack-appen för att detta ska fungera (referens).

Här är appen behöver behörigheter:

Interaktiva komponenter config:

Den URL – fältet är där din Netlify funktion kan kallas.

Med dessa ställa upp, jag installerade min app och öppnade den Inkommande webhooks fliken. Jag kopierade webhook URL, och kom tillbaka till mitt projekt.

Inne funktioner, jag skapade notifyslack.js filen med:

var https = require(“https”);

exporten.handler = function(event, sammanhang, återuppringning) {
var kroppen = JSON.parse(händelse.kroppen);

om(kropp != null && kropp.data != null){
var data = kroppen.uppgifter.

var message = `Ny recension från ${data.e-post} n ${data.namn}: ${data.meddelande}`;
var bifoga = [
{
“title”: “Granska ID”,
“text”: kropp.id
},
{
“title”: “vill du behålla översynen?”,
“text”: meddelande,
“fallback”: “kan Du inte vidta åtgärder för denna översyn.”,
“callback_id”: “answer_netlify”,
“färg” i: “#3AA3E3”,
“attachment_type”: “default”,
“åtgärder”: [
{
“name”: “svar”,
“text”: “Behåll”,
“typ”: “knappen”,
“värde”: “hålla”
},
{
“name”: “svar”,
“text”: “Avvisa”,
“typ”: “knappen”,
“style”: “fara”,
“värde”: “avvisa”,
“bekräfta”: {
“title”: “Är du säker?”,
“text”: “När det är gjort översynen kommer att raderas”,
“ok_text”: “Ja”,
“dismiss_text”: “Nej”
}
}
]
}
]

var postData = JSON.stringify({
bilagor: bifoga
});

var alt = {
värdnamn: ‘hooks.slack.com’,
port: 443,
sökväg: process.env.slack_webhook_url,
metod: ‘POST’,
rubriker: {
‘Content-Type”: “application/json’
}
};

var req = https.begäran(val, funktion(res) {

res.setEncoding(‘utf8’);

res.på (“avsluta”, function () {
återuppringning(null, {
statusCode: 200
})
});
});

req.på(‘fel’, function (e) {
konsolen.logga in (“Problem med begäran:’ e.meddelande);
});

req.skriv(postData);
req.end();

återuppringning(null, {
statusCode: 200
})
}
}

Här behöver du uppdatera sökvägen värdet av optioner som objekt med ditt motsvarande Slack app webhook URL.

Just nu, detta skulle bara meddela Slack—oavsett vilken åtgärd du valde skulle inte utlösa något annat.

För att göra Slack interaktiv anmälan, skapade jag en 3: e funktion i en fil som heter answerslack.js. Denna funktion är förmodligen den mest komplicerade, men det är mest förfrågningar overhead, så stå ut med mig:

var https = require(“https”);
var qs = require(‘querystring’)

funktionen getURL(href) {
var match = href.match(/^(https?:)//(([^:/?#]*)(?::([0-9]+))?)([/]{0,1}[^?#]*)(?[^#]*|)(#.*|)$/);
avkastning match && {
href: href,
protokoll: match[1],
värd: match[2],
värdnamn: match[3],
hamn: match[4],
sökväg: match[5],
sök: match[6],
hash: match[7]
}
}

exporten.handler = function(event, sammanhang, återuppringning) {
var json = JSON.parse(qs.parse(händelse.kroppen).nyttolast);

var svar = json.åtgärder[0].värde.
var access_token = process.env.netlify_access_token;
var id = json.original_message.bilagor[0].sms: a;

if(svar == ‘avvisa’){
var alt = {
värdnamn: ‘api.netlify.com’,
port: 443,
sökväg: `/api/v1/inlämningar/${id}?access_token=${access_token}`,
metod: ‘RADERA’,
rubriker: {
‘Content-Type”: “application/json’
}
};

var req1 = https.begäran(val, funktion(res) {

res.setEncoding(‘utf8’);

res.på (“avsluta”, function () {
konsolen.logga in (“Översyn med id: ${id} var tagits bort.`)
});
});

req1.på(‘fel’, function (e) {
konsolen.logga in (“Problem med begäran:’ e.meddelande);
});

req1.end();
}

var postData = JSON.stringify({
replace_original: sant,
bilagor: [{
text: svar == ‘hålla’
? Översyn (${id}) blev godkänd!`
: `Den översyn (${id}) avvisades.`
}]
});

var url = getURL(json.response_url);

var alt = {
värdnamn: url.hostname,
sökväg: url.sökväg,
metod: ‘POST’,
rubriker: {
‘Content-Type”: “application/json’
}
};

var req = https.begäran(val, funktion(res) {

res.setEncoding(‘utf8’);

res.på (“avsluta”, function () {
återuppringning(null, {
statusCode: 200
})
});
});

req.på(‘fel’, function (e) {
konsolen.logga in (“Problem med begäran:’ e.meddelande);
});

req.skriv(postData);
req.end();

återuppringning(null, {
statusCode: 200
})
}

Jag tolkar händelsen nyttolast och kontrollera om de åtgärder värde var avvisa. Om det inte, det är nödvändigtvis hålla—inget att göra. Men om det är, jag måste ringa Netlify s API för att ta bort den avvisade granskning. Jag hämtar granska ID sätta tidigare inne i första bifogad text med följande rad:

json.original_message.bilagor[0].sms: a;

När detta är gjort, kan jag ta bort det med ett API-anrop. Jag ger våra Slack användare feedback genom att ringa svar URL.

Jag är lite stolt över den slutliga arbetsflöde här TBH:

5. Distribuera Gatsby plats på Netlify

Här, jag sköt upp allt till GitHub och hakade det upp till Netlify med hjälp av dessa inställningar:

Du kan se att vi har använt några av de miljövariabler med processen.env.{variabel} notation i demoversionen.

Dessa är privata inställningar som vi inte vill ha att göra offentlig. För att definiera din direkt, gå till /inställningar/vecklas i Netlify instrumentbräda, tryck Redigera variabler, och mata in följande:

  • netlify_access_token: token har skapat tidigare inne netlify
  • site_id: Din webbadress utan protokollet
  • slack_webhook_url: Din Slack app webhook URL

Webbplats används, tid att leka!

Läs här för att lära dig att använda en webbplats på Netlify.

Live demo och GitHub repo