Infrastruktur zu abstrahieren liegt in unserer DNA. Straßen, Schulen, Wasserversorgungsnetze – Sie verstehen schon. Webentwicklung ist keine Ausnahme: Serverless Architekturen sind ein wunderschöner Ausdruck dieses Phänomens. Insbesondere statische Websites verwandeln sich in dynamische, reichhaltige Erlebnisse.
Die Verarbeitung von statischen Formularen, Authentifizierung und Backend-Funktionen auf statisch generierten Websites ist jetzt möglich. Insbesondere mit der JAMstack-Pionierplattform Netlify. Kürzlich kündigten sie die Unterstützung von AWS Lambda-Funktionen für Frontend-zentrierte Websites und Apps an. Ich hatte vor, mich seitdem mit ihren „Backend“-Funktionen zu beschäftigen.
Heute mache ich genau das, indem ich **eine statische Gatsby-Site, Netlify Forms, Identity und Functions Features** verwende. Dieses Tutorial zeigt Ihnen, wie Sie
- statische Formulare zu Ihrer Website hinzufügen
- Benutzerauthentifizierung für passwortgeschützte Inhalte hinzufügen
- eine AWS Lambda-Funktion erstellen
Bereit, eine statische Website mit Serverless-Funktionen aufzurüsten?
Erwägen Sie nach diesem Beitrag, sich Netlifys React-basiertes statisches CMS anzusehen! Und hier ist ein Tutorial zu einem vollständigen Kommentar-Workflow, komplett mit einem Genehmigungssystem, unter Verwendung des JAMstack.
Statische Formulare, Authentifizierung und AWS Lambda-Funktionen für statische Websites

Bevor wir uns in den Code stürzen, lassen Sie uns unseren Anwendungsfall detailliert beschreiben. Ich werde drei verschiedene Netlify Serverless Features verwenden
1. Identity
Identity wird verwendet, um einen passwortgeschützten, gesperrten Inhaltsbereich auf der Gatsby-Site zu erstellen. Authentifizierung ohne Backend war lange ein Problem bei statischen Websites. Aber diese clevere Funktion löst es elegant und ermöglicht es Entwicklern,
Anmeldungen, Logins, Passwortwiederherstellung und mehr zu verwalten – alles ohne eigene Authentifizierungsdienste entwickeln zu müssen.
2. Forms
Forms werden verwendet, um benutzergenerierte Produktbewertungen auf der Website zu ermöglichen. Dynamische Formulare können viele Formen annehmen (sehen Sie, was ich hier getan habe?), von einfachen Kontaktformularen bis hin zu Kommentar-, Bewertungs- und Rezensionssystemen, die mit internen Tools verknüpft sind.
Es gibt eine Fülle von Lösungen, um interaktive Formulare auf statischen Websites zu verarbeiten. Aber mit Forms können Sie diese direkt in Ihrem Build- und Hosting-Dienst (Netlifys Kernangebot) verarbeiten. Kein Bedarf an Spam-Schutz mailto:-Links, Konfiguration Ihres eigenen Servers, Einrichtung von Serverless Functions oder Integration von Drittanbietern wie Formspree oder FormKeep.
Kein JavaScript, keine APIs, kein Backend erforderlich: nur ein einfaches HTML-Formular mit dem netlify HTML-Attribut.
3. Functions
Functions werden verwendet, um einen Workflow zur Moderation von Bewertungen direkt in Slack einzurichten. Unter der Haube dieser Funktion verbergen sich AWS Lambda-Funktionen – ereignisgesteuerter, skalierbarer Backend-Code, den Sie ohne eigenen Server ausführen können. Die Bereitstellung dieser mit Netlify ist so einfach wie das Hinzufügen einer Datei zu einem Git-Repository.
Lambda-Funktionen sind in der Tat leistungsstark, erfordern aber normalerweise ein AWS-Konto und eine API-Gateway-Konfiguration. Wie bei Forms vereinfacht Functions Ihr Leben, indem es die Vorarbeit an Netlify abgibt.
Ihre Funktionen werden zusammen mit dem Rest Ihrer Netlify-Website versionskontrolliert, erstellt und bereitgestellt, und das Netlify API-Gateway kümmert sich automatisch um die Serviceerkennung. Außerdem profitieren Ihre Funktionen von der Leistung von Deploy Previews und Rollbacks.
Kurz gesagt, Functions ermöglichen es Ihnen, die Interaktivität der Website zu verbessern + die Verbindung zwischen Frontend und Backend herzustellen, um Daten zwischen Diensten fließen zu lassen.
Serverless Gatsby auf Netlify: Authentifizierung, statische Formulare und Lambda-Funktionen

