Skip to content
This repository has been archived by the owner on Dec 30, 2021. It is now read-only.

Commit

Permalink
Merge pull request #138 from kaimallea/modularize
Browse files Browse the repository at this point in the history
refactor: initial impl of ImgurClient class
  • Loading branch information
kaimallea authored Mar 19, 2021
2 parents d598f44 + 890a508 commit 4a34515
Show file tree
Hide file tree
Showing 12 changed files with 255 additions and 245 deletions.
263 changes: 18 additions & 245 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,260 +1,33 @@
### Installation

```bash
```shell
npm install imgur
```

### Usage

#### Requiring the module:
Require and instantiate with credentials:

```javascript
const imgur = require('imgur');
```

#### Dealing with client IDs:

```javascript
// Setting
imgur.setClientId('aCs53GSs4tga0ikp');

// Getting
imgur.getClientId();

// Saving to disk. Returns a promise.
// NOTE: path is optional. Defaults to ~/.imgur
imgur
.saveClientId(path)
.then(() => {
console.log('Saved.');
})
.catch((err) => {
console.log(err.message);
});

// Loading from disk
// NOTE: path is optional. Defaults to ~/.imgur
imgur.loadClientId(path).then(imgur.setClientId);
```

#### Dealing with API URL:

In order to change the API Url say Mashape URL, use setAPIUrl(MashapeURL)

```javascript
//Setting
imgur.setAPIUrl('https://api.imgur.com/3/');

//If setAPIUrl() is not called, API URL is read from process.env.IMGUR_API_URL

