comic-vine-sdk 1.3.0 → 1.3.1
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/CHANGELOG.md +1 -5
- package/CONTRIBUTING.md +294 -0
- package/README.md +434 -12
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -2,11 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
### Features
|
|
8
|
-
|
|
9
|
-
- complete migration from projen to standard npm project ([4c3ef8d](https://github.com/AllyMurray/comic-vine/commit/4c3ef8dbac71f10b17c6154421eaa750f1fa4ebf))
|
|
5
|
+
### [1.3.1](https://github.com/AllyMurray/comic-vine/compare/v1.3.0...v1.3.1) (2025-07-03)
|
|
10
6
|
|
|
11
7
|
## [1.2.8] - 2024-01-01
|
|
12
8
|
|
package/CONTRIBUTING.md
ADDED
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
# Contributing to Comic Vine SDK
|
|
2
|
+
|
|
3
|
+
Thank you for your interest in contributing to the Comic Vine SDK! This document provides guidelines and information to help you contribute effectively to the project.
|
|
4
|
+
|
|
5
|
+
## Table of Contents
|
|
6
|
+
|
|
7
|
+
- [Code of Conduct](#code-of-conduct)
|
|
8
|
+
- [Getting Started](#getting-started)
|
|
9
|
+
- [Development Setup](#development-setup)
|
|
10
|
+
- [Development Workflow](#development-workflow)
|
|
11
|
+
- [Code Standards](#code-standards)
|
|
12
|
+
- [Testing](#testing)
|
|
13
|
+
- [Submitting Changes](#submitting-changes)
|
|
14
|
+
- [Project Structure](#project-structure)
|
|
15
|
+
- [Resources](#resources)
|
|
16
|
+
|
|
17
|
+
## Code of Conduct
|
|
18
|
+
|
|
19
|
+
This project adheres to a [Code of Conduct](./CODE_OF_CONDUCT.md). By participating, you are expected to uphold this code. Please report unacceptable behavior to [allymurray88@gmail.com](mailto:allymurray88@gmail.com).
|
|
20
|
+
|
|
21
|
+
## Getting Started
|
|
22
|
+
|
|
23
|
+
### Prerequisites
|
|
24
|
+
|
|
25
|
+
Before you begin, ensure you have the following installed:
|
|
26
|
+
|
|
27
|
+
- **Node.js**: Version 20.0.0 or higher
|
|
28
|
+
- **pnpm**: Version 9.15.4+ (specified in package.json)
|
|
29
|
+
```bash
|
|
30
|
+
npm install -g pnpm@9.15.4
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### Development Setup
|
|
34
|
+
|
|
35
|
+
1. **Fork and Clone**
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
git clone https://github.com/your-username/comic-vine.git
|
|
39
|
+
cd comic-vine
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
2. **Install Dependencies**
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
pnpm install
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
3. **Verify Setup**
|
|
49
|
+
```bash
|
|
50
|
+
pnpm test
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
If all tests pass, you're ready to start developing!
|
|
54
|
+
|
|
55
|
+
## Development Workflow
|
|
56
|
+
|
|
57
|
+
### Creating a Branch
|
|
58
|
+
|
|
59
|
+
1. Create a feature branch from `main`:
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
git checkout -b feature/your-feature-name
|
|
63
|
+
# or
|
|
64
|
+
git checkout -b fix/issue-description
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
2. Use descriptive branch names:
|
|
68
|
+
- `feature/add-search-pagination`
|
|
69
|
+
- `fix/handle-rate-limiting`
|
|
70
|
+
- `docs/update-readme-examples`
|
|
71
|
+
|
|
72
|
+
### Making Changes
|
|
73
|
+
|
|
74
|
+
1. **Write Code**: Follow the [Code Standards](#code-standards) below
|
|
75
|
+
2. **Add Tests**: Ensure new functionality has corresponding tests
|
|
76
|
+
3. **Run Tests**: `pnpm test` to run tests and linting
|
|
77
|
+
4. **Build**: `pnpm compile` to ensure your changes compile correctly
|
|
78
|
+
|
|
79
|
+
### Commit Messages
|
|
80
|
+
|
|
81
|
+
Follow conventional commit format:
|
|
82
|
+
|
|
83
|
+
```
|
|
84
|
+
type(scope): description
|
|
85
|
+
|
|
86
|
+
[optional body]
|
|
87
|
+
|
|
88
|
+
[optional footer]
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
**Types:**
|
|
92
|
+
|
|
93
|
+
- `feat`: New feature
|
|
94
|
+
- `fix`: Bug fix
|
|
95
|
+
- `docs`: Documentation changes
|
|
96
|
+
- `style`: Code style changes (formatting, etc.)
|
|
97
|
+
- `refactor`: Code refactoring
|
|
98
|
+
- `test`: Adding or updating tests
|
|
99
|
+
- `chore`: Maintenance tasks
|
|
100
|
+
|
|
101
|
+
**Examples:**
|
|
102
|
+
|
|
103
|
+
```
|
|
104
|
+
feat(resources): add pagination support to character list
|
|
105
|
+
fix(http-client): handle network timeout errors
|
|
106
|
+
docs(readme): update installation instructions
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
## Code Standards
|
|
110
|
+
|
|
111
|
+
### TypeScript Guidelines
|
|
112
|
+
|
|
113
|
+
- **Type Safety**: Prefer explicit types over `any`
|
|
114
|
+
- **Interfaces**: Use interfaces for object shapes
|
|
115
|
+
- **Generics**: Leverage generics for reusable components
|
|
116
|
+
- **Strict Mode**: The project uses strict TypeScript settings
|
|
117
|
+
|
|
118
|
+
### Code Style
|
|
119
|
+
|
|
120
|
+
The project uses **ESLint** and **Prettier** for code formatting:
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
# Auto-fix linting issues and format code
|
|
124
|
+
pnpm lint
|
|
125
|
+
|
|
126
|
+
# Check linting without fixing
|
|
127
|
+
npx eslint src --ext .ts
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
**Key Style Rules:**
|
|
131
|
+
|
|
132
|
+
- Use camelCase for variables and functions
|
|
133
|
+
- Use PascalCase for classes and interfaces
|
|
134
|
+
- Prefer `const` over `let` when possible
|
|
135
|
+
- Use meaningful variable names
|
|
136
|
+
- Add JSDoc comments for public APIs
|
|
137
|
+
|
|
138
|
+
### Import Organization
|
|
139
|
+
|
|
140
|
+
Imports should be organized as follows:
|
|
141
|
+
|
|
142
|
+
```typescript
|
|
143
|
+
// 1. Built-in Node.js modules
|
|
144
|
+
import { readFile } from 'fs/promises';
|
|
145
|
+
|
|
146
|
+
// 2. External dependencies
|
|
147
|
+
import axios from 'axios';
|
|
148
|
+
import { z } from 'zod';
|
|
149
|
+
|
|
150
|
+
// 3. Internal modules (ordered alphabetically)
|
|
151
|
+
import { BaseResource } from './base-resource';
|
|
152
|
+
import { HttpClient } from './http-client';
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
## Testing
|
|
156
|
+
|
|
157
|
+
### Running Tests
|
|
158
|
+
|
|
159
|
+
```bash
|
|
160
|
+
# Run all tests with linting
|
|
161
|
+
pnpm test
|
|
162
|
+
|
|
163
|
+
# Run tests only (without linting)
|
|
164
|
+
pnpm test:run
|
|
165
|
+
|
|
166
|
+
# Run tests in watch mode
|
|
167
|
+
npx vitest --dir=src
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
### Writing Tests
|
|
171
|
+
|
|
172
|
+
1. **Location**: Place test files alongside source files with `.test.ts` extension
|
|
173
|
+
2. **Naming**: Use descriptive test names that explain the behavior being tested
|
|
174
|
+
3. **Structure**: Follow Arrange-Act-Assert pattern
|
|
175
|
+
|
|
176
|
+
**Example Test:**
|
|
177
|
+
|
|
178
|
+
```typescript
|
|
179
|
+
import { describe, test, expect } from 'vitest';
|
|
180
|
+
|
|
181
|
+
describe('ResourceName', () => {
|
|
182
|
+
test('should return correct data when field list is specified', async () => {
|
|
183
|
+
// Arrange
|
|
184
|
+
const expectedFields = ['id', 'name'];
|
|
185
|
+
|
|
186
|
+
// Act
|
|
187
|
+
const result = await resource.retrieve(123, { fieldList: expectedFields });
|
|
188
|
+
|
|
189
|
+
// Assert
|
|
190
|
+
expect(Object.keys(result)).toEqual(expectedFields);
|
|
191
|
+
});
|
|
192
|
+
});
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
### Test Coverage
|
|
196
|
+
|
|
197
|
+
- Write tests for all new functionality
|
|
198
|
+
- Include both success and error scenarios
|
|
199
|
+
- Mock external dependencies using **nock** for HTTP requests
|
|
200
|
+
- Test files are located in `src/__mocks__/` for mock data
|
|
201
|
+
|
|
202
|
+
## Submitting Changes
|
|
203
|
+
|
|
204
|
+
### Pull Request Process
|
|
205
|
+
|
|
206
|
+
1. **Update Documentation**: Ensure README, JSDoc, and other docs reflect your changes
|
|
207
|
+
|
|
208
|
+
2. **Verify Quality Checks**: All checks must pass before merging
|
|
209
|
+
|
|
210
|
+
```bash
|
|
211
|
+
pnpm test:run # All tests pass
|
|
212
|
+
pnpm lint # No linting errors
|
|
213
|
+
pnpm compile # Code compiles successfully
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
3. **Create Pull Request**:
|
|
217
|
+
- Use a descriptive title
|
|
218
|
+
- Reference any related issues
|
|
219
|
+
- Provide clear description of changes
|
|
220
|
+
- Include examples if adding new features
|
|
221
|
+
|
|
222
|
+
4. **Review Process**:
|
|
223
|
+
- Maintainers will review your PR
|
|
224
|
+
- Address any feedback promptly
|
|
225
|
+
- See [CODE_REVIEW.md](./CODE_REVIEW.md) for review criteria
|
|
226
|
+
|
|
227
|
+
### Pre-commit Hooks
|
|
228
|
+
|
|
229
|
+
The project uses **Husky** and **lint-staged** to ensure code quality:
|
|
230
|
+
|
|
231
|
+
- **Auto-formatting**: Prettier formats code on commit
|
|
232
|
+
- **Linting**: ESLint checks are enforced
|
|
233
|
+
- **Type checking**: TypeScript compilation is verified
|
|
234
|
+
|
|
235
|
+
If pre-commit hooks fail, fix the issues before committing:
|
|
236
|
+
|
|
237
|
+
```bash
|
|
238
|
+
pnpm lint # Fix linting issues
|
|
239
|
+
git add . # Stage the fixes
|
|
240
|
+
git commit # Try committing again
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
## Project Structure
|
|
244
|
+
|
|
245
|
+
```
|
|
246
|
+
src/
|
|
247
|
+
├── comic-vine.ts # Main SDK class
|
|
248
|
+
├── errors/ # Custom error classes
|
|
249
|
+
├── http-client/ # HTTP client and URL builder
|
|
250
|
+
├── options/ # Configuration options
|
|
251
|
+
├── resources/ # API resource implementations
|
|
252
|
+
│ ├── base-resource.ts # Base class for all resources
|
|
253
|
+
│ ├── character/ # Character-specific code
|
|
254
|
+
│ ├── issue/ # Issue-specific code
|
|
255
|
+
│ └── ... # Other Comic Vine resources
|
|
256
|
+
├── types/ # TypeScript type definitions
|
|
257
|
+
└── utils/ # Utility functions
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
### Adding New Resources
|
|
261
|
+
|
|
262
|
+
When adding support for a new Comic Vine API resource:
|
|
263
|
+
|
|
264
|
+
1. Create a new directory under `src/resources/`
|
|
265
|
+
2. Implement the resource class extending `BaseResource`
|
|
266
|
+
3. Add TypeScript types in a `types/` subdirectory
|
|
267
|
+
4. Write comprehensive tests
|
|
268
|
+
5. Update the main `ComicVine` class to include the new resource
|
|
269
|
+
6. Add mock data for testing
|
|
270
|
+
|
|
271
|
+
## Resources
|
|
272
|
+
|
|
273
|
+
### Documentation
|
|
274
|
+
|
|
275
|
+
- [Comic Vine API Documentation](https://comicvine.gamespot.com/api/documentation)
|
|
276
|
+
- [Project README](./README.md)
|
|
277
|
+
- [Code Review Guidelines](./CODE_REVIEW.md)
|
|
278
|
+
|
|
279
|
+
### Getting Help
|
|
280
|
+
|
|
281
|
+
- **Issues**: [GitHub Issues](https://github.com/AllyMurray/comic-vine/issues)
|
|
282
|
+
- **Discussions**: Use GitHub Discussions for questions
|
|
283
|
+
|
|
284
|
+
### Development Tools
|
|
285
|
+
|
|
286
|
+
- **Package Manager**: [pnpm](https://pnpm.io/)
|
|
287
|
+
- **Testing**: [Vitest](https://vitest.dev/)
|
|
288
|
+
- **Linting**: [ESLint](https://eslint.org/) + [TypeScript ESLint](https://typescript-eslint.io/)
|
|
289
|
+
- **Formatting**: [Prettier](https://prettier.io/)
|
|
290
|
+
- **Git Hooks**: [Husky](https://typicode.github.io/husky/)
|
|
291
|
+
|
|
292
|
+
---
|
|
293
|
+
|
|
294
|
+
Thank you for contributing to Comic Vine SDK! Your contributions help make this library better for everyone. 🚀
|
package/README.md
CHANGED
|
@@ -1,10 +1,21 @@
|
|
|
1
1
|
# Comic Vine SDK
|
|
2
2
|
|
|
3
|
+
[](https://www.npmjs.com/package/comic-vine-sdk)
|
|
4
|
+
[](https://github.com/AllyMurray/comic-vine/blob/main/LICENSE)
|
|
5
|
+
[](https://nodejs.org/)
|
|
6
|
+
[](https://www.typescriptlang.org/)
|
|
7
|
+
|
|
3
8
|
The Comic Vine SDK provides convenient access to the [Comic Vine API][comic-vine-api] from applications written in JavaScript/TypeScript. The API provides full access to the structured-wiki content.
|
|
4
9
|
|
|
5
10
|
## Table of Contents
|
|
6
11
|
|
|
12
|
+
- [Requirements](#requirements)
|
|
7
13
|
- [Installation](#installation)
|
|
14
|
+
- [Quick Start](#quick-start)
|
|
15
|
+
- [API Key Security](#api-key-security)
|
|
16
|
+
- [Rate Limiting](#rate-limiting)
|
|
17
|
+
- [Error Handling](#error-handling)
|
|
18
|
+
- [Advanced Usage](#advanced-usage)
|
|
8
19
|
- [Roadmap](#roadmap)
|
|
9
20
|
- [Comic Vine Resources](#comic-vine-resources)
|
|
10
21
|
- [Usage/Examples](#usageexamples)
|
|
@@ -18,19 +29,426 @@ The Comic Vine SDK provides convenient access to the [Comic Vine API][comic-vine
|
|
|
18
29
|
- [Run Locally](#run-locally)
|
|
19
30
|
- [Authors](#authors)
|
|
20
31
|
|
|
32
|
+
## Requirements
|
|
33
|
+
|
|
34
|
+
- Node.js 20.0.0 or higher
|
|
35
|
+
- npm, yarn, or pnpm
|
|
36
|
+
|
|
21
37
|
## Installation
|
|
22
38
|
|
|
23
|
-
|
|
39
|
+
Choose your preferred package manager:
|
|
40
|
+
|
|
41
|
+
**pnpm**
|
|
42
|
+
|
|
43
|
+
```sh
|
|
44
|
+
pnpm add comic-vine-sdk
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
**npm**
|
|
24
48
|
|
|
25
49
|
```sh
|
|
26
50
|
npm install comic-vine-sdk
|
|
27
|
-
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
**yarn**
|
|
54
|
+
|
|
55
|
+
```sh
|
|
28
56
|
yarn add comic-vine-sdk
|
|
29
57
|
```
|
|
30
58
|
|
|
59
|
+
## Quick Start
|
|
60
|
+
|
|
61
|
+
```js
|
|
62
|
+
import ComicVine from 'comic-vine-sdk';
|
|
63
|
+
|
|
64
|
+
// Initialize the client
|
|
65
|
+
const comicVine = new ComicVine('your-api-key-here');
|
|
66
|
+
|
|
67
|
+
// Fetch a single publisher
|
|
68
|
+
const publisher = await comicVine.publisher.retrieve(1859);
|
|
69
|
+
console.log(publisher.name);
|
|
70
|
+
|
|
71
|
+
// Fetch a list of issues
|
|
72
|
+
const issues = await comicVine.issue.list({ limit: 10 });
|
|
73
|
+
console.log(issues.data.map((issue) => issue.name));
|
|
74
|
+
|
|
75
|
+
// Fetch with field limiting
|
|
76
|
+
const limitedIssue = await comicVine.issue.retrieve(1234, {
|
|
77
|
+
fieldList: ['id', 'name', 'description'],
|
|
78
|
+
});
|
|
79
|
+
console.log(limitedIssue.name);
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## API Key Security
|
|
83
|
+
|
|
84
|
+
⚠️ **Important**: Never expose your API key in client-side code or commit it to version control.
|
|
85
|
+
|
|
86
|
+
### Environment Variables (Recommended)
|
|
87
|
+
|
|
88
|
+
**Create a .env file:**
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
# .env file
|
|
92
|
+
COMIC_VINE_API_KEY=your-api-key-here
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
**Use in your application:**
|
|
96
|
+
|
|
97
|
+
```js
|
|
98
|
+
import ComicVine from 'comic-vine-sdk';
|
|
99
|
+
|
|
100
|
+
const comicVine = new ComicVine(process.env.COMIC_VINE_API_KEY);
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### Browser Usage
|
|
104
|
+
|
|
105
|
+
The Comic Vine API doesn't support CORS. For browser usage, you'll need:
|
|
106
|
+
|
|
107
|
+
- A backend proxy to make API calls
|
|
108
|
+
- Server-side API key storage (never send keys to the browser)
|
|
109
|
+
|
|
110
|
+
**Example proxy setup:**
|
|
111
|
+
|
|
112
|
+
```js
|
|
113
|
+
// Backend API route (Express.js example)
|
|
114
|
+
app.get('/api/comic-vine/publisher/:id', async (req, res) => {
|
|
115
|
+
try {
|
|
116
|
+
const comicVine = new ComicVine(process.env.COMIC_VINE_API_KEY);
|
|
117
|
+
const publisher = await comicVine.publisher.retrieve(req.params.id);
|
|
118
|
+
res.json(publisher);
|
|
119
|
+
} catch (error) {
|
|
120
|
+
res.status(500).json({ error: error.message });
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
```
|
|
124
|
+
|
|
31
125
|
## TypeScript Typings
|
|
32
126
|
|
|
33
|
-
There's a good
|
|
127
|
+
There's a good chance you may find an issue with the typings in the API response objects. They were generated using sample data from the API, if you find a problem [open an issue](https://github.com/AllyMurray/comic-vine/issues/new) detailing the problem along with the request details so I can add that request to the sample dataset. While you wait for it to be fixed add `// @ts-expect-error` above the line causing the problem. This will allow you to compile in the meantime but will flag when the problem has been fixed.
|
|
128
|
+
|
|
129
|
+
## Rate Limiting
|
|
130
|
+
|
|
131
|
+
The Comic Vine API implements rate limiting to ensure fair usage and API health for all users.
|
|
132
|
+
|
|
133
|
+
> ⚠️ **Note**: This library will soon include built-in solutions for caching, request deduplication, and rate limiting. The examples below are temporary workarounds until these features are available.
|
|
134
|
+
|
|
135
|
+
### Limits
|
|
136
|
+
|
|
137
|
+
- **200 requests per resource per hour** - Official limit per user
|
|
138
|
+
- **Velocity detection** - Prevents too many requests per second
|
|
139
|
+
- **Temporary blocks** - May occur if limits are exceeded
|
|
140
|
+
|
|
141
|
+
### Best Practices
|
|
142
|
+
|
|
143
|
+
**Cache responses** to avoid duplicate requests:
|
|
144
|
+
|
|
145
|
+
```js
|
|
146
|
+
// Example: Simple in-memory cache
|
|
147
|
+
const cache = new Map();
|
|
148
|
+
|
|
149
|
+
async function getCachedPublisher(id) {
|
|
150
|
+
const cacheKey = `publisher-${id}`;
|
|
151
|
+
|
|
152
|
+
if (cache.has(cacheKey)) {
|
|
153
|
+
return cache.get(cacheKey);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
const publisher = await comicVine.publisher.retrieve(id);
|
|
157
|
+
cache.set(cacheKey, publisher);
|
|
158
|
+
|
|
159
|
+
return publisher;
|
|
160
|
+
}
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
**Implement delays** between requests:
|
|
164
|
+
|
|
165
|
+
```js
|
|
166
|
+
// Example: Add delay between requests
|
|
167
|
+
async function fetchMultipleIssues(ids) {
|
|
168
|
+
const issues = [];
|
|
169
|
+
|
|
170
|
+
for (const id of ids) {
|
|
171
|
+
const issue = await comicVine.issue.retrieve(id);
|
|
172
|
+
issues.push(issue);
|
|
173
|
+
|
|
174
|
+
// Wait 100ms between requests
|
|
175
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
return issues;
|
|
179
|
+
}
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
**Use pagination wisely**:
|
|
183
|
+
|
|
184
|
+
```js
|
|
185
|
+
// Instead of making many small requests
|
|
186
|
+
const issues = await comicVine.issue.list({ limit: 100 }); // Better
|
|
187
|
+
// Rather than
|
|
188
|
+
const issues = await comicVine.issue.list({ limit: 10 }); // Less efficient
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
## Error Handling
|
|
192
|
+
|
|
193
|
+
The Comic Vine SDK provides specific error types to help you handle different failure scenarios gracefully.
|
|
194
|
+
|
|
195
|
+
### Error Types
|
|
196
|
+
|
|
197
|
+
All errors extend the base `BaseError` class and include:
|
|
198
|
+
|
|
199
|
+
- `message`: Human-readable error description
|
|
200
|
+
- `help`: Guidance on how to resolve the issue
|
|
201
|
+
|
|
202
|
+
**Common Error Types:**
|
|
203
|
+
|
|
204
|
+
| Error Type | When It Occurs | How to Handle |
|
|
205
|
+
| ------------------------------ | ----------------------- | -------------------------------- |
|
|
206
|
+
| `ComicVineUnauthorizedError` | Invalid API key | Check your API key |
|
|
207
|
+
| `ComicVineObjectNotFoundError` | Resource doesn't exist | Verify the resource ID |
|
|
208
|
+
| `OptionsValidationError` | Invalid request options | Check your parameters |
|
|
209
|
+
| `ComicVineGenericRequestError` | API request failed | Retry or check API status |
|
|
210
|
+
| `ComicVineSubscriberOnlyError` | Premium content access | Requires Comic Vine subscription |
|
|
211
|
+
|
|
212
|
+
### Basic Error Handling
|
|
213
|
+
|
|
214
|
+
**Simple try-catch:**
|
|
215
|
+
|
|
216
|
+
```js
|
|
217
|
+
import ComicVine from 'comic-vine-sdk';
|
|
218
|
+
|
|
219
|
+
const comicVine = new ComicVine('your-api-key-here');
|
|
220
|
+
|
|
221
|
+
try {
|
|
222
|
+
const publisher = await comicVine.publisher.retrieve(999999);
|
|
223
|
+
console.log(publisher.name);
|
|
224
|
+
} catch (error) {
|
|
225
|
+
console.error('Error:', error.message);
|
|
226
|
+
console.error('Help:', error.help);
|
|
227
|
+
}
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
### Specific Error Handling
|
|
231
|
+
|
|
232
|
+
**Handle different error types:**
|
|
233
|
+
|
|
234
|
+
```js
|
|
235
|
+
import ComicVine, {
|
|
236
|
+
ComicVineUnauthorizedError,
|
|
237
|
+
ComicVineObjectNotFoundError,
|
|
238
|
+
OptionsValidationError,
|
|
239
|
+
} from 'comic-vine-sdk';
|
|
240
|
+
|
|
241
|
+
const comicVine = new ComicVine('your-api-key-here');
|
|
242
|
+
|
|
243
|
+
try {
|
|
244
|
+
const issue = await comicVine.issue.retrieve(999999);
|
|
245
|
+
} catch (error) {
|
|
246
|
+
if (error instanceof ComicVineUnauthorizedError) {
|
|
247
|
+
console.error(
|
|
248
|
+
'Invalid API key. Get one from: https://comicvine.gamespot.com/api/',
|
|
249
|
+
);
|
|
250
|
+
} else if (error instanceof ComicVineObjectNotFoundError) {
|
|
251
|
+
console.error('Issue not found. Please check the ID.');
|
|
252
|
+
} else if (error instanceof OptionsValidationError) {
|
|
253
|
+
console.error('Invalid request parameters:', error.message);
|
|
254
|
+
} else {
|
|
255
|
+
console.error('Unexpected error:', error.message);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
### Robust Error Handling with Retry
|
|
261
|
+
|
|
262
|
+
**Implement retry logic for transient errors:**
|
|
263
|
+
|
|
264
|
+
```js
|
|
265
|
+
async function fetchWithRetry(fetchFn, maxRetries = 3) {
|
|
266
|
+
for (let attempt = 1; attempt <= maxRetries; attempt++) {
|
|
267
|
+
try {
|
|
268
|
+
return await fetchFn();
|
|
269
|
+
} catch (error) {
|
|
270
|
+
// Don't retry on client errors
|
|
271
|
+
if (
|
|
272
|
+
error instanceof ComicVineUnauthorizedError ||
|
|
273
|
+
error instanceof ComicVineObjectNotFoundError ||
|
|
274
|
+
error instanceof OptionsValidationError
|
|
275
|
+
) {
|
|
276
|
+
throw error;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
// Retry on server errors
|
|
280
|
+
if (attempt === maxRetries) {
|
|
281
|
+
throw error;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
// Wait before retrying (exponential backoff)
|
|
285
|
+
const delay = Math.pow(2, attempt) * 1000;
|
|
286
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
// Usage
|
|
292
|
+
try {
|
|
293
|
+
const publisher = await fetchWithRetry(() =>
|
|
294
|
+
comicVine.publisher.retrieve(1859),
|
|
295
|
+
);
|
|
296
|
+
console.log(publisher.name);
|
|
297
|
+
} catch (error) {
|
|
298
|
+
console.error('Failed after retries:', error.message);
|
|
299
|
+
}
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
### Error Handling in Lists
|
|
303
|
+
|
|
304
|
+
**Handle errors when processing multiple items:**
|
|
305
|
+
|
|
306
|
+
```js
|
|
307
|
+
async function fetchMultipleIssues(ids) {
|
|
308
|
+
const results = [];
|
|
309
|
+
const errors = [];
|
|
310
|
+
|
|
311
|
+
for (const id of ids) {
|
|
312
|
+
try {
|
|
313
|
+
const issue = await comicVine.issue.retrieve(id);
|
|
314
|
+
results.push({ id, issue });
|
|
315
|
+
} catch (error) {
|
|
316
|
+
errors.push({ id, error: error.message });
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
return { results, errors };
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
// Usage
|
|
324
|
+
const { results, errors } = await fetchMultipleIssues([1, 2, 999999]);
|
|
325
|
+
console.log(`Successfully fetched: ${results.length}`);
|
|
326
|
+
console.log(`Errors: ${errors.length}`);
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
## Advanced Usage
|
|
330
|
+
|
|
331
|
+
### Available Filters
|
|
332
|
+
|
|
333
|
+
Common filter options for list methods:
|
|
334
|
+
|
|
335
|
+
**Filter by name:**
|
|
336
|
+
|
|
337
|
+
```js
|
|
338
|
+
const issues = await comicVine.issue.list({
|
|
339
|
+
filter: { name: 'The Boys' },
|
|
340
|
+
});
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
**Filter by date range:**
|
|
344
|
+
|
|
345
|
+
```js
|
|
346
|
+
const recentIssues = await comicVine.issue.list({
|
|
347
|
+
filter: {
|
|
348
|
+
date_added: '2024-01-01 00:00:00|2024-12-31 23:59:59',
|
|
349
|
+
},
|
|
350
|
+
});
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
**Multiple filters:**
|
|
354
|
+
|
|
355
|
+
```js
|
|
356
|
+
const filteredIssues = await comicVine.issue.list({
|
|
357
|
+
filter: {
|
|
358
|
+
name: 'Spider-Man',
|
|
359
|
+
date_added: '2024-01-01 00:00:00|2024-12-31 23:59:59',
|
|
360
|
+
},
|
|
361
|
+
});
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
**Publisher-specific content:**
|
|
365
|
+
|
|
366
|
+
```js
|
|
367
|
+
const marvelIssues = await comicVine.issue.list({
|
|
368
|
+
filter: {
|
|
369
|
+
publisher: 'Marvel Comics',
|
|
370
|
+
},
|
|
371
|
+
limit: 50,
|
|
372
|
+
});
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
### Common Field Lists
|
|
376
|
+
|
|
377
|
+
**Minimal issue data:**
|
|
378
|
+
|
|
379
|
+
```js
|
|
380
|
+
const lightIssue = await comicVine.issue.retrieve(1234, {
|
|
381
|
+
fieldList: ['id', 'name', 'issue_number'],
|
|
382
|
+
});
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
**Full issue details:**
|
|
386
|
+
|
|
387
|
+
```js
|
|
388
|
+
const fullIssue = await comicVine.issue.retrieve(1234, {
|
|
389
|
+
fieldList: ['id', 'name', 'description', 'cover_date', 'image', 'volume'],
|
|
390
|
+
});
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
**Character essentials:**
|
|
394
|
+
|
|
395
|
+
```js
|
|
396
|
+
const character = await comicVine.character.retrieve(1234, {
|
|
397
|
+
fieldList: ['id', 'name', 'description', 'image', 'publisher', 'powers'],
|
|
398
|
+
});
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
**Publisher overview:**
|
|
402
|
+
|
|
403
|
+
```js
|
|
404
|
+
const publisher = await comicVine.publisher.retrieve(1234, {
|
|
405
|
+
fieldList: [
|
|
406
|
+
'id',
|
|
407
|
+
'name',
|
|
408
|
+
'description',
|
|
409
|
+
'image',
|
|
410
|
+
'date_added',
|
|
411
|
+
'location_city',
|
|
412
|
+
],
|
|
413
|
+
});
|
|
414
|
+
```
|
|
415
|
+
|
|
416
|
+
### Sorting and Ordering
|
|
417
|
+
|
|
418
|
+
**Sort by date (newest first):**
|
|
419
|
+
|
|
420
|
+
```js
|
|
421
|
+
const recentIssues = await comicVine.issue.list({
|
|
422
|
+
sort: 'date_added:desc',
|
|
423
|
+
limit: 10,
|
|
424
|
+
});
|
|
425
|
+
```
|
|
426
|
+
|
|
427
|
+
**Sort by name:**
|
|
428
|
+
|
|
429
|
+
```js
|
|
430
|
+
const sortedCharacters = await comicVine.character.list({
|
|
431
|
+
sort: 'name:asc',
|
|
432
|
+
limit: 100,
|
|
433
|
+
});
|
|
434
|
+
```
|
|
435
|
+
|
|
436
|
+
### Complex Queries
|
|
437
|
+
|
|
438
|
+
**Combine multiple options:**
|
|
439
|
+
|
|
440
|
+
```js
|
|
441
|
+
const complexQuery = await comicVine.issue.list({
|
|
442
|
+
filter: {
|
|
443
|
+
name: 'Spider-Man',
|
|
444
|
+
date_added: '2024-01-01 00:00:00|2024-12-31 23:59:59',
|
|
445
|
+
},
|
|
446
|
+
fieldList: ['id', 'name', 'issue_number', 'cover_date', 'image'],
|
|
447
|
+
sort: 'cover_date:desc',
|
|
448
|
+
limit: 25,
|
|
449
|
+
offset: 0,
|
|
450
|
+
});
|
|
451
|
+
```
|
|
34
452
|
|
|
35
453
|
## Roadmap
|
|
36
454
|
|
|
@@ -82,7 +500,7 @@ const comicVine = new ComicVine('your-api-key-here');
|
|
|
82
500
|
|
|
83
501
|
comicVine.publisher
|
|
84
502
|
.retrieve(1859)
|
|
85
|
-
.then((
|
|
503
|
+
.then((publisher) => console.log(publisher.id))
|
|
86
504
|
.catch((error) => console.error(error));
|
|
87
505
|
```
|
|
88
506
|
|
|
@@ -160,7 +578,7 @@ const comicVine = new ComicVine('your-api-key-here');
|
|
|
160
578
|
|
|
161
579
|
### Fetch a resource list
|
|
162
580
|
|
|
163
|
-
All resources have a
|
|
581
|
+
All resources have a list method, the following example retrieves a list of publishers
|
|
164
582
|
|
|
165
583
|
```js
|
|
166
584
|
import ComicVine from 'comic-vine-sdk';
|
|
@@ -188,7 +606,7 @@ const comicVine = new ComicVine('your-api-key-here');
|
|
|
188
606
|
|
|
189
607
|
(async () => {
|
|
190
608
|
try {
|
|
191
|
-
const issue = await comicVine.issue.retrieve(
|
|
609
|
+
const issue = await comicVine.issue.retrieve(1234, {
|
|
192
610
|
fieldList: ['id', 'name', 'description'],
|
|
193
611
|
});
|
|
194
612
|
|
|
@@ -219,18 +637,22 @@ const comicVine = new ComicVine('your-api-key-here');
|
|
|
219
637
|
|
|
220
638
|
(async () => {
|
|
221
639
|
try {
|
|
222
|
-
const limit
|
|
223
|
-
const filter
|
|
640
|
+
const limit = 50;
|
|
641
|
+
const filter = { name: 'The Boys' };
|
|
224
642
|
|
|
225
643
|
// Retrieve the first 50 issues of The Boys (Page 1)
|
|
226
644
|
const issuesPage1 = await comicVine.issue.list({ limit, filter });
|
|
227
645
|
console.log(`Total issues: ${issuesPage1.data.length}`);
|
|
228
|
-
console.log(issuesPage1.data.map(issue => issue.name).join(', '));
|
|
646
|
+
console.log(issuesPage1.data.map((issue) => issue.name).join(', '));
|
|
229
647
|
|
|
230
648
|
// Retrieve the next 50 issues of The Boys (Page 2)
|
|
231
|
-
const issuesPage2 = await comicVine.issue.list({
|
|
649
|
+
const issuesPage2 = await comicVine.issue.list({
|
|
650
|
+
limit,
|
|
651
|
+
filter,
|
|
652
|
+
offset: 50,
|
|
653
|
+
});
|
|
232
654
|
console.log(`Total issues: ${issuesPage2.data.length}`);
|
|
233
|
-
console.log(issuesPage2.data.map(issue => issue.name).join(', '));
|
|
655
|
+
console.log(issuesPage2.data.map((issue) => issue.name).join(', '));
|
|
234
656
|
} catch (error) {
|
|
235
657
|
console.error(error);
|
|
236
658
|
}
|
|
@@ -256,7 +678,7 @@ const comicVine = new ComicVine('your-api-key-here');
|
|
|
256
678
|
|
|
257
679
|
let issueNames = [];
|
|
258
680
|
for await (const issue of comicVine.issue.list(listOptions)) {
|
|
259
|
-
|
|
681
|
+
issueNames.push(issue.name);
|
|
260
682
|
}
|
|
261
683
|
|
|
262
684
|
console.log(`Total issues: ${issueNames.length}`);
|
package/package.json
CHANGED
|
@@ -66,12 +66,12 @@
|
|
|
66
66
|
"metadata"
|
|
67
67
|
],
|
|
68
68
|
"engines": {
|
|
69
|
-
"node": ">=
|
|
69
|
+
"node": ">= 20.0.0"
|
|
70
70
|
},
|
|
71
71
|
"main": "lib/cjs/index.js",
|
|
72
72
|
"license": "MIT",
|
|
73
73
|
"homepage": "https://github.com/AllyMurray/comic-vine#readme",
|
|
74
|
-
"version": "1.3.
|
|
74
|
+
"version": "1.3.1",
|
|
75
75
|
"bugs": {
|
|
76
76
|
"url": "https://github.com/AllyMurray/comic-vine/issues"
|
|
77
77
|
},
|