-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #6 from ECLK/refactor
merging Refactor with master
- Loading branch information
Showing
21 changed files
with
1,107 additions
and
3,466 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
.git | ||
.gitignore | ||
.dockerignore | ||
.DS_Store | ||
|
||
node_modules/ | ||
config.json |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,6 @@ | ||
node_modules/ | ||
node_modules | ||
config.json | ||
.idea | ||
.DS_Store | ||
result.pdf | ||
result2.pdf | ||
|
||
package-lock.json | ||
static/exports |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,8 +1,13 @@ | ||
# build environment | ||
FROM node:12.2.0 | ||
FROM node:10 | ||
|
||
WORKDIR /app | ||
ENV PATH /app/node_modules/.bin:$PATH | ||
COPY package.json /app/package.json | ||
RUN npm install --silent | ||
COPY . /app | ||
CMD [ "nodemon", "index.js" ] | ||
RUN mv config.json.prod config.json | ||
RUN npm install | ||
|
||
RUN apt-get update && \ | ||
apt-get -y install gconf-service libasound2 libatk1.0-0 libatk-bridge2.0-0 libc6 libcairo2 libcups2 libdbus-1-3 libexpat1 libfontconfig1 libgcc1 libgconf-2-4 libgdk-pixbuf2.0-0 libglib2.0-0 libgtk-3-0 libnspr4 libpango-1.0-0 libpangocairo-1.0-0 libstdc++6 libx11-6 libx11-xcb1 libxcb1 libxcomposite1 libxcursor1 libxdamage1 libxext6 libxfixes3 libxi6 libxrandr2 libxrender1 libxss1 libxtst6 ca-certificates fonts-liberation libappindicator1 libnss3 lsb-release xdg-utils wget | ||
RUN apt-get -y install fonts-lklug-sinhala | ||
|
||
EXPOSE 8000 | ||
CMD ["npm","start"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
MIT License | ||
|
||
Copyright (c) 2019 fritsvt | ||
|
||
Permission is hereby granted, free of charge, to any person obtaining a copy | ||
of this software and associated documentation files (the "Software"), to deal | ||
in the Software without restriction, including without limitation the rights | ||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
copies of the Software, and to permit persons to whom the Software is | ||
furnished to do so, subject to the following conditions: | ||
|
||
The above copyright notice and this permission notice shall be included in all | ||
copies or substantial portions of the Software. | ||
|
||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
SOFTWARE. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,126 @@ | ||
# Puppeteer HTML to PDF converter REST API | ||
|
||
This is a html to pdf converter rest api which converts web pages to pdfs using the headless chrome instance powered by [Puppeteer](https://github.com/GoogleChrome/puppeteer). | ||
|
||
|
||
## Usage | ||
### `POST /generate` | ||
|
||
**Parameters** | ||
|
||
The api doesn't care much how you send the parameters. Wether it's form-data form-urlencoded or as raw json. It's all welcome here. | ||
|
||
| Parameter | Type | Description | | ||
| :--- | :--- | :--- | | ||
| `url` | `string` | **Required if no html**. The url of the webpage to convert to pdf | | ||
| `html` | `string` | **Required if no url**. The html to convert to pdf | | ||
| `file` | `string` | **Required if no html or url**. The template and value information to create pdf | | ||
| `scale` | `string` | **Optional**. Scale of the webpage rendering. Defaults to 1. Scale amount must be between 0.1 and 2 | | ||
| `displayHeaderFooter` | `boolean` | **Optional**. Display header and footer. Defaults to `false ` | | ||
| `headerTemplate` | `string` | **Optional**. HTML template for the print header. Should be valid HTML markup with following classes used to inject printing values into them: `date`, `title`, `url`, `pageNumber`, `totalPages` | | ||
| `footerTemplate` | `string` | **Optional**. HTML template for the print footer. Should use the same format as the `headerTemplate` | | ||
| `printBackground` | `boolean` | **Optional**. Print background graphics. Defaults to `false` | | ||
| `landscape` | `boolean` | **Optional**. Paper orientation. Defaults to `false` | | ||
| `pageRanges` | `string` | **Optional**. Paper ranges to print, e.g., '1-5, 8, 11-13'. Defaults to the empty string, which means print all pages | | ||
| `format` | `string` | **Optional**. Paper format. If set, takes priority over width or height options. Defaults to 'Letter' | | ||
| `width` | `integer` | **Optional**. Paper width, accepts values labeled with units | | ||
| `height` | `integer` | **Optional**. Paper height, accepts values labeled with units | | ||
| `margin.top` | `integer` | **Optional**. Top margin, accepts values labeled with units | | ||
| `margin.right` | `integer` | **Optional**. Right margin, accepts values labeled with units | | ||
| `margin.bottom` | `integer` | **Optional**. Bottom margin, accepts values labeled with units | | ||
| `margin.left` | `integer` | **Optional**. Left margin, accepts values labeled with units | | ||
| `preferCSSPageSize` | `boolean` | **Optional**. Give any CSS `@page` size declared in the page priority over what is declared in `width` and `height` or `format` options. Defaults to `false`, which will scale the content to fit the paper size | | ||
|
||
Following examples is using 'curl' on terminal | ||
|
||
**Example 1** | ||
``` | ||
curl -H "Content-Type: application/json" -X POST \ | ||
-d '{"url":"http://google.com"}' \ | ||
<BASE_URL>/generate | ||
``` | ||
|
||
**Example 2** | ||
``` | ||
curl -H "Content-Type: application/json" -X POST \ | ||
-d '{"html":"<h1>This is some title</h1>"}' \ | ||
<BASE_URL>/generate | ||
``` | ||
|
||
**Example 3** | ||
``` | ||
curl -H "Content-Type: application/json" -X POST \ | ||
-d '{"file": { "template": "exTemplateBootstrap.js", "title": "This is some title" } }' \ | ||
<BASE_URL>/generate | ||
``` | ||
|
||
|
||
**Response** | ||
|
||
If the request was succesful the response will look like this: | ||
``` | ||
{ | ||
"success": true, | ||
"url": "https://<BASE_URL>/exports/<AUTO_GENERATED_FILE_NAME>.pdf", | ||
"path": "/exports/<AUTO_GENERATED_FILE_NAME>.pdf", | ||
"expires": 1564590505 | ||
} | ||
``` | ||
|
||
If one of the parameters was invalid the request will look something like: | ||
``` | ||
{ | ||
"success": true, | ||
"errors": { | ||
"errors": [ | ||
{ | ||
"msg": "Must provide either url or html or file", | ||
"param": "url_html_file", | ||
"location": "body" | ||
} | ||
] | ||
} | ||
} | ||
``` | ||
|
||
## Installation | ||
|
||
Aside from the option to deploy this project on Heroku the instruction below is meant for either a local or standalone setup. | ||
|
||
1. Clone the repo | ||
2. Navigate in the project directory | ||
``` | ||
cd pdf-generate-service | ||
``` | ||
3. Install the npm dependencies | ||
``` | ||
npm install | ||
``` | ||
4. Copy the contents of [config-example.json](config-example.json) and place them in a new config.json | ||
``` | ||
cp config-example.json config.json | ||
``` | ||
5. Fill in the config.json with your configuration | ||
6. Run the app | ||
``` | ||
npm run start | ||
``` | ||
|
||
## Technologies | ||
[puppeteer](https://github.com/GoogleChrome/puppeteer) | ||
|
||
[expressjs](https://github.com/expressjs/express) | ||
|
||
[express-slow-down](https://github.com/nfriedly/express-slow-down) | ||
|
||
[express-validator](https://github.com/express-validator/express-validator) | ||
|
||
[cors](https://github.com/expressjs/cors) | ||
|
||
[multer](https://github.com/expressjs/multer) | ||
|
||
## Contributing | ||
Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change. | ||
|
||
## License | ||
[MIT](LICENSE) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
{ | ||
"PORT": 3000, | ||
"BASE_URL": "http://localhost:3000", | ||
"EXPIRES_IN": 900, | ||
"EXPIRE_CHECK_INTERVAL": 10, | ||
"NODE_ENV": "development" | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
const fs = require('fs') | ||
const path = './config.json'; | ||
let config = {}; | ||
if (fs.existsSync(path)) { | ||
config = require(path); | ||
} | ||
|
||
module.exports = function(key) { | ||
key = key.toUpperCase(); | ||
if (process.env[key]) { | ||
return process.env[key]; | ||
} | ||
|
||
return config[key]; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
{ | ||
"PORT": 8000, | ||
"BASE_URL": "http://localhost:8000", | ||
"EXPIRES_IN": 900, | ||
"EXPIRE_CHECK_INTERVAL": 10, | ||
"NODE_ENV": "production" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
const { validationResult } = require('express-validator'); | ||
const puppeteer = require('puppeteer'); | ||
const config = require('../config'); | ||
const baseURL = config('BASE_URL'); | ||
const expiresIn = config('EXPIRES_IN'); | ||
|
||
module.exports = async function(req, res) { | ||
const errors = validationResult(req); | ||
if (!errors.isEmpty()) { | ||
return res.status(422).json({ | ||
success: true, | ||
errors: errors | ||
}); | ||
}; | ||
|
||
const timestamp = Math.round(Date.now() / 1000); | ||
const randomID = `${timestamp}-${revisedRandId()}`; | ||
const pdfOptions = { | ||
path: `static/exports/${randomID}.pdf`, | ||
format: 'A4', | ||
margin: { | ||
top: 0, | ||
right: 0, | ||
bottom: 0, | ||
left: 0 | ||
} | ||
}; | ||
const availableOptions = ['scale', 'displayHeaderFooter', 'headerTemplate', 'footerTemplate', 'printBackground', 'landscape', | ||
'pageRanges', 'format', 'width', 'height', 'margin.top', 'right', 'margin.bottom', 'margin.left', 'preferCSSPageSize']; | ||
const integerOptions = ['scale', 'width', 'height']; | ||
for (const option of availableOptions) { | ||
if (req.body[option] && !option.includes('margin')) { | ||
if (integerOptions.indexOf(option) > -1) { | ||
pdfOptions[option] = Number(req.body[option]); | ||
} else { | ||
pdfOptions[option] = req.body[option]; | ||
} | ||
} | ||
|
||
if (req.body[option] && option.includes('margin')) { | ||
pdfOptions.margin[option.replace('margin.', '')] = req.body[option]; | ||
} | ||
} | ||
|
||
if (!global.browser) { | ||
const browser = await puppeteer.launch({ args: ['--no-sandbox'] }) | ||
} | ||
const page = await global.browser.newPage(); | ||
if (req.body.url) { | ||
await page.goto(req.body.url); | ||
} else if (req.body.html) { | ||
await page.setContent(req.body.html); | ||
} else if (req.body.file) { | ||
const file = req.body.file; | ||
const htmlContent = require('../templates/'+file.template); | ||
await page.setContent(htmlContent(file)); | ||
} | ||
await page.pdf(pdfOptions); | ||
|
||
await page.close(); | ||
|
||
return res.status(200).json({ | ||
success: true, | ||
url: `${baseURL}/exports/${randomID}.pdf`, | ||
path: `/exports/${randomID}.pdf`, | ||
expires: timestamp + expiresIn | ||
}); | ||
} | ||
|
||
function revisedRandId() { | ||
return Math.random().toString(36).replace(/[^a-z]+/g, '').substr(2, 10); | ||
} |
Oops, something went wrong.