在靠近用户的地方部署容器
本工程教育(EngEd)计划由科支持。
在全球范围内即时部署容器。Section是经济实惠、简单而强大的。
免费开始。
掌握API - 使用Node.js和EJS
2020年7月30日
- 主题。
- API
你是否一直想使用API(应用编程接口)中的数据,但却不知道如何使用?本教程将指导你如何使用Node.js和EJS模板来创建一个动态的网络应用程序,从而掌握你的第一个API。如果你以前从未使用过JSON或者对JavaScript知之甚少,也不用担心,本指南就是针对你的。
所以你已经创建了你的第一个NodeJS网络应用,但现在你想通过使用API来提高这些技能。使用你现有的EJS模板和Node.js知识,你将能够与Goodreads API合作,能够搜索、列出和返回有关书籍的详细信息。
**注意:**还没有部署一个基本的NodeJS网络应用程序吗?请看我的《将静态网站转换为动态NodeJS网络应用》教程,它将向你介绍全栈开发。
获取你的API密钥
为了能够使用API,我们首先需要获得一些密钥。除其他事项外,这允许API供应商监控你的使用情况,并确保你在他们的服务条款范围内。
**注意:**不幸的是,从2020年12月8日开始,Goodreads APIs已经被废弃,没有新的API密钥被发放,所以新的开发者不能使用它。然而,这篇文章仍然是有用的,因为无论你使用哪种API,其过程都是相似的,可以作为初学者使用API的深入指南。但是,如果你正在寻找一个可以在你的下一个项目中使用的有效API的指南,请注意《掌握API--使用Spotify API》。
首先,你需要有一个Goodreads账户。如果你还没有在Goodreads网站上注册的话。
其次,你需要注册你的应用程序以获得密钥。去goodreads.com/api/keys,填写应用程序的名称和公司名称(可以只是你的名字。)
不要担心任何可选字段。你唯一需要填写的是用于认证的回调URL,我们将在第二部分介绍。
点击更新应用程序信息按钮,提交详细信息。你现在应该看到一个密钥和秘密,这将是一长串随机的数字和字母。我们很快就会把这些加入我们的server.js文件,这样我们就可以访问Goodreads的API了。
安装goodreads-api-node
现在我们有了Goodreads API的API密钥和秘密,我们需要告诉我们的服务器如何访问Goodreads APIs。
最简单的方法是安装一个API包装器。我们将使用的是goodreads-api-node。API包装器是一个开发者编写的代码,使我们更容易使用API。
要安装goodreads-api-node,在终端输入npm install --save goodreads-api-node
,然后按回车。
在你的server.js文件中,在你其他需要的node模块下面添加const goodreads = require('goodreads-api-node');
。
现在我们需要使用下面的代码添加你的API密钥和密码。我们强烈建议将这些存储在其他地方,这样它们就不会被盗。一种方法是使用dotenv,我在这里做了这个。
(如果你愿意承担风险,只需用你从Goodreads网站上获得的密钥和密码替换process.env.GOODREADS_KEY
和process.env.GOODREADS_SECRET
)。
const myCredentials = {
key: 'process.env.GOODREADS_KEY',
secret: 'process.env.GOODREADS_SECRET'
};
const gr = goodreads(myCredentials);
如果你正确地添加了代码,你的server.js文件的开头(在你添加任何路由之前)应该看起来像。
// Node Modules
const express = require('express');
const ejs = require('ejs');
require('dotenv').config();
const goodreads = require('goodreads-api-node');
const app = express();
// Goodreads API - NodeJS
const myCredentials = {
key: process.env.GOODREADS_KEY,
secret: process.env.GOODREADS_SECRET
};
const gr = goodreads(myCredentials);
// Initialising Express
app.use(express.static('public'));
// set the view engine to ejs
app.set('view engine', 'ejs');
app.listen(8080);
console.log('Listening on 8080');
搜索一本书
我们要用Goodreads API创建的第一个功能是搜索书籍。在主页上,会有一个搜索栏,用户可以输入书名或作者,他们会看到搜索结果中的书籍封面。
显示一个表单
首先,我们需要添加一个表单,以便用户可以输入他们的查询。因此,在你的index.ejs
文件中添加。
<form action="/search" method="post">
<input type="text" name="book" value="" placeholder="Book Title or Author">
<input type="submit">
</form>
这将把表单发送到/搜索路径,并把输入的查询值附加到URL上。接下来,我们需要告诉服务器如何处理这个请求,这需要使用body-parser节点模块并创建一个搜索路由。
解析提交的表单URL
要安装body-parser,在终端输入npm install body-parser --save
,然后按回车键。在server.js中把const bodyParser = require('body-parser');
添加到你所需要的node模块中,并在初始化Express后添加以下代码。
app.use(bodyParser.urlencoded({
extended: true
}));
app.use(bodyParser.json());
更新的server.js示例
// Node Modules
const express = require('express');
const bodyParser = require('body-parser');
const ejs = require('ejs');
require('dotenv').config();
const goodreads = require('goodreads-api-node');
const app = express();
// Goodreads API - NodeJS
const myCredentials = {
key: process.env.GOODREADS_KEY,
secret: process.env.GOODREADS_SECRET
};
const gr = goodreads(myCredentials);
// Initialising Express
app.use(express.static('public'));
// set the view engine to ejs
app.set('view engine', 'ejs');
app.use(bodyParser.urlencoded({
extended: true
}));
app.use(bodyParser.json());
app.listen(8080);
console.log('Listening on 8080');
添加Goodreads API searchBooks()函数
为了创建搜索路线,添加以下内容。
// *** POST Routes ***
// Search Route
app.post('/search', function (req, res) {
var bookquery = req.body.book;
var booklist = gr.searchBooks({
q: bookquery,
page: 1,
field: 'title'
});
booklist.then(function (result) {
console.log(result);
}).catch(function () {
console.log("Goodreads Search Books Rejected");
});
});
该 **bookquery
**变量解析了图书表单字段的值,并将其插入一个 **searchBooks()
**函数,并使用Goodreads API。
**gr
**在调用goodreads-api-node模块的同时,也调用了你的API凭证。
然后 **q
**定义了要使用的查询(搜索词)。
为了加快查询速度,Goodreads API使用分页来分割结果,所以你可以选择你想返回的页面,使用 page
.
最后。 **field
**决定了要搜索的参数,在本例中是标题。
在searchBooks函数之后,有一个 **booklist.then
**函数,它是一个承诺。承诺是一种确保代码在一个函数完成后运行的方式。这一点很重要,因为否则,如果你要返回大量的数据,需要这些数据的代码可能会在数据被返回之前运行。承诺的catch部分是指如果承诺被拒绝(即失败)会发生什么。
在把它声明为一个函数后,括号里是变量。 result
.这存储了书单函数的输出,当然,如果你愿意,你可以重新命名这个变量。在这个例子中,我们把它用在console.log()
,这样我们就可以看到返回的数据是什么。
解析Goodreads API searchBooks数据
现在你已经添加了一个函数来返回图书搜索的结果,让我们来测试一下。
在你的网页浏览器中进入localhost:8080,输入一本书或作者的名字,如The Serpent's Shadow,然后点击提交查询。
等待大约五秒钟(取决于你的网络连接有多好),回到终端,你应该已经收到一个类似的响应。
{
Request: {
authentication: 'true',
key: '(Your API Key)',
method: 'search_index'
},
search: {
query: "The Serpent's Shadow",
'results-start': '1',
'results-end': '20',
'total-results': '33',
source: 'Goodreads',
'query-time-seconds': '0.07',
results: { work: [Array] }
}
}
这个响应告诉我们,我们以 "大蛇的影子 "为查询内容,成功地进行了搜索请求。显示的结果是1到20,但总共有33个。来源是Goodreads,服务器上的查询本身花了0.07秒。
然而,搜索结果(我们想要返回的那部分响应)被储存在更远的地方,所以我们将相应地调整我们的console.log()
。使用console.log()
,是了解JSON和你所选择的API在与你的前端代码连接之前如何工作的一个好方法。
我们可以从响应中看到,搜索结果被存储在search.results
。由于一次搜索最多可以返回20本书,这些信息被存储在一个名为work的数组中(这是Goodreads对一本书的分类)。
将你的console.log()
更新为console.log(result.search.results.work);
并再次测试。这应该会返回具体的书籍结果。下面是一个数组中的书籍数据的例子。
{
id: { _: '16416771', type: 'integer' },
books_count: { _: '92', type: 'integer' },
ratings_count: { _: '117390', type: 'integer' },
text_reviews_count: { _: '5244', type: 'integer' },
original_publication_year: { _: '2012', type: 'integer' },
original_publication_month: { _: '5', type: 'integer' },
original_publication_day: { _: '1', type: 'integer' },
average_rating: '4.29',
best_book: {
type: 'Book',
id: [Object],
title: "The Serpent's Shadow (The Kane Chronicles, #3)",
author: [Object],
image_url: 'https://i.gr-assets.com/images/S/compressed.photo.goodreads.com/books/1366227982l/12893742._SX98_.jpg',
small_image_url: 'https://i.gr-assets.com/images/S/compressed.photo.goodreads.com/books/1366227982l/12893742._SY75_.jpg'
}
},
在前端显示图书信息
现在我们可以从图书搜索中返回一个数组的结果,我们想显示这些信息(如书名),以便用户可以看到。我们可以通过EJS模板化来实现这个目的。
首先,你需要为result.search.results.work
添加一个变量,然后渲染一个新的页面,包括你刚刚创建的这个变量。更新后的搜索路线应该是这样的。
// Search Route
app.post('/search', function (req, res) {
var bookquery = req.body.book;
var booklist = gr.searchBooks({
q: bookquery,
page: 1,
field: 'title'
});
booklist.then(function (result) {
var bookresult = result.search.results.work;
console.log(bookresult);
res.render('pages/search-results', {
bookresult: bookresult
});
}).catch(function () {
console.log("Goodreads Search Books Rejected");
});
});
第二,在你的views/pages
文件夹中创建一个名为search-results.ejs
的新EJS文件,并像往常一样包括你的参数(如head、header和footer)。
然后在主标签之间,添加以下HTML。
<% bookresult.forEach(function(book) { %>
<h2><%= book.best_book.title %></h2>
<% }); %>
这将采取bookresult数组中的每一本书(也就是我们的搜索结果),并渲染一个包含其标题的h2
标签。
创建动态图书页面
到目前为止,我们已经创建了一个带有表单的搜索页面,可以使用Goodreads API来搜索书籍,还创建了一个结果页面,在结果的第一页显示每一个书名,但用户如何找到更多关于这些书籍的信息呢?最后,我们的最后一项任务是动态地创建新的图书页面,并将其与结果链接。
首先,我们需要创建一个新的路由来处理这些书页,并使用gr.showBook()
函数来抓取一本书的详细信息。
// Single Book Route
app.get('/book', function (req, res) {
var bookid = gr.showBook(req.query.id);
bookid.then(function (result) {
var bookdetails = result.book;
console.log(bookdetails);
res.render('pages/book', {
bookdetails: bookdetails
});
}).catch(function () {
console.log("Book Search Rejected");
});
});
只有一个问题。我们如何将书的ID附加到URL上,以便API知道当用户点击书名时应该获取哪本书的信息?答案是一点客户端的JavaScript和HTML。
在search-results.ejs中,在h2标签周围加上一个a
标签,像这样。
<% bookresult.forEach(function(book) { %>
<a id="<%= book.best_book.id._ %>" href="/book">
<img class="book-result" src="<%= book.best_book.image_url %>">
<% }); %>
</a>
这将把每个书名链接到我们刚刚创建的/book路由,并把它的Goodreads图书id(gr.showBook
功能所需)作为id属性加入。
现在,如果你还没有,在你的public/js文件夹中创建一个script.js
文件,并在head.ejs部分文件中添加一个脚本标签。在你的script.js
文件中添加以下内容。
// Append slash with book id, only if a book ID is not found in the link yet
const booklinks = document.querySelectorAll('a[href*="/book"]');
booklinks.forEach(function (el) {
if (!el.href.includes('id=')) {
el.href = el.href.replace(/\?.*$/, '') + '?id=' + el.getAttribute('id');
}
});
这将获取每一个带有<a href="/book">
标签的链接(即结果页上的每一个书名),并添加?id=
和标签的id(在本例中是书的id),这将使我们的gr.showBook()
函数能够抓取我们想要的书的id。
最后,我们只需要创建一个book.ejs
,以确定书页的内容。在主标签之间,添加以下内容。
<h3><%= bookdetails.title %></h3>
<img src="<%= bookdetails.image_url %>">
<h3><%= bookdetails.publication_year %></h3>
<p><%= bookdetails.description %></p>
这将显示书名、出版年份和书籍描述。
恭喜你,你刚刚使用Node.js和EJS模板处理了你的第一个API。为什么不试试呢?搜索一本书并点击任何一个标题。一个新的页面将加载你从Goodreads API中点击的结果的详细信息。
想把它部署到网络上吗?请看我的使用DigitalOcean部署Node.js网络应用的指南。
接下来的步骤。
如果你想扩大规模,为什么不考虑改变图书的URL以包括标题,如/book/booktitle。想通过用户的Goodreads账户访问其拥有的书籍,请查看第二部分,它将教你如何通过Goodreads API进行认证。
想了解更多的示例代码?请看LibraryTrackr,这是我正在开发的一个NodeJS网络应用,旨在为图书爱好者解决图书馆管理问题(包括印刷品和电子书)。
[
边缘主机
Section的Node.js边缘主机使DevOps团队能够在网络边缘运行关键的Node.js应用程序,在企业级的AppSec保护下获得超快的结果。
了解更多信息并开始使用免费计划
](www.section.io/modules/nod…)
类似文章
[
语言、API
在Jetpack Compose中创建一个嵌套的滚动音乐播放器应用程序
阅读更多
架构
在React-Django应用中整合Razorpay
阅读更多
架构
实现Spring查询语言Spring Boot搜索
阅读更多