@library-pals/isbn 0.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.gitattributes +2 -0
- package/.github/workflows/npm-publish.yml +30 -0
- package/.github/workflows/test.yml +14 -0
- package/README.md +151 -0
- package/package.json +56 -0
- package/src/cli.js +41 -0
- package/src/index.js +93 -0
- package/src/provider-resolvers.js +41 -0
- package/src/providers/google.js +36 -0
- package/src/providers/isbndb.js +60 -0
- package/src/providers/open-library.js +72 -0
- package/src/providers/worldcat.js +63 -0
package/.gitattributes
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
name: Publish npm package
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
release:
|
|
5
|
+
types: [created]
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
build:
|
|
9
|
+
runs-on: ubuntu-latest
|
|
10
|
+
steps:
|
|
11
|
+
- uses: actions/checkout@v4
|
|
12
|
+
- uses: actions/setup-node@v4
|
|
13
|
+
with:
|
|
14
|
+
node-version: 20
|
|
15
|
+
- run: npm ci
|
|
16
|
+
- run: npm test
|
|
17
|
+
|
|
18
|
+
publish-npm:
|
|
19
|
+
needs: build
|
|
20
|
+
runs-on: ubuntu-latest
|
|
21
|
+
steps:
|
|
22
|
+
- uses: actions/checkout@v4
|
|
23
|
+
- uses: actions/setup-node@v4
|
|
24
|
+
with:
|
|
25
|
+
node-version: 20.x
|
|
26
|
+
registry-url: https://registry.npmjs.org/
|
|
27
|
+
- run: npm ci
|
|
28
|
+
- run: npm publish --access public
|
|
29
|
+
env:
|
|
30
|
+
NODE_AUTH_TOKEN: ${{secrets.npm_token}}
|
package/README.md
ADDED
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
# @library-pals/isbn
|
|
2
|
+
|
|
3
|
+
An npm module that given an ISBN will return the book's metadata using the
|
|
4
|
+
following providers:
|
|
5
|
+
|
|
6
|
+
- [Google Books API](https://developers.google.com/books/)
|
|
7
|
+
- [Open Library Books API](https://openlibrary.org/dev/docs/api/books)
|
|
8
|
+
- [WorldCat xISBN API](http://xisbn.worldcat.org/xisbnadmin/doc/api.htm)
|
|
9
|
+
- [ISBNdb API](https://isbndb.com/apidocs/v2) using API key in the environment
|
|
10
|
+
variable `ISBNDB_API_KEY`
|
|
11
|
+
|
|
12
|
+
## Acknowledgements
|
|
13
|
+
|
|
14
|
+
This repository is a fork of
|
|
15
|
+
[node-isbn by Guido García <@palmerabollo>](https://github.com/palmerabollo/node-isbn).
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm install @library-pals/isbn
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Supports Node.js versions 20.x and greater.
|
|
24
|
+
|
|
25
|
+
## Examples
|
|
26
|
+
|
|
27
|
+
```javascript
|
|
28
|
+
import isbn from "@library-pals/isbn";
|
|
29
|
+
|
|
30
|
+
try {
|
|
31
|
+
const book = await isbn.resolve("9780374104092");
|
|
32
|
+
console.log("Book found %j", book);
|
|
33
|
+
} catch (err) {
|
|
34
|
+
console.log("Book not found", err);
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### Setting a timeout
|
|
39
|
+
|
|
40
|
+
```javascript
|
|
41
|
+
import isbn from "@library-pals/isbn";
|
|
42
|
+
|
|
43
|
+
try {
|
|
44
|
+
const book = await isbn.resolve("9780374104092", { timeout: 15000 });
|
|
45
|
+
console.log("Book found %j", book);
|
|
46
|
+
} catch (err) {
|
|
47
|
+
console.log("Book not found", err);
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### Response
|
|
52
|
+
|
|
53
|
+
Response follows the same schema, but some fields could depend on the service
|
|
54
|
+
that was used to find the book. In general, Google Books API returns more
|
|
55
|
+
information.
|
|
56
|
+
|
|
57
|
+
```json
|
|
58
|
+
{
|
|
59
|
+
"title": "Annihilation",
|
|
60
|
+
"subtitle": "A Novel",
|
|
61
|
+
"authors": ["Jeff VanderMeer"],
|
|
62
|
+
"publisher": "Macmillan",
|
|
63
|
+
"publishedDate": "2014-02-04",
|
|
64
|
+
"description": "Describes the 12th expedition to “Area X,” a region cut off from the continent for decades, by a group of intrepid women scientists who try to ignore the high mortality rates of those on the previous 11 missions. Original. 75,000 first printing.",
|
|
65
|
+
"industryIdentifiers": [
|
|
66
|
+
{ "type": "ISBN_13", "identifier": "9780374104092" },
|
|
67
|
+
{ "type": "ISBN_10", "identifier": "0374104093" }
|
|
68
|
+
],
|
|
69
|
+
"readingModes": { "text": false, "image": false },
|
|
70
|
+
"pageCount": 209,
|
|
71
|
+
"printType": "BOOK",
|
|
72
|
+
"categories": ["Fiction"],
|
|
73
|
+
"averageRating": 5,
|
|
74
|
+
"ratingsCount": 1,
|
|
75
|
+
"maturityRating": "NOT_MATURE",
|
|
76
|
+
"allowAnonLogging": false,
|
|
77
|
+
"contentVersion": "0.5.1.0.preview.0",
|
|
78
|
+
"panelizationSummary": {
|
|
79
|
+
"containsEpubBubbles": false,
|
|
80
|
+
"containsImageBubbles": false
|
|
81
|
+
},
|
|
82
|
+
"imageLinks": {
|
|
83
|
+
"smallThumbnail": "http://books.google.com/books/content?id=2cl7AgAAQBAJ&printsec=frontcover&img=1&zoom=5&edge=curl&source=gbs_api",
|
|
84
|
+
"thumbnail": "http://books.google.com/books/content?id=2cl7AgAAQBAJ&printsec=frontcover&img=1&zoom=1&edge=curl&source=gbs_api"
|
|
85
|
+
},
|
|
86
|
+
"language": "en",
|
|
87
|
+
"previewLink": "http://books.google.com/books?id=2cl7AgAAQBAJ&printsec=frontcover&dq=isbn:9780374104092&hl=&cd=1&source=gbs_api",
|
|
88
|
+
"infoLink": "http://books.google.com/books?id=2cl7AgAAQBAJ&dq=isbn:9780374104092&hl=&source=gbs_api",
|
|
89
|
+
"canonicalVolumeLink": "https://books.google.com/books/about/Annihilation.html?hl=&id=2cl7AgAAQBAJ"
|
|
90
|
+
}
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### Setting backend providers
|
|
94
|
+
|
|
95
|
+
You can optionally specify the providers that you want to use, in the order you
|
|
96
|
+
need them to be invoked.
|
|
97
|
+
|
|
98
|
+
```javascript
|
|
99
|
+
import isbn from "@library-pals/isbn";
|
|
100
|
+
|
|
101
|
+
// This request will search first in the Open Library API and then in the Google Books API
|
|
102
|
+
isbn.provider(["openlibrary", "google"]);
|
|
103
|
+
|
|
104
|
+
try {
|
|
105
|
+
const book = await isbn.resolve("9780374104092");
|
|
106
|
+
console.log("Book isbn:" + input + " found %j", book);
|
|
107
|
+
} catch (err) {
|
|
108
|
+
console.log("Book isbn:" + input + " not found", err);
|
|
109
|
+
}
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
```javascript
|
|
113
|
+
import isbn from "@library-pals/isbn";
|
|
114
|
+
|
|
115
|
+
// This request will search ONLY in the Google Books API
|
|
116
|
+
isbn.provider( "google"]);
|
|
117
|
+
|
|
118
|
+
try {
|
|
119
|
+
const book = await isbn.resolve("9780374104092");
|
|
120
|
+
console.log("Book isbn:" + input + " found %j", book);
|
|
121
|
+
} catch (err) {
|
|
122
|
+
console.log("Book isbn:" + input + " not found", err);
|
|
123
|
+
}
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
If you do not like using strings to specify the providers, you could grab the
|
|
127
|
+
providers from `isbn.PROVIDER_NAMES` constant that the library provides!
|
|
128
|
+
|
|
129
|
+
```javascript
|
|
130
|
+
import isbn from "@library-pals/isbn";
|
|
131
|
+
|
|
132
|
+
// This request will search ONLY in the Google Books API
|
|
133
|
+
isbn.provider([isbn.PROVIDER_NAMES.GOOGLE]);
|
|
134
|
+
|
|
135
|
+
try {
|
|
136
|
+
const book = await isbn.resolve("9780374104092");
|
|
137
|
+
console.log("Book isbn:" + input + " found %j", book);
|
|
138
|
+
} catch (err) {
|
|
139
|
+
console.log("Book isbn:" + input + " not found", err);
|
|
140
|
+
}
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
## License
|
|
144
|
+
|
|
145
|
+
**AGPL v3.0 LICENSE** http://www.gnu.org/licenses/agpl-3.0.html
|
|
146
|
+
|
|
147
|
+
See also
|
|
148
|
+
[Google Books API Terms of Service](https://developers.google.com/books/terms),
|
|
149
|
+
[Open Library Licensing](https://openlibrary.org/developers/licensing),
|
|
150
|
+
[WorldCat xISBN Terms of Service](http://www.oclc.org/worldcat/community/terms.en.html),
|
|
151
|
+
[ISBNdb Terms and Conditions](https://isbndb.com/terms-and-conditions).
|
package/package.json
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@library-pals/isbn",
|
|
3
|
+
"version": "0.0.0",
|
|
4
|
+
"description": "Find books by ISBN",
|
|
5
|
+
"main": "src/index.js",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"engines": {
|
|
8
|
+
"node": ">=20.0.0"
|
|
9
|
+
},
|
|
10
|
+
"bin": {
|
|
11
|
+
"isbn": "./src/cli.js"
|
|
12
|
+
},
|
|
13
|
+
"scripts": {
|
|
14
|
+
"lint": "eslint .",
|
|
15
|
+
"pretest": "npm run lint",
|
|
16
|
+
"test": "mocha test/spec",
|
|
17
|
+
"testDebug": "mocha --inspect-brk test/spec"
|
|
18
|
+
},
|
|
19
|
+
"repository": {
|
|
20
|
+
"type": "git",
|
|
21
|
+
"url": "git+ssh://git@github.com/library-pals/isbn.git"
|
|
22
|
+
},
|
|
23
|
+
"keywords": [
|
|
24
|
+
"isbn",
|
|
25
|
+
"book",
|
|
26
|
+
"google",
|
|
27
|
+
"openlibrary",
|
|
28
|
+
"api",
|
|
29
|
+
"worldcat",
|
|
30
|
+
"isbndb"
|
|
31
|
+
],
|
|
32
|
+
"author": "Katy DeCorah <@katydecorah>",
|
|
33
|
+
"license": "AGPL-3.0-or-later",
|
|
34
|
+
"devDependencies": {
|
|
35
|
+
"@eslint/js": "^9.2.0",
|
|
36
|
+
"@types/nock": "^11.1.0",
|
|
37
|
+
"eslint": "^9.2.0",
|
|
38
|
+
"eslint-plugin-jsdoc": "^48.2.3",
|
|
39
|
+
"eslint-plugin-unicorn": "^52.0.0",
|
|
40
|
+
"globals": "^15.1.0",
|
|
41
|
+
"meow": "^13.2.0",
|
|
42
|
+
"mocha": "^10.4.0",
|
|
43
|
+
"nock": "^13.5.4"
|
|
44
|
+
},
|
|
45
|
+
"dependencies": {
|
|
46
|
+
"axios": "^1.6.8"
|
|
47
|
+
},
|
|
48
|
+
"bugs": {
|
|
49
|
+
"url": "https://github.com/palmerabollo/node-isbn/issues"
|
|
50
|
+
},
|
|
51
|
+
"homepage": "https://github.com/palmerabollo/node-isbn#readme",
|
|
52
|
+
"directories": {
|
|
53
|
+
"example": "examples",
|
|
54
|
+
"test": "test"
|
|
55
|
+
}
|
|
56
|
+
}
|
package/src/cli.js
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import meow from "meow";
|
|
3
|
+
import isbn from "./index.js";
|
|
4
|
+
|
|
5
|
+
const cli = meow(
|
|
6
|
+
`
|
|
7
|
+
Usage
|
|
8
|
+
$ isbn <input>
|
|
9
|
+
|
|
10
|
+
Options
|
|
11
|
+
--isbn, -i The ISBN for the book
|
|
12
|
+
|
|
13
|
+
Examples
|
|
14
|
+
$ isbn 9780374104092
|
|
15
|
+
|
|
16
|
+
This script will resolve the provided ISBN to a book. The ISBN must be a valid ISBN-10 or ISBN-13.
|
|
17
|
+
`,
|
|
18
|
+
{
|
|
19
|
+
importMeta: import.meta,
|
|
20
|
+
flags: {
|
|
21
|
+
isbn: {
|
|
22
|
+
type: "string",
|
|
23
|
+
shortFlag: "i",
|
|
24
|
+
isRequired: true,
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
}
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
if (!/^(\d{10}|\d{13})$/.test(cli.flags.isbn)) {
|
|
31
|
+
console.error("Invalid ISBN. Please provide a valid ISBN-10 or ISBN-13.");
|
|
32
|
+
process.exit(1);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
try {
|
|
36
|
+
const book = await isbn.resolve(cli.flags.isbn);
|
|
37
|
+
console.log(book);
|
|
38
|
+
} catch (error) {
|
|
39
|
+
console.error("An error occurred while trying to resolve the ISBN:", error);
|
|
40
|
+
process.exit(1);
|
|
41
|
+
}
|
package/src/index.js
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import {
|
|
2
|
+
PROVIDER_NAMES,
|
|
3
|
+
DEFAULT_PROVIDERS,
|
|
4
|
+
PROVIDER_RESOLVERS,
|
|
5
|
+
} from "./provider-resolvers.js";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Represents an ISBN (International Standard Book Number) utility class.
|
|
9
|
+
* Provides methods for configuring providers, retrieving book information, and resolving ISBNs.
|
|
10
|
+
*/
|
|
11
|
+
class Isbn {
|
|
12
|
+
constructor() {
|
|
13
|
+
this.PROVIDER_NAMES = PROVIDER_NAMES;
|
|
14
|
+
|
|
15
|
+
this._resetProviders();
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Resets the providers to the default set of providers.
|
|
20
|
+
*/
|
|
21
|
+
_resetProviders() {
|
|
22
|
+
this._providers = DEFAULT_PROVIDERS;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Sets the providers for the ISBN lookup.
|
|
27
|
+
* @param {string[]} providers - An array of provider names.
|
|
28
|
+
* @returns {object} - The current instance of the ISBN lookup.
|
|
29
|
+
* @throws {TypeError} - If `providers` is not an array.
|
|
30
|
+
* @throws {Error} - If any of the provided providers are not supported.
|
|
31
|
+
*/
|
|
32
|
+
provider(providers) {
|
|
33
|
+
if (!Array.isArray(providers)) {
|
|
34
|
+
throw new TypeError("`providers` must be an array.");
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if (providers.length === 0) {
|
|
38
|
+
return this;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const unsupportedProviders = providers.filter(
|
|
42
|
+
(p) => !DEFAULT_PROVIDERS.includes(p)
|
|
43
|
+
);
|
|
44
|
+
if (unsupportedProviders.length > 0) {
|
|
45
|
+
throw new Error(
|
|
46
|
+
`Unsupported providers: ${unsupportedProviders.join(", ")}`
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
this._providers = [...new Set(providers)];
|
|
51
|
+
return this;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Retrieves book information from a list of providers using the given ISBN.
|
|
56
|
+
* @param {Array<string>} providers - The list of providers to retrieve book information from.
|
|
57
|
+
* @param {string} isbn - The ISBN of the book.
|
|
58
|
+
* @param {object} options - Additional options for retrieving book information.
|
|
59
|
+
* @returns {Promise<object>} A promise that resolves to the book information.
|
|
60
|
+
* @throws {Error} If none of the providers are able to retrieve the book information.
|
|
61
|
+
*/
|
|
62
|
+
async _getBookInfo(providers, isbn, options) {
|
|
63
|
+
for (const provider of providers) {
|
|
64
|
+
try {
|
|
65
|
+
return await PROVIDER_RESOLVERS[provider](isbn, options);
|
|
66
|
+
} catch {
|
|
67
|
+
// console.debug(`Unable to reach ${provider}. Trying the next one...`);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
// If none of the providers worked, we throw an error.
|
|
71
|
+
throw new Error("All providers failed.");
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Resolves the book information for the given ISBN.
|
|
76
|
+
* @param {string} isbn - The ISBN of the book.
|
|
77
|
+
* @param {object} options - The options for the request.
|
|
78
|
+
* @returns {Promise<object>} - A Promise that resolves to the book information.
|
|
79
|
+
* @throws {Error} - If an error occurs while resolving the book information.
|
|
80
|
+
*/
|
|
81
|
+
async resolve(isbn, options = {}) {
|
|
82
|
+
try {
|
|
83
|
+
const book = await this._getBookInfo(this._providers, isbn, options);
|
|
84
|
+
this._resetProviders();
|
|
85
|
+
return book;
|
|
86
|
+
} catch (error) {
|
|
87
|
+
this._resetProviders();
|
|
88
|
+
throw error;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export default new Isbn();
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { resolveGoogle } from "./providers/google.js";
|
|
2
|
+
import { resolveOpenLibrary } from "./providers/open-library.js";
|
|
3
|
+
import { resolveWorldcat } from "./providers/worldcat.js";
|
|
4
|
+
import { resolveIsbnDb } from "./providers/isbndb.js";
|
|
5
|
+
|
|
6
|
+
export const defaultOptions = {
|
|
7
|
+
poll: {
|
|
8
|
+
maxSockets: 500,
|
|
9
|
+
},
|
|
10
|
+
timeout: 5000,
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export const GOOGLE_BOOKS_API_BASE = "https://www.googleapis.com";
|
|
14
|
+
export const GOOGLE_BOOKS_API_BOOK = "/books/v1/volumes";
|
|
15
|
+
|
|
16
|
+
export const OPENLIBRARY_API_BASE = "https://openlibrary.org";
|
|
17
|
+
export const OPENLIBRARY_API_BOOK = "/api/books";
|
|
18
|
+
|
|
19
|
+
export const WORLDCAT_API_BASE = "http://xisbn.worldcat.org";
|
|
20
|
+
export const WORLDCAT_API_BOOK = "/webservices/xid/isbn";
|
|
21
|
+
|
|
22
|
+
export const ISBNDB_API_BASE = "https://api2.isbndb.com";
|
|
23
|
+
export const ISBNDB_API_BOOK = "/book";
|
|
24
|
+
export const PROVIDER_NAMES = {
|
|
25
|
+
GOOGLE: "google",
|
|
26
|
+
OPENLIBRARY: "openlibrary",
|
|
27
|
+
WORLDCAT: "worldcat",
|
|
28
|
+
ISBNDB: "isbndb",
|
|
29
|
+
};
|
|
30
|
+
export const DEFAULT_PROVIDERS = [
|
|
31
|
+
PROVIDER_NAMES.GOOGLE,
|
|
32
|
+
PROVIDER_NAMES.OPENLIBRARY,
|
|
33
|
+
PROVIDER_NAMES.WORLDCAT,
|
|
34
|
+
PROVIDER_NAMES.ISBNDB,
|
|
35
|
+
];
|
|
36
|
+
export const PROVIDER_RESOLVERS = {
|
|
37
|
+
[PROVIDER_NAMES.GOOGLE]: resolveGoogle,
|
|
38
|
+
[PROVIDER_NAMES.OPENLIBRARY]: resolveOpenLibrary,
|
|
39
|
+
[PROVIDER_NAMES.WORLDCAT]: resolveWorldcat,
|
|
40
|
+
[PROVIDER_NAMES.ISBNDB]: resolveIsbnDb,
|
|
41
|
+
};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import axios from "axios";
|
|
2
|
+
import {
|
|
3
|
+
defaultOptions,
|
|
4
|
+
GOOGLE_BOOKS_API_BASE,
|
|
5
|
+
GOOGLE_BOOKS_API_BOOK,
|
|
6
|
+
} from "../provider-resolvers.js";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Resolves book information from Google Books API using the provided ISBN.
|
|
10
|
+
* @param {string} isbn - The ISBN of the book.
|
|
11
|
+
* @param {object} options - Additional options for the API request.
|
|
12
|
+
* @returns {Promise<object>} The book information retrieved from the API.
|
|
13
|
+
* @throws {Error} If the API response code is not 200, or if no books are found with the provided ISBN, or if no volume information is found for the book.
|
|
14
|
+
*/
|
|
15
|
+
export async function resolveGoogle(isbn, options) {
|
|
16
|
+
const requestOptions = {
|
|
17
|
+
...defaultOptions,
|
|
18
|
+
...options,
|
|
19
|
+
url: `${GOOGLE_BOOKS_API_BASE}${GOOGLE_BOOKS_API_BOOK}?q=isbn:${isbn}`,
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
const { status, data } = await axios.request(requestOptions);
|
|
23
|
+
if (status !== 200) {
|
|
24
|
+
throw new Error(`wrong response code: ${status}`);
|
|
25
|
+
}
|
|
26
|
+
const books = data;
|
|
27
|
+
if (!books.totalItems) {
|
|
28
|
+
throw new Error(`no books found with isbn: ${isbn}`);
|
|
29
|
+
}
|
|
30
|
+
// In very rare circumstances books.items[0] is undefined (see #2)
|
|
31
|
+
if (!books.items || books.items.length === 0) {
|
|
32
|
+
throw new Error(`no volume info found for book with isbn: ${isbn}`);
|
|
33
|
+
}
|
|
34
|
+
const book = books.items[0].volumeInfo;
|
|
35
|
+
return book;
|
|
36
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import axios from "axios";
|
|
2
|
+
import {
|
|
3
|
+
defaultOptions,
|
|
4
|
+
ISBNDB_API_BASE,
|
|
5
|
+
ISBNDB_API_BOOK,
|
|
6
|
+
} from "../provider-resolvers.js";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Resolves the ISBN using the ISBNdb API.
|
|
10
|
+
* @param {string} isbn - The ISBN to resolve.
|
|
11
|
+
* @param {object} options - Additional options for the request.
|
|
12
|
+
* @returns {Promise<object>} - A promise that resolves to the standardized book data.
|
|
13
|
+
* @throws {Error} - If the response code is not 200 or if no books are found with the given ISBN.
|
|
14
|
+
*/
|
|
15
|
+
export async function resolveIsbnDb(isbn, options) {
|
|
16
|
+
const requestOptions = {
|
|
17
|
+
...defaultOptions,
|
|
18
|
+
...options,
|
|
19
|
+
url: `${ISBNDB_API_BASE}${ISBNDB_API_BOOK}/${isbn}`,
|
|
20
|
+
headers: { Authorization: process.env.ISBNDB_API_KEY || "" },
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
const { status, data } = await axios.request(requestOptions);
|
|
24
|
+
if (status !== 200) {
|
|
25
|
+
throw new Error(
|
|
26
|
+
`Wrong response code: ${status}. Response data: ${JSON.stringify(data)}`
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
const books = data;
|
|
30
|
+
if (!books.book) {
|
|
31
|
+
throw new Error(`No books found with ISBN: ${isbn}`);
|
|
32
|
+
}
|
|
33
|
+
return standardize(books.book);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Standardizes a book object by transforming its properties into a consistent format.
|
|
38
|
+
* @param {object} book - The book object to be standardized.
|
|
39
|
+
* @returns {object} - The standardized book object.
|
|
40
|
+
*/
|
|
41
|
+
function standardize(book) {
|
|
42
|
+
return {
|
|
43
|
+
title: book.title_long,
|
|
44
|
+
publishedDate: book.date_published,
|
|
45
|
+
authors: book.authors,
|
|
46
|
+
description: book.overview,
|
|
47
|
+
industryIdentifiers: [book.isbn, book.isbn13, book.dewey_decimal].filter(
|
|
48
|
+
Boolean
|
|
49
|
+
),
|
|
50
|
+
pageCount: book.pages,
|
|
51
|
+
printType: "BOOK",
|
|
52
|
+
categories: book.subjects,
|
|
53
|
+
imageLinks: {
|
|
54
|
+
smallThumbnail: book.image,
|
|
55
|
+
thumbnail: book.image,
|
|
56
|
+
},
|
|
57
|
+
publisher: book.publisher,
|
|
58
|
+
language: book.language,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import axios from "axios";
|
|
2
|
+
import {
|
|
3
|
+
defaultOptions,
|
|
4
|
+
OPENLIBRARY_API_BASE,
|
|
5
|
+
OPENLIBRARY_API_BOOK,
|
|
6
|
+
} from "../provider-resolvers.js";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Resolves a book from the Open Library API using the provided ISBN.
|
|
10
|
+
* @param {string} isbn - The ISBN of the book.
|
|
11
|
+
* @param {object} options - Additional options for the request.
|
|
12
|
+
* @returns {Promise<object>} A promise that resolves to the standardized book object.
|
|
13
|
+
* @throws {Error} If the response code is not 200 or if no books are found with the provided ISBN.
|
|
14
|
+
*/
|
|
15
|
+
export async function resolveOpenLibrary(isbn, options) {
|
|
16
|
+
const requestOptions = {
|
|
17
|
+
...defaultOptions,
|
|
18
|
+
...options,
|
|
19
|
+
url: `${OPENLIBRARY_API_BASE}${OPENLIBRARY_API_BOOK}?bibkeys=ISBN:${isbn}&format=json&jscmd=details`,
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
const { status, data } = await axios.request(requestOptions);
|
|
23
|
+
if (status !== 200) {
|
|
24
|
+
throw new Error(
|
|
25
|
+
`Wrong response code: ${status}. Response data: ${JSON.stringify(data)}`
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
const books = data;
|
|
29
|
+
const book = books[`ISBN:${isbn}`];
|
|
30
|
+
if (!book) {
|
|
31
|
+
throw new Error(`No books found with ISBN: ${isbn}`);
|
|
32
|
+
}
|
|
33
|
+
return standardize(book);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const LANGUAGE_MAP = {
|
|
37
|
+
"/languages/eng": "en",
|
|
38
|
+
"/languages/spa": "es",
|
|
39
|
+
"/languages/fre": "fr",
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Standardizes a book object by extracting relevant information from the provided book object.
|
|
44
|
+
* @param {object} book - The book object to be standardized.
|
|
45
|
+
* @returns {object} - The standardized book object.
|
|
46
|
+
*/
|
|
47
|
+
function standardize(book) {
|
|
48
|
+
const standardBook = {
|
|
49
|
+
title: book.details.title,
|
|
50
|
+
publishedDate: book.details.publish_date,
|
|
51
|
+
authors: book.details.authors
|
|
52
|
+
? book.details.authors.map(({ name }) => name)
|
|
53
|
+
: [],
|
|
54
|
+
description: book.details.subtitle,
|
|
55
|
+
industryIdentifiers: [],
|
|
56
|
+
pageCount: book.details.number_of_pages,
|
|
57
|
+
printType: "BOOK",
|
|
58
|
+
categories: [],
|
|
59
|
+
imageLinks: {
|
|
60
|
+
smallThumbnail: book.thumbnail_url,
|
|
61
|
+
thumbnail: book.thumbnail_url,
|
|
62
|
+
},
|
|
63
|
+
previewLink: book.preview_url,
|
|
64
|
+
infoLink: book.info_url,
|
|
65
|
+
publisher: book.details.publishers ? book.details.publishers[0] : "",
|
|
66
|
+
language: book.details.languages
|
|
67
|
+
? LANGUAGE_MAP[book.details.languages[0].key] || "unknown"
|
|
68
|
+
: "unknown",
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
return standardBook;
|
|
72
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import axios from "axios";
|
|
2
|
+
import {
|
|
3
|
+
defaultOptions,
|
|
4
|
+
WORLDCAT_API_BASE,
|
|
5
|
+
WORLDCAT_API_BOOK,
|
|
6
|
+
} from "../provider-resolvers.js";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Resolves a book using the Worldcat API based on the provided ISBN.
|
|
10
|
+
* @param {string} isbn - The ISBN of the book to resolve.
|
|
11
|
+
* @param {object} options - Additional options for the request.
|
|
12
|
+
* @returns {Promise<object>} A promise that resolves to the standardized book object.
|
|
13
|
+
* @throws {Error} If the response code is not 200 or if no books are found with the provided ISBN.
|
|
14
|
+
*/
|
|
15
|
+
export async function resolveWorldcat(isbn, options) {
|
|
16
|
+
const requestOptions = {
|
|
17
|
+
...defaultOptions,
|
|
18
|
+
...options,
|
|
19
|
+
url: `${WORLDCAT_API_BASE}${WORLDCAT_API_BOOK}/${isbn}?method=getMetadata&fl=*&format=json`,
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
const { status, data } = await axios.request(requestOptions);
|
|
23
|
+
if (status !== 200) {
|
|
24
|
+
throw new Error(
|
|
25
|
+
`Wrong response code: ${status}. Response data: ${JSON.stringify(data)}`
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
const books = data;
|
|
29
|
+
if (books.stat !== "ok") {
|
|
30
|
+
throw new Error(`No books found with ISBN: ${isbn}`);
|
|
31
|
+
}
|
|
32
|
+
const [book] = books.list;
|
|
33
|
+
return standardize(book);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const LANGUAGE_MAP = {
|
|
37
|
+
eng: "en",
|
|
38
|
+
spa: "es",
|
|
39
|
+
fre: "fr",
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Standardizes a book object by extracting relevant information from the provided book object.
|
|
44
|
+
* @param {object} book - The book object to be standardized.
|
|
45
|
+
* @returns {object} - The standardized book object.
|
|
46
|
+
*/
|
|
47
|
+
function standardize(book) {
|
|
48
|
+
const standardBook = {
|
|
49
|
+
title: book.title,
|
|
50
|
+
publishedDate: book.year,
|
|
51
|
+
authors: book.author ? [book.author] : [],
|
|
52
|
+
description: null,
|
|
53
|
+
industryIdentifiers: [],
|
|
54
|
+
pageCount: null,
|
|
55
|
+
printType: "BOOK",
|
|
56
|
+
categories: [],
|
|
57
|
+
imageLinks: {},
|
|
58
|
+
publisher: book.publisher,
|
|
59
|
+
language: LANGUAGE_MAP[book.lang] || "unknown",
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
return standardBook;
|
|
63
|
+
}
|