//Getting
imgur.getAPIUrl();
```

#### Dealing with Mashape Key

Requests to the Mashape URL expects a X-Mashape-Key: MashapeKey header.
Set Mashape Key by using setMashapeKey(MashapeKey) method.
Note: Defaults to process.env.IMGUR_MASHAPE_KEY

```javascript
//Setting
imgur.setMashapeKey(https://imgur-apiv3.p.mashape.com/);

//Getting
imgur.getMashapeKey()
```
#### Dealing with credentials:
For when you want to upload images to an account.
```javascript
// Setting
imgur.setCredentials('email@domain.com', 'password', 'aCs53GSs4tga0ikp');
```
#### Uploading files; globbing supported:
```javascript
// A single image
imgur
.uploadFile('/home/kai/kittens.png')
.then((json) => {
console.log(json.link);
})
.catch((err) => {
console.error(err.message);
});

// All jpegs in a specific folder
// to an album you own
const albumId = 'F8KTV';
imgur
.uploadFile('/home/kai/*.jpg', albumId)
.then((json) => {
console.log(json.link);
})
.catch((err) => {
console.error(err.message);
});

// Multiple image types from home folder
imgur
.uploadFile('~/*.(jpg|png|gif)')
.then((json) => {
console.log(json.link);
})
.catch((err) => {
console.error(err.message);
});
```
#### Searching images within the gallery:
The first argument should be a query to search and it's the only required option. The second argument is optional params to sort your query by.
- `sort` - Accepts 'time', 'viral', or 'top' as a value. Defaults to top.
- `dateRange` - Accepts 'day', 'week', 'month', 'year', or 'all' as a value. Defaults to all.
- `page` - Accepts an integer (e.g. 1, 2, 3, 4) as a value. Defaults to 1.
```ts
import { ImgurClient } from 'imgur';

Search returns an object with the query response as an array of objects that include an image's ID, title, description, views, etc.. and the params you sent with the request.
```javascript
const query = 'cats';
const optionalParams = { sort: 'top', dateRange: 'week', page: 1 };
imgur
.search(query, optionalParams)
.then((json) => {
console.log(json);
})
.catch((err) => {
console.error(err);
});
```
#### Fetching image data:
```javascript
const kittenPic = 'mbgq7nd';
imgur
.getInfo(kittenPic)
.then((json) => {
console.log(json);
})
.catch((err) => {
console.error(err.message);
});
```
#### Fetching album data:
```javascript
const kittenAlbum = 'mbgq7nd';
imgur
.getAlbumInfo(kittenAlbum)
.then((json) => {
console.log(json);
})
.catch((err) => {
console.error(err.message);
});
```
#### Creating an album:
```javascript
imgur
.createAlbum()
.then((json) => {
console.log(json);
})
.catch((err) => {
console.error(err.message);
});
```
#### Uploading URLs of images hosted elsewhere:
```javascript
// Include http(s) when specifying URLs
imgur
.uploadUrl('https://octodex.github.com/images/topguntocat.png')
.then((json) => {
console.log(json.link);
})
.catch((err) => {
console.error(err.message);
});
```
#### Uploading Base-64 encoded images:
```javascript
const imgurFavicon =
'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAmUlEQVQ4je2TsQ3CMBBFnxMa08WR2IQKJskIUNwMZAcYwWIQMs65JCUpEEIYW4pJy6v+6e6+/hVnnGsAzsCBMi7AsbbW/rIMsAU2xrnmkeruuzW7zgIw+JGbv6fGQpWzfy3HOsJlDQY/AlCv3jpF9oS5ZBOICKoB1YCIlCdQDR9127qyBHP5Gyw3CBXPr/qi709JHXE1S995AsqoJu8x78GsAAAAAElFTkSuQmCC';

imgur
.uploadBase64(imgurFavicon)
.then((json) => {
console.log(json.link);
})
.catch((err) => {
console.error(err.message);
});
```
#### Uploading multiple images:
Upload an array of images of the desired upload type ('File', 'Url', 'Base64').
Returns an array of images (imgur image data).
```javascript
imgur
.uploadImages(images, uploadType /*, albumId */)
.then((images) => {
console.log(images);
})
.catch((err) => {
console.error(err.message);
});
```
#### Uploading an album:
Create a new album and upload an array of images of the desired upload type to it ('File', 'Url', 'Base64').
Returns an object with the album data and an array of images { data: {...}, images: [{...}, ...]}.
The third parameter is an optional fail safe, meaning if the array of images is empty or invalid, it will not fail, but returns an object with empty data and empty images.
```javascript
imgur
.uploadAlbum(images, uploadType /*, failSafe */)
.then((album) => {
console.log(album.data, album.images);
})
.catch((err) => {
console.error(err.message);
});
```
let client;

#### Deleting anonymous uploads
// if you already have an access token acquired
client = new ImgurClient({ accessToken: process.env.ACCESS_TOKEN });

Delete an image based on the deletehash(generated during the image upload)
// or your client ID
client = new ImgurClient({ clientId: process.env.CLIENT_ID });

```javascript
imgur
.deleteImage(deletehash)
.then((status) => {
console.log(status);
})
.catch((err) => {
console.error(err.message);
});
// or your username/password/client id to retrieve an access token automatically:
client = new ImgurClient({
username: process.env.USERNAME,
password: process.env.PASSWORD,
clientId: process.env.CLIENT_ID,
});
```

## License
If you don't have any credentials, you'll need to:

#### MIT
1. [Create an Imgur account](https://imgur.com/register)
1. [Register an application](https://api.imgur.com/#registerapp)
14 changes: 14 additions & 0 deletions src/__tests__/mocks/handlers/image.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,20 @@ const FavoriteSuccessResponse = {
status: 200,
};

export function getHandler(req, res, ctx) {
const { id } = req.params;
const response = {
data: {
id,
title: 'image-title',
description: 'image-description',
},
success: true,
status: 200,
};
return res(ctx.json(response));
}

export function postHandler(_req, res, ctx) {
return res(ctx.json(SuccessResponse));
}
Expand Down
1 change: 1 addition & 0 deletions src/__tests__/mocks/handlers/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export const handlers = [
rest.get('https://api.imgur.com/3/gallery/:id', gallery.getHandler),

// image
rest.get('https://api.imgur.com/3/image/:id', image.getHandler),
rest.post('https://api.imgur.com/3/image/:id', image.postHandler),
rest.post(
'https://api.imgur.com/3/image/:id/favorite',
Expand Down
31 changes: 31 additions & 0 deletions src/client.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { EventEmitter } from 'events';
import got, { Options } from 'got';
import { getAuthorizationHeader, Credentials } from './helpers';

export class ImgurClient extends EventEmitter {
constructor(readonly credentials: Credentials) {
super();
}

async request(options: Options): Promise<any> {
try {
return await got(options);
} catch (err) {
throw new Error(err);
}
}

async authorizedRequest(options: Options): Promise<any> {
try {
const authorization = await getAuthorizationHeader(this);
const mergedOptions = got.mergeOptions(options, {
headers: { authorization },
responseType: 'json',
resolveBodyOnly: true,
});
return await this.request(mergedOptions);
} catch (err) {
throw new Error(err.message);
}
}
}
26 changes: 26 additions & 0 deletions src/helpers/credentials.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
export type AccessToken = {
accessToken: string;
};

export type ClientId = {
clientId: string;
};

export type Login = ClientId & {
username: string;
password: string;
};

export type Credentials = AccessToken | ClientId | Login;

export function isAccessToken(arg: any): arg is AccessToken {
return arg.accessToken !== undefined;
}

export function isLogin(arg: any): arg is Login {
return arg.username !== undefined && arg.password !== undefined;
}

export function isClientId(arg: any): arg is ClientId {
return arg.clientId !== undefined;
}
7 changes: 7 additions & 0 deletions src/helpers/endpoints.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
const HOST = 'https://api.imgur.com';
const API_VERSION = '3';
const API_BASE = `${HOST}/${API_VERSION}`;

export const AUTHORIZE_ENDPOINT = `${HOST}/oauth2/authorize`;

export const IMAGE_ENDPOINT = `${API_BASE}/image`;
Loading

0 comments on commit 4a34515

Please sign in to comment.