掌握API - 使用Node.js和EJS

245 阅读11分钟

在靠近用户的地方部署容器

本工程教育(EngEd)计划由科支持。

在全球范围内即时部署容器。Section是经济实惠、简单而强大的。

免费开始

掌握API - 使用Node.js和EJS

2020年7月30日
  • 主题。
  • API

你是否一直想使用API(应用编程接口)中的数据,但却不知道如何使用?本教程将指导你如何使用Node.jsEJS模板来创建一个动态的网络应用程序,从而掌握你的第一个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_KEYprocess.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…)

类似文章

[

Nested Scroll Music Player App in Jetpack Compose

语言、API

在Jetpack Compose中创建一个嵌套的滚动音乐播放器应用程序

阅读更多

](www.section.io/engineering…

Razorpay React-Django Application example Image

架构

在React-Django应用中整合Razorpay

阅读更多

](www.section.io/engineering…

Implementing a Spring Query Language

架构

实现Spring查询语言Spring Boot搜索

阅读更多

](www.section.io/engineering…)