Skip to content

Commit

Permalink
Merge branch 'release/0.1.0'
Browse files Browse the repository at this point in the history
  • Loading branch information
Donovan Lambert committed May 26, 2017
2 parents 9d89842 + 11cb35f commit c9aad4f
Show file tree
Hide file tree
Showing 23 changed files with 4,125 additions and 3 deletions.
15 changes: 15 additions & 0 deletions .babelrc
@@ -0,0 +1,15 @@
{
"presets" : [
["env", { "targets": { "node": 6 } }]
],
"env": {
"test": {
"plugins": ["istanbul"]
}
},
"plugins": [
["babel-plugin-transform-builtin-extend", {
"globals": ["Error"]
}]
]
}
12 changes: 12 additions & 0 deletions .editorconfig
@@ -0,0 +1,12 @@
root = true

[*]
indent_style = space
indent_size = 4
end_of_line = lf
charset = utf-8
insert_final_newline = true
trim_trailing_whitespace = true

[*.md]
trim_trailing_whitespace = false
38 changes: 38 additions & 0 deletions .eslintrc.json
@@ -0,0 +1,38 @@
{
"extends" : "airbnb-base",
"env" : { "node": true },
"rules" : {
"indent" : ["error", 4, {
"SwitchCase" : 1,
"VariableDeclarator" : 1,
"outerIIFEBody" : 1,
"FunctionDeclaration" : { "parameters": 1, "body": 1 },
"FunctionExpression" : { "parameters": 1, "body": 1 }
}],
"quotes" : ["error", "single", { "allowTemplateLiterals": true }],
"quote-props" : ["error", "consistent"],
"camelcase" : ["error", { "properties": "always" }],
"func-style" : ["error", "expression"],
"no-empty-function" : ["error"],
"no-underscore-dangle" : ["off"],
"class-methods-use-this" : ["off"],
"comma-dangle" : ["off"],
"func-names" : ["off"],
"no-continue" : ["off"],
"no-implicit-globals" : ["error"],
"key-spacing" : ["error", {
"singleLine" : { "beforeColon": false, "afterColon": true },
"multiLine" : { "beforeColon": false, "afterColon": true },
"align" : { "beforeColon": true, "afterColon": true, "on": "colon" }
}],
"no-multi-spaces": ["error", {
"exceptions": {
"ImportDeclaration" : true,
"Property" : true,
"ClassProperty" : true,
"VariableDeclarator" : true,
"AssignmentExpression" : true
}
}]
}
}
6 changes: 6 additions & 0 deletions .gitignore
@@ -0,0 +1,6 @@
/node_modules

/lib

/test/coverage
/.nyc_output
7 changes: 7 additions & 0 deletions .npmignore
@@ -0,0 +1,7 @@
/src
/test

/.*

**/*.md
**/*.lock
6 changes: 6 additions & 0 deletions .nycrc
@@ -0,0 +1,6 @@
{
"report-dir" : "./test/coverage",
"reporter" : ["lcov", "html", "text-summary"],
"sourceMap" : false,
"instrument" : false
}
16 changes: 16 additions & 0 deletions .travis.yml
@@ -0,0 +1,16 @@
sudo : false
language : node_js
node_js :
- '7'
- '6'

cache:
yarn : true
directories :
- node_modules

script :
- yarn test

after_script:
- cat ./test/coverage/lcov.info | ./node_modules/.bin/coveralls
4 changes: 4 additions & 0 deletions CHANGELOG.md
@@ -0,0 +1,4 @@
## 0.1.0 (2017-05-27)
- Add `Pdfkiwi.convertHtml()` method (allowing to convert html string to pdf).
- Add `saveToFile()` utility method (allowing to save the return of `Pdfkiwi.convertHtml()` in a file).
- Add `sendHttpResponse()` utility method (allowing to return the generated PDF in an HTTP response).
103 changes: 100 additions & 3 deletions README.md
@@ -1,4 +1,101 @@
# pdfkiwi/js-lib
# pdfkiwi-node