Ich werde dieses Tutorial mit einer abgespeckten Version einer früheren Gatsby-Website, die wir erstellt haben, beginnen.
Um die Grundlagen von Gatsby zu erlernen, schauen Sie sich das offizielle Tutorial an. Wir haben auch zwei E-Commerce-Tutorials mit Gatsby hier und hier.
Voraussetzungen
Für dieses Tutorial benötigen Sie
- Ein kostenloses Netlify-Konto
- Netlify Forms Pro für die Slack-Integration (optional – kostenpflichtige Funktion)
1. Gatsby-Projekt forken
Beginnen Sie damit, das Repository zu forken
Ich empfehle, damit herumzuspielen, um sich mit dem Projekt vertraut zu machen. Produkte befinden sich im Ordner src/data/products – alle in Markdown-Dateien. Diese Dateien werden zur Build-Zeit geladen und verwendet, um die richtigen Informationen in unsere Templates einzufügen. Dies geschieht in der Datei gatsby-node.js.
2. Identity für Authentifizierung hinzufügen
Wenn Sie eine Produktdatei geöffnet haben, haben Sie wahrscheinlich ein Feld gesehen, das wir in Snipcart-Demos normalerweise nicht verwenden: ein privates Attribut. Das Ziel ist einfach: Zeigen Sie diese „exklusiven“ Produkte nur an, wenn ein Benutzer angemeldet ist.
Um dies zu handhaben, habe ich das Netlify Identity Widget verwendet, eine einfache Möglichkeit, Authentifizierung zu einer statischen Website hinzuzufügen.
Sie können das Identity-Paket installieren, indem Sie Folgendes ausführen
npm install --save netlify-identity-widget
Stellen Sie sicher, dass Sie es in Ihrer Kopfzeile einfügen! Innerhalb der Datei src/components/Header/index.js habe ich diese Zeile nach dem schließenden h1-Tag hinzugefügt
<div data-netlify-identity-menu></div>
Sie können das Widget dann am Anfang Ihrer Datei mit Folgendem importieren
const netlifyIdentity = require("netlify-identity-widget");
Und eine componentDidMount Funktion wie folgt deklarieren
componentDidMount(){
netlifyIdentity.init();
}
Das Identity-Widget fügt nun entsprechende Login-Formulare in dieses <div> ein. Jetzt, da Sie ein statisches Formular zum Anmelden haben, benötigen Sie die entsprechende Logik, um zu validieren, ob ein Benutzer angemeldet ist oder nicht.
Ich habe diese Logik verwendet, um angemeldete Benutzer mit entsprechenden, passwortgeschützten Produkten anzuzeigen. Dazu habe ich products.js im Ordner src/pages erstellt und die folgende Komponente definiert
import React from 'react'
import Link from 'gatsby-link'
import styles from './products.module.css'
const netlifyIdentity = require("netlify-identity-widget");
export default class Products extends React.Component {
constructor(data){
super(data);
this.state = {
products: []
}
}
getProducts(){
return netlifyIdentity.currentUser() != null
? this.props.data.allMarkdownRemark.edges
: this.props.data.allMarkdownRemark.edges
.filter(x => !x.node.frontmatter.private)
}
updateProducts(){
this.setState({ products: this.getProducts() });
}
componentDidMount(){
netlifyIdentity.on("login", user => this.updateProducts());
netlifyIdentity.on("logout", () => this.updateProducts());
this.updateProducts();
}
render(){
return (
<div>
<h1>Products</h1>
<p>To login use the email: [email protected] with password: admin</p>
<ul className={styles.itemsList}>
{this.state.products.map((o, index) =>
<li key={index} className={styles.item}>
<Link to={o.node.frontmatter.loc}>
<figure>
<img className={styles.image} src={o.node.frontmatter.image} alt={o.node.frontmatter.name}></img>
<figcaption className={styles.figCaption}>Buy the {o.node.frontmatter.name} now</figcaption>
</figure>
</Link>
</li>
)}
</ul>
</div>)
}
}
export const query = graphql`
query allProducts {
allMarkdownRemark {
edges {
node {
frontmatter {
sku,
loc,
price,
desc,
private,
name,
image
}
}
}
}
`
Ich werde das GraphQL-Zeug hier nicht erklären. Wenn Sie interessiert sind, lesen Sie hier mehr.
Der wichtige Teil zum Verständnis ist, was innerhalb der componentDidMount Lifecycle-Funktion passiert. Ich binde mich an die 'login'- und 'logout'-Ereignisse des Widgets, um verfügbare Produkte zu aktualisieren.
Das Endergebnis ist ziemlich beeindruckend

