Tworzenie interfejsu API Node.js Express do konwersji Markdown do HTML
Opublikowany: 2022-03-10Markdown to lekki język znaczników tekstu, który umożliwia konwersję zaznaczonego tekstu do różnych formatów. Pierwotnym celem stworzenia Markdown było umożliwienie ludziom „pisania przy użyciu łatwego do odczytania i łatwego do zapisania formatu zwykłego tekstu” i opcjonalnie przekonwertowanie go na strukturalnie poprawny XHTML (lub HTML). Obecnie, gdy WordPress obsługuje Markdown, format ten stał się jeszcze szerzej stosowany.
Celem napisania artykułu jest pokazanie, jak używać Node.js i frameworka Express do tworzenia punktu końcowego API. Kontekst, w którym będziemy się tego uczyć, polega na zbudowaniu aplikacji, która konwertuje składnię Markdown na HTML. Dodamy również mechanizm uwierzytelniania do API, aby zapobiec niewłaściwemu użyciu naszej aplikacji.
Aplikacja Markdown Node.js
Nasza maleńka aplikacja, którą nazwiemy „Konwerter Markdown”, umożliwi nam publikowanie tekstu w stylu Markdown i pobieranie wersji HTML. Aplikacja zostanie utworzona przy użyciu frameworka Node.js Express i będzie obsługiwać uwierzytelnianie dla żądań konwersji.
Zbudujemy aplikację w małych etapach — najpierw tworząc szkielet za pomocą Express, a następnie dodając różne funkcje, takie jak uwierzytelnianie, w miarę postępów. Zacznijmy więc od wstępnego etapu budowy aplikacji, tworząc rusztowanie.
Etap 1: Instalacja Express
Zakładając, że już zainstalowałeś Node.js w swoim systemie, utwórz katalog do przechowywania aplikacji (nazwijmy go „ markdown-api
”) i przejdź do tego katalogu:
$ mkdir markdown-api $ cd markdown-api
Użyj polecenia npm init, aby utworzyć plik package.json dla swojej aplikacji. To polecenie monituje o wiele rzeczy, takich jak nazwa i wersja aplikacji.
Na razie po prostu naciśnij Enter , aby zaakceptować ustawienia domyślne dla większości z nich. Użyłem domyślnego pliku punktu wejścia jako index.js , ale możesz wypróbować app.js lub inny w zależności od twoich preferencji.
Teraz zainstaluj Express w katalogu markdown-api
i zapisz go na liście zależności:
$ npm install express --save
Utwórz plik index.js w bieżącym katalogu ( markdown-api
) i dodaj następujący kod, aby sprawdzić, czy framework Express jest poprawnie zainstalowany:
Const express = require('express'); var app = express(); app.get('/', function(req, res){ res.send('Hello World!'); }); app.listen(3000);
Teraz przejdź do adresu URL https://localhost:3000
, aby sprawdzić, czy plik testowy działa poprawnie. Jeśli wszystko będzie w porządku, zobaczymy Hello World! powitanie w przeglądarce i możemy przystąpić do budowy bazowego API do konwersji Markdown do HTML.
Etap 2: Budowanie podstawowego API
Głównym celem naszego API będzie konwersja tekstu w składni Markdown na HTML. Interfejs API będzie miał dwa punkty końcowe:
-
/login
-
/convert
Punkt końcowy login
umożliwi aplikacji uwierzytelnianie prawidłowych żądań, podczas gdy punkt końcowy convert
przekonwertuje (oczywiście) Markdown na HTML.
Poniżej znajduje się podstawowy kod API do wywołania dwóch punktów końcowych. Wywołanie login
po prostu zwraca ciąg „Uwierzytelniony”, podczas gdy wywołanie convert
zwraca całą zawartość Markdown przesłaną do aplikacji. Metoda domowa po prostu zwraca komunikat „Hello World!” strunowy.
const express = require("express"); const bodyParser = require('body-parser'); var app = express(); app.use(bodyParser.urlencoded({ extended: true })); app.use(bodyParser.json()); app.get('/', function(req, res){ res.send('Hello World!'); }); app.post('/login', function(req, res) { res.send("Authenticated"); }, ); app.post("/convert", function(req, res, next) { console.log(req.body); if(typeof req.body.content == 'undefined' || req.body.content == null) { res.json(["error", "No data found"]); } else { res.json(["markdown", req.body.content]); } }); app.listen(3000, function() { console.log("Server running on port 3000"); });
Używamy oprogramowania pośredniczącego body-parser
, aby ułatwić analizowanie żądań przychodzących do aplikacji. Oprogramowanie pośredniczące udostępni wszystkie przychodzące żądania we właściwości req.body
. Możesz obejść się bez dodatkowego oprogramowania pośredniczącego, ale dodanie go znacznie ułatwia analizowanie różnych parametrów przychodzących żądań.
Możesz zainstalować body-parser
za pomocą npm:
$ npm install body-parser
Teraz, gdy mamy już nasze atrapy funkcji pośredniczących, użyjemy Postmana do przetestowania tego samego. Zacznijmy najpierw od krótkiego omówienia Postmana.
Listonosz Przegląd
Postman to narzędzie programistyczne API, które ułatwia budowanie, modyfikowanie i testowanie punktów końcowych API z poziomu przeglądarki lub poprzez pobranie aplikacji komputerowej (wersja przeglądarki jest teraz przestarzała). Posiada możliwość wykonywania różnych typów żądań HTTP tj. GET, POST, PUT, PATCH. Jest dostępny dla systemów Windows, macOS i Linux.
Oto przedsmak interfejsu Postmana:
Aby wysłać zapytanie do punktu końcowego interfejsu API, musisz wykonać następujące kroki:
- Wprowadź adres URL, który chcesz zapytać w pasku adresu w górnej sekcji;
- Wybierz metodę HTTP po lewej stronie paska adresu URL, aby wysłać żądanie;
- Kliknij przycisk „Wyślij”.
Listonosz wyśle wówczas żądanie do aplikacji, pobierze wszelkie odpowiedzi i wyświetli je w dolnym oknie. To jest podstawowy mechanizm korzystania z narzędzia Listonosz. W naszej aplikacji będziemy musieli również dodać do żądania inne parametry, które zostaną opisane w kolejnych sekcjach.
Korzystanie z listonosza
Teraz, gdy widzieliśmy już omówienie Postmana, przejdźmy dalej do używania go w naszej aplikacji.
Uruchom aplikację markdown-api
z wiersza polecenia:
$ node index.js
Aby przetestować podstawowy kod API, wykonujemy wywołania API do aplikacji z Postmana. Zauważ, że używamy metody POST do przekazania tekstu do konwersji do aplikacji.
Obecnie aplikacja akceptuje zawartość Markdown do konwersji za pomocą parametru content
POST. To przekazujemy jako format zakodowany URL. Aplikacja obecnie zwraca dosłownie ciąg znaków w formacie JSON — przy czym pierwsze pole zawsze zwraca markdown
ciągu, a drugie pole zwraca przekonwertowany tekst. Później, gdy dodamy kod przetwarzania Markdown, zwróci on przekonwertowany tekst.
Etap 3: Dodanie konwertera Markdown
Po zbudowaniu szkieletu aplikacji możemy zajrzeć do biblioteki JavaScript Showdown
, której użyjemy do przekonwertowania Markdown na HTML. Showdown to dwukierunkowy konwerter Markdown na HTML napisany w JavaScript, który umożliwia konwersję Markdown do HTML iz powrotem.
Zainstaluj pakiet za pomocą npm:
$ npm install showdown
Po dodaniu wymaganego kodu showdown do rusztowania otrzymujemy następujący wynik:
const express = require("express"); const bodyParser = require('body-parser'); const showdown = require('showdown'); var app = express(); app.use(bodyParser.urlencoded({ extended: true })); app.use(bodyParser.json()); converter = new showdown.Converter(); app.get('/', function(req, res){ res.send('Hello World!'); }); app.post('/login', function(req, res) { res.send("Authenticated"); }, ); app.post("/convert", function(req, res, next) { if(typeof req.body.content == 'undefined' || req.body.content == null) { res.json(["error", "No data found"]); } else { text = req.body.content; html = converter.makeHtml(text); res.json(["markdown", html]); } }); app.listen(3000, function() { console.log("Server running on port 3000"); });
Główny kod konwertera znajduje się w punkcie końcowym /convert
, jak wyodrębniono i pokazano poniżej. Spowoduje to przekonwertowanie dowolnego opublikowanego tekstu Markdown na wersję HTML i zwrócenie go jako dokumentu JSON.
... } else { text = req.body.content; html = converter.makeHtml(text); res.json(["markdown", html]); }
Metodą dokonującą konwersji jest converter.makeHtml(text)
. Możemy ustawić różne opcje konwersji Markdown za pomocą metody setOption
w następującym formacie:
converter.setOption('optionKey', 'value');
Na przykład możemy ustawić opcję automatycznego wstawiania i linkowania określonego adresu URL bez żadnych znaczników.
converter.setOption('simplifiedAutoLink', 'true');
Podobnie jak w przykładzie Postman, jeśli przekażemy prosty ciąg (taki jak Google home https://www.google.com/
) do aplikacji, zwróci ona następujący ciąg, jeśli jest włączony simplifiedAutoLink
:
<p>Google home <a href="https://www.google.com/">https://www.google.com/</a></p>
Bez tej opcji będziemy musieli dodać informacje o znacznikach, aby osiągnąć te same wyniki:
Google home <https://www.google.com/>
Istnieje wiele opcji modyfikacji sposobu przetwarzania Markdown. Pełną listę można znaleźć na stronie Showdown.
Więc teraz mamy działający konwerter Markdown-to-HTML z jednym punktem końcowym. Idźmy dalej i dodajmy uwierzytelnianie, aby mieć aplikację.
Etap 4: Dodawanie uwierzytelniania API za pomocą paszportu
Wystawienie interfejsu API aplikacji na zewnątrz bez odpowiedniego uwierzytelnienia zachęci użytkowników do wysyłania zapytań do punktu końcowego interfejsu API bez ograniczeń. Zaprosi to pozbawione skrupułów elementy do nadużywania Twojego interfejsu API, a także obciąży Twój serwer niemoderowanymi żądaniami. Aby to złagodzić, musimy dodać odpowiedni mechanizm uwierzytelniania.
Będziemy używać pakietu Passport, aby dodać uwierzytelnianie do naszej aplikacji. Podobnie jak oprogramowanie pośredniczące body-parser
, które napotkaliśmy wcześniej, Passport jest oprogramowaniem pośredniczącym do uwierzytelniania dla Node.js. Powodem, dla którego będziemy używać Passport jest to, że ma on różne mechanizmy uwierzytelniania do pracy (nazwa użytkownika i hasło, Facebook, Twitter itd.), co daje użytkownikowi elastyczność w wyborze konkretnego mechanizmu. Oprogramowanie pośredniczące Passport można łatwo wrzucić do dowolnej aplikacji Express bez konieczności zmiany kodu.
Zainstaluj pakiet za pomocą npm.
$ npm install passport
Będziemy również używać local
strategii, która zostanie wyjaśniona później, do uwierzytelniania. Więc go też zainstaluj.
$ npm install passport-local
Będziesz także musiał dodać moduł kodowania i dekodowania JWT (JSON Web Token) dla Node.js, który jest używany przez Passport:
$ npm install jwt-simple
Strategie w paszporcie
Passport wykorzystuje koncepcję strategii do uwierzytelniania żądań. Strategie to różne metody, które umożliwiają uwierzytelnianie żądań i mogą obejmować proste przypadki, takie jak weryfikacja poświadczeń nazwy użytkownika i hasła, uwierzytelnianie za pomocą OAuth (Facebook lub Twitter) lub korzystanie z OpenID. Przed uwierzytelnieniem żądań należy skonfigurować strategię używaną przez aplikację.
W naszej aplikacji użyjemy prostego schematu uwierzytelniania nazwy użytkownika i hasła, ponieważ jest łatwy do zrozumienia i kodowania. Obecnie Passport obsługuje ponad 300 strategii, które można znaleźć tutaj.
Chociaż projekt Passport może wydawać się skomplikowany, implementacja w kodzie jest bardzo prosta. Oto przykład, który pokazuje, jak nasz punkt końcowy /convert
jest dekorowany do uwierzytelniania. Jak zobaczysz, dodanie uwierzytelniania do metody jest dość proste.
app.post("/convert", passport.authenticate('local',{ session: false, failWithError: true }), function(req, res, next) { // If this function gets called, authentication was successful. // Also check if no content is sent if(typeof req.body.content == 'undefined' || req.body.content == null) { res.json(["error", "No data found"]); } else { text = req.body.content; html = converter.makeHtml(text); res.json(["markdown", html]); }}, // Return a 'Unauthorized' message back if authentication failed. function(err, req, res, next) { return res.status(401).send({ success: false, message: err }) });
Teraz wraz z ciągiem znaków Markdown do przekonwertowania musimy również wysłać nazwę użytkownika i hasło. Zostanie to sprawdzone za pomocą nazwy użytkownika i hasła aplikacji i zweryfikowane. Ponieważ używamy lokalnej strategii uwierzytelniania, poświadczenia są przechowywane w samym kodzie.
Chociaż może to brzmieć jak koszmar bezpieczeństwa, w przypadku aplikacji demonstracyjnych jest to wystarczające. Ułatwia to również zrozumienie procesu uwierzytelniania w naszym przykładzie. Nawiasem mówiąc, powszechnie stosowaną metodą zabezpieczeń jest przechowywanie poświadczeń w zmiennych środowiskowych. Mimo to wiele osób może nie zgadzać się z tą metodą, ale uważam, że jest to stosunkowo bezpieczne.
Pełny przykład z uwierzytelnianiem pokazano poniżej.
const express = require("express"); const showdown = require('showdown'); const bodyParser = require('body-parser'); const passport = require('passport'); const jwt = require('jwt-simple'); const LocalStrategy = require('passport-local').Strategy; var app = express(); app.use(bodyParser.urlencoded({ extended: true })); app.use(bodyParser.json()); converter = new showdown.Converter(); const ADMIN = 'admin'; const ADMIN_PASSWORD = 'smagazine'; const SECRET = 'secret#4456'; passport.use(new LocalStrategy(function(username, password, done) { if (username === ADMIN && password === ADMIN_PASSWORD) { done(null, jwt.encode({ username }, SECRET)); return; } done(null, false); })); app.get('/', function(req, res){ res.send('Hello World!'); }); app.post('/login', passport.authenticate('local',{ session: false }), function(req, res) { // If this function gets called, authentication was successful. // Send a 'Authenticated' string back. res.send("Authenticated"); }); app.post("/convert", passport.authenticate('local',{ session: false, failWithError: true }), function(req, res, next) { // If this function gets called, authentication was successful. // Also check if no content is sent if(typeof req.body.content == 'undefined' || req.body.content == null) { res.json(["error", "No data found"]); } else { text = req.body.content; html = converter.makeHtml(text); res.json(["markdown", html]); }}, // Return a 'Unauthorized' message back if authentication failed. function(err, req, res, next) { return res.status(401).send({ success: false, message: err }) }); app.listen(3000, function() { console.log("Server running on port 3000"); });
Sesja Postman, która pokazuje konwersję z dodanym uwierzytelnianiem, jest pokazana poniżej.
Tutaj widzimy, że otrzymaliśmy prawidłowy ciąg przekonwertowany na HTML ze składni Markdown. Chociaż poprosiliśmy o przekonwertowanie tylko jednego wiersza Markdown, interfejs API może przekonwertować większą ilość tekstu.
To kończy naszą krótką przygodę z tworzeniem punktu końcowego API przy użyciu Node.js i Express. Budowanie API to złożony temat i istnieją drobniejsze niuanse, o których powinieneś wiedzieć podczas tworzenia jednego, na co niestety nie mamy tutaj czasu, ale być może omówimy to w przyszłych artykułach.
Dostęp do naszego API z innej aplikacji
Teraz, gdy zbudowaliśmy API, możemy stworzyć mały skrypt Node.js, który pokaże Ci, w jaki sposób można uzyskać dostęp do API. W naszym przykładzie będziemy musieli zainstalować pakiet request
npm, który zapewnia prosty sposób wykonywania żądań HTTP. (Najprawdopodobniej masz już to zainstalowane.)
$ npm install request --save
Przykładowy kod do wysłania żądania do naszego API i uzyskania odpowiedzi znajduje się poniżej. Jak widać, pakiet request
znacznie upraszcza sprawę. Przecena do przekonwertowania znajduje się w zmiennej textToConvert
.
Przed uruchomieniem poniższego skryptu upewnij się, że aplikacja API, którą stworzyliśmy wcześniej, już działa. Uruchom następujący skrypt w innym oknie poleceń.
Uwaga : używamy znaku (back-tick)
, aby objąć wiele wierszy JavaScript dla zmiennej textToConvert
. To nie jest pojedynczy cytat.
var Request = require("request"); // Start of markdown var textToConvert = `Heading ======= ## Sub-heading Paragraphs are separated by a blank line. Two spaces at the end of a line produces a line break. Text attributes _italic_, **bold**, 'monospace'. A [link](https://example.com). Horizontal rule:`; // End of markdown Request.post({ "headers": { "content-type": "application/json" }, "url": "https://localhost:3000/convert", "body": JSON.stringify({ "content": textToConvert, "username": "admin", "password": "smagazine" }) }, function(error, response, body){ // If we got any connection error, bail out. if(error) { return console.log(error); } // Else display the converted text console.dir(JSON.parse(body)); });
Gdy wysyłamy żądanie POST do naszego interfejsu API, dostarczamy tekst Markdown do przekonwertowania wraz z danymi uwierzytelniającymi. Jeśli podamy nieprawidłowe dane uwierzytelniające, zostaniemy powitani komunikatem o błędzie.
{ success: false, message: { name: 'AuthenticationError', message: 'Unauthorized', status: 401 } }
W przypadku poprawnie autoryzowanego żądania powyższa przykładowa przecena zostanie przekonwertowana na następującą:
[ 'markdown', `<h1>Heading</h1> <h2>Sub-heading</h2> <p>Paragraphs are separated by a blank line.</p> <p>Two spaces at the end of a line<br /> produces a line break.</p> <p>Text attributes <em>italic</em>, <strong>bold</strong>, 'monospace'. A <a href="https://example.com">link</a>. Horizontal rule:</p>` ]
Chociaż zakodowaliśmy tutaj Markdown na sztywno, tekst może pochodzić z różnych innych źródeł — plików, formularzy internetowych i tak dalej. Proces żądania pozostaje taki sam.
Zauważ, że ponieważ wysyłamy żądanie jako typ zawartości application/json
; musimy zakodować ciało za pomocą json, stąd wywołanie funkcji JSON.stringify
. Jak widać, do przetestowania lub aplikacji API potrzeba bardzo małego przykładu.
Wniosek
W tym artykule rozpoczęliśmy samouczek, którego celem jest nauczenie się, jak używać Node, js i frameworka Express do budowania punktu końcowego API. Zamiast tworzyć fikcyjną aplikację bez celu, zdecydowaliśmy się stworzyć interfejs API, który konwertuje składnię Markdown na HTML, który zakotwicza lub uczy się w przydatnym kontekście. Po drodze dodaliśmy uwierzytelnianie do naszego punktu końcowego API, a także zobaczyliśmy sposoby testowania punktu końcowego naszej aplikacji za pomocą Postmana.