[![Build Status](https://travis-ci.org/pdfkiwi/js-lib.svg?branch=master)](https://travis-ci.org/pdfkiwi/js-lib)
[![Coverage Status](https://coveralls.io/repos/github/pdfkiwi/js-lib/badge.svg?branch=master)](https://coveralls.io/github/pdfkiwi/js-lib?branch=master)
> A node library for interacting with [Pdf.kiwi](https://pdf.kiwi) API
[![Build Status](https://travis-ci.org/pdfkiwi/node-lib.svg?branch=master)](https://travis-ci.org/pdfkiwi/node-lib)
[![Coverage Status](https://coveralls.io/repos/github/pdfkiwi/node-lib/badge.svg?branch=master)](https://coveralls.io/github/pdfkiwi/node-lib?branch=master)

## Installation

```bash
# - Npm
npm install pdfkiwi --save

# - Yarn
yarn add pdfkiwi
```

## Usage

Start by instantiating a client instance:

```js
const pdf = require('pdfkiwi');

const client = new pdf.Pdfkiwi('[api email]', ['api token']);
```

You can then use any of the methods described below.

- Available options (for the `options` parameters) are listed on [this page](https://doc.pdf.kiwi/options-list.html).
- API error codes are listed on [this page](https://doc.pdf.kiwi/error-codes.html).
- All of these methods return a [promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise).
- The promise is resolved with a `Buffer` containing the PDF binary data,
You can use built-in utility functions to save or download the pdf directly.
(see [Built-in utility functions](#built-in-utility-functions))

### `.convertHtml()` - Convert HTML string to PDF

```js
Pdfkiwi.convertHtml(html: String|Number, options: Object): Promise
```

__Exemple:__

```js
client.convertHtml('<h1>Hello world</h1>', { orientation: 'landscape' })
.then(pdf.saveToFile('./my-pdf-file.pdf'))
.then(() => { console.log('done !'); })
.catch((err) => {
// err.code : Api error code (if available)
// err.status : Http code (if available)
console.log(err);
});
```

## Built-in utility functions

### `pdf.saveToFile()` — Saves the generated PDF to a file.

```js
pdf.saveToFile(filePath: String): Function
```

- If the `filePath` has no extension, the `.pdf` extension will be automatically appended.
- The `filePath` path is resolved regarding the current working directory.

__Exemple:__

```js
client.convertHtml('<h1>Hello world</h1>')
.then(pdf.saveToFile('/path/to/my-file.pdf'))
.catch((err) => { console.log(err); });
```

### `pdf.sendHttpResponse()` — Returns the generated PDF in an HTTP [response](https://nodejs.org/docs/latest/api/http.html#http_class_http_serverresponse).

```js
pdf.sendHttpResponse(response: http.ServerResponse, fileName: String): Function
```

- If the `fileName` has no extension, the `.pdf` extension will be automatically appended.

__Exemple:__

```js
const express = require('express');
const app = express();

app.get('/pdf', (request, response) => {
client.convertHtml('<h1>Hello world</h1>')
.then(pdf.sendHttpResponse(response, 'my-file'))
.catch((err) => { console.log(err); });
});

app.listen(3000);
```

## Useful links

- https://pdf.kiwi
- http://doc.pdf.kiwi — API Documentation
7 changes: 7 additions & 0 deletions index.js
@@ -0,0 +1,7 @@
/* eslint-disable global-require */

module.exports = {
Pdfkiwi : require('./lib/pdfkiwi'),
saveToFile : require('./lib/utils/saveToFile'),
sendHttpResponse : require('./lib/utils/sendHttpResponse')
};
45 changes: 45 additions & 0 deletions package.json
@@ -0,0 +1,45 @@
{
"name" : "pdfkiwi",
"version" : "0.1.0",
"description" : "A node library for interacting with Pdf.kiwi API",
"repository" : "git@github.com:pdfkiwi/node-lib.git",
"license" : "MIT",
"main" : "./index.js",
"scripts" : {
"build" : "rimraf lib && babel src -d lib/",
"prepublish" : "yarn run build",
"test" : "cross-env NODE_ENV=test nyc _mocha",
"test:watch" : "cross-env NODE_ENV=test mocha --watch",
"lint" : "eslint --max-warnings 0 --ext .js src test/specs"
},
"dependencies": {
"lodash.isplainobject" : "^4.0.6",
"p-queue" : "^1.0.0",
"request" : "^2.81.0"
},
"devDependencies": {
"babel-cli" : "^6.24.1",
"babel-plugin-istanbul" : "^4.1.3",
"babel-plugin-transform-builtin-extend" : "^1.1.2",
"babel-preset-env" : "^1.5.1",
"chai" : "^3.5.0",
"chai-as-promised" : "^6.0.0",
"chai-fs" : "^1.0.0",
"coveralls" : "^2.13.1",
"cross-env" : "^5.0.0",
"eslint" : "^3.19.0",
"eslint-config-airbnb-base" : "^11.2.0",
"eslint-plugin-import" : "^2.2.0",
"mocha" : "^3.4.1",
"mock-fs" : "^4.3.0",
"nock" : "^9.0.13",
"nyc" : "^10.3.2",
"qs" : "^6.4.0",
"rimraf" : "^2.6.1",
"sinon" : "^2.3.2",
"sinon-chai" : "^2.10.0"
},
"engines": {
"node": ">= 6"
}
}
49 changes: 49 additions & 0 deletions src/pdfkiwi-error.js
@@ -0,0 +1,49 @@
class PdfkiwiError extends Error {
constructor(message, code, status) {
super(message);

const hasValidCode = code !== null && code !== undefined;
Object.defineProperty(this, 'message', {
configurable : true,
enumerable : false,
value : hasValidCode ? `${message} (code: ${code})` : message,
writable : true
});

Object.defineProperty(this, 'name', {
configurable : true,
enumerable : false,
value : this.constructor.name,
writable : true
});

Object.defineProperty(this, 'code', {
configurable : true,
enumerable : false,
value : code,
writable : true
});

Object.defineProperty(this, 'status', {
configurable : true,
enumerable : false,
value : status,
writable : true
});

// eslint-disable-next-line no-prototype-builtins
if (Error.hasOwnProperty('captureStackTrace')) {
Error.captureStackTrace(this, this.constructor);
return;
}

Object.defineProperty(this, 'stack', {
configurable : true,
enumerable : false,
value : (new Error(message)).stack,
writable : true
});
}
}

module.exports = PdfkiwiError;
75 changes: 75 additions & 0 deletions src/pdfkiwi.js
@@ -0,0 +1,75 @@
const request = require('request');
const isPlainObject = require('lodash.isplainobject');
const PdfkiwiError = require('./pdfkiwi-error');
const Queue = require('./utils/queue');

class Pdfkiwi {
constructor(apiEmail, apiToken) {
if (!apiEmail || !apiToken) {
throw new Error(`[Pdfkiwi] Incomplete Pdf.kiwi API credentials.`);
}

this.api = 'https://pdf.kiwi/api';
this.apiEmail = apiEmail;
this.apiToken = apiToken;
}

convertHtml(html, options) {
if (!html && html !== 0) {
throw new Error(`[Pdfkiwi#convertHtml] No HTML provided.`);
}

if (typeof html !== 'string' && (typeof html !== 'number' || !Number.isFinite(html))) {
throw new TypeError(`[Pdfkiwi#convertHtml] Invalid HTML string.`);
}

const params = { src: html.toString() };
if (options) {
if (!isPlainObject(options)) {
throw new TypeError(`[Pdfkiwi#convertHtml] Invalid options object.`);
}
params.options = Object.assign({}, options);
}

return Queue.add(() => this._doRequest('/generator/render/', params));
}

_doRequest(endpoint, params) {
return new Promise((resolve, reject) => {
const formData = {
email : this.apiEmail,
token : this.apiToken,
html : params.src,
options : params.options || {}
};

const requestOptions = { baseUrl: this.api, form: formData, encoding: null };
request.post(endpoint, requestOptions, (err, res, body) => {
if (err) {
reject(new PdfkiwiError(err.message));
return;
}

if (res.statusCode < 200 || res.statusCode >= 300) {
let errData;
try {
errData = JSON.parse(body.toString('utf8')).error || {};
if ((errData.code || errData.code === 0) && !errData.message) {
errData.message = `API error occurred, see the code.`;
}
} catch (_) {
// eslint-disable-next no-empty
}

errData = Object.assign({ code: null, message: `Unknown API error: ${body}` }, errData);
reject(new PdfkiwiError(errData.message, errData.code, res.statusCode));
return;
}

resolve(body);
});
});
}
}

module.exports = Pdfkiwi;

0 comments on commit c9aad4f

Please sign in to comment.