3. Statische Formulare für Bewertungen verarbeiten
Um Produktbewertungen zur Gatsby-Site hinzuzufügen, habe ich Netlifys Forms verwendet. Sie können ihre Forms auf Ihrer eigenen Website einbinden, indem Sie ein 'data-netlify="true"' (oder einfach netlify) Attribut zu einer Formularerklärung hinzufügen. Ich habe es in meiner src/components/product.js-Datei, nach dem letzten section-Tag, eingefügt.
Sie müssen auch eine formId-Variable vor dem Return Ihrer Render-Funktion deklarieren, wie zum Beispiel
render(){
if(this.props.data.markdownRemark.frontmatter.private
&& !this.state.loggedIn){
return fourOfour();
}
var formId = `product-${this.props.data.markdownRemark.frontmatter.sku}`
const button = this.props.data.markdownRemark.frontmatter.private ? (
<button type="button" className={`${styles.buyButton}`}>
SOLD OUT
</button>
) : (
<button type="button" className={`${styles.buyButton} snipcart-add-item`}
data-item-name={this.props.data.markdownRemark.frontmatter.name}
data-item-id={this.props.data.markdownRemark.frontmatter.sku}
data-item-image={this.props.data.markdownRemark.frontmatter.image}
data-item-url={`${NETLIFY_URL}${this.props.location.pathname}`}
data-item-price={this.props.data.markdownRemark.frontmatter.price}
data-item-description={this.props.data.markdownRemark.frontmatter.desc}>
Buy it now for {this.props.data.markdownRemark.frontmatter.price}$
</button>
);
return (
<div>
<h1>{this.props.data.markdownRemark.frontmatter.name}</h1>
<div className={styles.breadcrumb}>
<Link to='/'>Back to the products</Link>
</div>
<p>{this.props.data.markdownRemark.frontmatter.desc}</p>
<section className="section__product">
<figure className={styles.productFigure}>
<img src={this.props.data.markdownRemark.frontmatter.image} />
</figure>
<article>
{this.props.data.markdownRemark.frontmatter.description}
</article>
<div className={styles.actions}>
{button}
</div>
</section>
<section>
<h3 className="reviews">Reviews</h3>
<div className="reviews__list">
{this.state.reviews.map((o) =>
<p key={o.number}>
<div className="review__name">{o.name}</div>
<div>{o.data.message}</div>
</p>
)}
</div>
<form className="review__form" name={formId} method="POST" data-netlify-honeypot="bot-field" data-netlify="true">
<input type="hidden" name="form-name" value={formId} />
<div className="field__form">
<label>NAME</label>
<input type="text" name="name"></input>
</div>
<div className="field__form">
<label>EMAIL</label>
<input type="email" name="email"></input>
</div>
<div className="field__form">
<label>MESSAGE</label>
<textarea name="message"></textarea>
</div>
<button className="button__form" type="submit">SEND</button>
</form>
</section>
</div>)
}
Boom, statische Formulare sind auf Ihrer Website!
Um die über diese Formulare eingehenden Einreichungen anzuzeigen, benötigen Sie jedoch eine Netlify-Funktion, um Benutzerbewertungen abzurufen und zurückzugeben. Dazu habe ich eine netlify.toml-Datei mit folgendem Inhalt erstellt
[build]
functions = "functions"
Ich habe dann einen functions-Ordner direkt im Stammverzeichnis des Projekts platziert. Darin habe ich eine fetchreviews.js-Datei mit folgendem Inhalt abgelegt
const https = require('https');
exports.handler = function(event, context, callback) {
var id = event.queryStringParameters.id;
var token = process.env.netlify_access_token;
if(id == undefined){
callback('A product id must be specified.', {
statusCode: 500
})
}
var options = {
hostname: 'api.netlify.com',
port: 443,
method: 'GET',
headers: {
'Content-Type': 'application/json'
}
};
var queryToken = `access_token=${token}`;
var opts1 = Object.assign({}, options, { path: `/api/v1/sites/${process.env.site_id}/forms?${queryToken}`});
var req = https.request(opts1, function(res) {
res.setEncoding('utf8');
var body = "";
res.on('data', data => {
body += data;
});
res.on('end', function () {
body = JSON.parse(body);
var form = body.filter(x => x.name == `product-${id}`)[0];
var opts2 = Object.assign({}, options, { path: `/api/v1/forms/${form.id}/submissions?${queryToken}`});
var req2 = https.request(opts2, function(res2) {
res2.setEncoding('utf8');
var body2 = "";
res2.on("data", (data) => {
body2 += data;
});
res2.on('end', function () {
callback(null, {
statusCode: 200,
headers: {
"Access-Control-Allow-Origin" : "*",
'Content-Type': 'application/json'
},
body: body2
})
});
});
req2.end();
});
});
req.end();
}
Die Funktion prüft, ob ein Produkt-ID als Query-Parameter angegeben wurde. Wenn eine ID vorhanden ist, ruft sie das Formular mit dem Namen product-{product-id} ab, um alle Bewertungen davon zu erhalten. Auf diese Weise könnte ich Bewertungen im Frontend anzeigen.
Ich habe zwei Funktionen zu product.js hinzugefügt, um dies zu tun
constructor(props){
super(props);
this.state = {
reviews: [],
loggedIn: false
}
}
componentDidMount(){
fetch(`https://${NETLIFY_FUNC}/fetchreviews?id=${this.props.data.markdownRemark.frontmatter.sku}`)
.then(x => x.json())
.then(x => {
this.setState({reviews: x})
})
if(netlifyIdentity.currentUser() != null){
this.setState({loggedIn: true});
}
netlifyIdentity.on("login", user => this.setState({loggedIn: true}));
netlifyIdentity.on("logout", () => this.setState({loggedIn: false}));
}
Dann, kurz vor dem Bewertungsformular
{this.state.reviews.map((o) =>
<p key={o.number}>{o.name}: {o.data.message}</p>
)}
Oben ruft die gemountete Komponente die neuen Funktionen auf, um spezifische Produktbewertungen abzurufen. Sie aktualisiert auch den Zustand und zeigt sie auf den Seiten an. Sie können auch sehen, dass wir beschlossen haben, einen „Ausverkauft“-Button für private Produkte zu verwenden. Das liegt daran, dass diese privat sind und unsere Validierung nicht bestehen würden, wenn wir einfach die aktuelle URL verwenden würden. Wir könnten es immer noch tun, aber das würde etwas mehr Arbeit erfordern, die über den Rahmen dieser Demo hinausgeht.
Wenn Sie Ihre Funktionen testen möchten, ohne sie auf Netlify zu deployen, verwenden Sie das netlify-lambda Node-Paket, um dies lokal zu tun. Sobald Sie es installiert haben (npm install netlify-lambda), führen Sie netlify-lambda serve ./ in Ihrem Projektordner aus. Die Funktion wird unter https://:9000/fetchreviews ausgeführt.
Sie können die Fetch-Route oben aktualisieren und das gleiche Verhalten erzielen, das Sie mit einer gehosteten Funktion hätten.
4. Konfiguration einer AWS Lambda-Funktion mit Slack
Sie benötigen Netlify Forms Pro, um eine Funktion bei Formularübermittlungen auszulösen.
Last but not least: der Reviews-Moderations-Workflow direkt in Slack. Das Ziel ist einfach: Übermittlungsdetails und Benachrichtigungen an Slack pushen und es ermöglichen, eine Bewertung entweder von Slack aus *zu behalten* oder *abzulehnen*.
Dazu habe ich 2 neue Funktionen im functions-Ordner erstellt: notifyslack.js und answerslack.js. Die erste wird durch den Webhook von Netlify bei jeder Formularübermittlung benachrichtigt und ist dafür verantwortlich, dies mit entsprechenden Aktionspunkten an Slack zu kommunizieren. Ich habe dafür eine kleine Slack-App erstellt (Referenz).
Hier sind die Berechtigungen, die die App benötigt

Konfiguration der interaktiven Komponenten

Das Feld Request URL ist der Punkt, an dem Ihre Netlify-Funktion aufgerufen werden kann.
Mit diesen Einstellungen habe ich meine App installiert und den Tab Incoming webhooks geöffnet. Ich habe die Webhook-URL kopiert und bin zu meinem Projekt zurückgekehrt.
Innerhalb von functions habe ich die Datei notifyslack.js mit folgendem Inhalt erstellt
var https = require("https");
exports.handler = function(event, context, callback) {
var body = JSON.parse(event.body);
if(body != null && body.data != null){
var data = body.data;
var message = `New review from ${data.email} \n ${data.name}: ${data.message}`;
var attach = [
{
"title": "Review ID",
"text": body.id
},
{
"title": "Do you want to keep the review?",
"text": message,
"fallback": "You can't take actions for this review.",
"callback_id": "answer_netlify",
"color": "#3AA3E3",
"attachment_type": "default",
"actions": [
{
"name": "response",
"text": "Keep",
"type": "button",
"value": "keep"
},
{
"name": "response",
"text": "Reject",
"type": "button",
"style": "danger",
"value": "reject",
"confirm": {
"title": "Are you sure?",
"text": "Once it's done the review will be deleted",
"ok_text": "Yes",
"dismiss_text": "No"
}
}
]
}
]
var postData = JSON.stringify({
attachments: attach
});
var options = {
hostname: 'hooks.slack.com',
port: 443,
path: process.env.slack_webhook_url,
method: 'POST',
headers: {
'Content-Type': 'application/json'
}
};
var req = https.request(options, function(res) {
res.setEncoding('utf8');
res.on('end', function () {
callback(null, {
statusCode: 200
})
});
});
req.on('error', function (e) {
console.log('Problem with request:', e.message);
});
req.write(postData);
req.end();
callback(null, {
statusCode: 200
})
}
}
Hier müssen Sie den Pfadwert des Optionen-Objekts mit Ihrer entsprechenden Slack-App-Webhook-URL aktualisieren.
Im Moment würde dies nur Slack benachrichtigen – jede gewählte Aktion würde nichts weiter auslösen.
Um die Slack-Benachrichtigung interaktiv zu gestalten, habe ich eine 3. Funktion in einer Datei namens answerslack.js erstellt. Diese Funktion ist wahrscheinlich die komplizierteste, aber sie ist hauptsächlich Anfrage-Overhead, also halten Sie durch.
var https = require("https");
var qs = require('querystring')
function getURL(href) {
var match = href.match(/^(https?\:)\/\/(([^:\/?#]*)(?:\:([0-9]+))?)([\/]{0,1}[^?#]*)(\?[^#]*|)(#.*|)$/);
return match && {
href: href,
protocol: match[1],
host: match[2],
hostname: match[3],
port: match[4],
pathname: match[5],
search: match[6],
hash: match[7]
}
}
exports.handler = function(event, context, callback) {
var json = JSON.parse(qs.parse(event.body).payload);
var answer = json.actions[0].value;
var access_token = process.env.netlify_access_token;
var id = json.original_message.attachments[0].text;
if(answer == 'reject'){
var options = {
hostname: 'api.netlify.com',
port: 443,
path: `/api/v1/submissions/${id}?access_token=${access_token}`,
method: 'DELETE',
headers: {
'Content-Type': 'application/json'
}
};
var req1 = https.request(options, function(res) {
res.setEncoding('utf8');
res.on('end', function () {
console.log(`Review with id: ${id} was deleted successfully.`)
});
});
req1.on('error', function (e) {
console.log('Problem with request:', e.message);
});
req1.end();
}
var postData = JSON.stringify({
replace_original: true,
attachments: [{
text: answer == 'keep'
? `The review (${id}) was approved!`
: `The review (${id}) was rejected.`
}]
});
var url = getURL(json.response_url);
var options = {
hostname: url.hostname,
path: url.pathname,
method: 'POST',
headers: {
'Content-Type': 'application/json'
}
};
var req = https.request(options, function(res) {
res.setEncoding('utf8');
res.on('end', function () {
callback(null, {
statusCode: 200
})
});
});
req.on('error', function (e) {
console.log('Problem with request:', e.message);
});
req.write(postData);
req.end();
callback(null, {
statusCode: 200
})
}
Ich analysiere die Event-Payload und prüfe, ob der Aktionswert reject war. Wenn nicht, ist er zwangsläufig keep – nichts zu tun. Aber wenn es das ist, muss ich die Netlify-API aufrufen, um die abgelehnte Bewertung zu löschen. Ich rufe die zuvor in den ersten Anhangstext eingefügte Bewertungs-ID mit der folgenden Zeile ab
json.original_message.attachments[0].text;
Sobald dies erledigt ist, kann ich sie mit einem API-Aufruf löschen. Ich gebe dann unseren Slack-Benutzern Feedback, indem ich die Antwort-URL aufrufe.
Ich bin ziemlich stolz auf den endgültigen Workflow hier Ehrlich gesagt

5. Bereitstellung der Gatsby-Site auf Netlify
Hier habe ich alles nach GitHub gepusht und es mit Netlify über diese Einstellungen verbunden

Sie können sehen, dass wir einige der Umgebungsvariablen mit der process.env.{variable}-Notation im Demo verwendet haben.
Dies sind private Einstellungen, die wir nicht öffentlich machen möchten. Um Ihre eigenen direkt zu definieren, gehen Sie zu /settings/deploys im Netlify Dashboard, klicken Sie auf Edit variables und geben Sie Folgendes ein
netlify_access_token: Das zuvor in Netlify erstellte Tokensite_id: Ihre Website-URL ohne Protokollslack_webhook_url: Die Webhook-URL Ihrer Slack-App
Website bereitgestellt; Zeit zum Spielen!
Lesen Sie dies, um zu erfahren, wie Sie eine Website auf Netlify bereitstellen.
Live-Demo und GitHub-Repository

Abschließende Gedanken
Diese Demo hat mich viel mehr Zeit gekostet als erwartet – ein wenig Fehlinterpretation der Dokumentation meinerseits, das gebe ich zu.
Die Herausforderung bestand hauptsächlich darin, alle Dienste gut zu bündeln. Die größte Hürde war, dass die Funktionen beim Starten nach Netlify nicht richtig geladen wurden; sie führten bei jedem Aufruf zu Fehlern. Aus irgendeinem Grund waren meine Projekt-Node-Abhängigkeiten nicht zugänglich. Ich entschied mich, das Paket, das ich für meine Anfragen verwendete, zu verwerfen und stattdessen das altbewährte native https-Paket zu verwenden.
Außerdem war es etwas mühsam, ständig nach Netlify zu pushen, um meine Funktionen zu testen, aus Angst, dass sie sich nicht gleich verhalten würden wie lokal.
Nun, einige Anpassungen könnten vorgenommen werden, um diese Demo zu verbessern, aber insgesamt bin ich sehr zufrieden. Ziemlich dynamisch für statische Seiten, würden Sie nicht sagen? :)
Ich hoffe aufrichtig, dass dies Entwicklern hilft, mit den Backend-Funktionen von Netlify zu beginnen. Wenn Sie ähnliche JAMstack-Projekte erstellen, senden Sie sie uns bitte.
Wir würden uns freuen, Ihren Code zu sehen!