├── examples ├── producer │ └── index.js └── consumer │ ├── package.json │ └── index.js ├── .github ├── dependabot.yml └── workflows │ └── ci.yml ├── index.test-d.ts ├── index.js ├── LICENSE ├── .gitignore ├── package.json ├── index.d.ts ├── test.js └── README.md /examples/producer/index.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "npm" 4 | directory: "/" 5 | schedule: 6 | interval: "daily" 7 | -------------------------------------------------------------------------------- /index.test-d.ts: -------------------------------------------------------------------------------- 1 | import fastify from 'fastify'; 2 | import fastifyAmqp from '../fastify-amqp'; 3 | 4 | const app = fastify(); 5 | 6 | app.register(fastifyAmqp, { hostname: 'localhost' }).after((_err) => { 7 | const amqp = app.amqp.connection; 8 | const amqpChannel = app.amqp.channel; 9 | }) 10 | -------------------------------------------------------------------------------- /examples/consumer/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "fasify-amqp-example-consumer", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [], 10 | "author": "", 11 | "license": "MIT" 12 | } 13 | -------------------------------------------------------------------------------- /examples/consumer/index.js: -------------------------------------------------------------------------------- 1 | const Fastify = require('fastify') 2 | 3 | const app = Fastify({ logger: true }) 4 | 5 | app.register(require('../../index'), { 6 | hostname: 'localhost' 7 | }).ready(function (err) { 8 | if (err) throw err 9 | 10 | if (!app.hasDecorator('amqp')) { 11 | throw new Error('Undefined error with connection.') 12 | } 13 | 14 | app.amqp.channel.assertQueue('') 15 | }) 16 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI workflow 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | build: 7 | runs-on: ubuntu-latest 8 | 9 | strategy: 10 | matrix: 11 | node: [10, 12, 14] 12 | 13 | name: Node.js ${{ matrix.node }} 14 | 15 | services: 16 | rabbitmq: 17 | image: rabbitmq:3.4.3 18 | ports: 19 | - 5672:5672 20 | 21 | steps: 22 | - uses: actions/checkout@v1 23 | with: 24 | node-version: ${{ matrix.node-version }} 25 | 26 | - name: Install 27 | run: npm install 28 | 29 | - name: Run lint 30 | run: npm run lint 31 | 32 | - name: Run tests 33 | run: npm run test 34 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const fp = require('fastify-plugin') 4 | const amqpClient = require('amqplib') 5 | 6 | function getTarget ({ 7 | frameMax, 8 | heartbeat, 9 | hostname, 10 | locale, 11 | password, 12 | port, 13 | url, 14 | username, 15 | vhost 16 | }) { 17 | if (url) { 18 | return url 19 | } else if (hostname) { 20 | return { 21 | frameMax, 22 | heartbeat, 23 | hostname, 24 | locale, 25 | password, 26 | port, 27 | username, 28 | vhost 29 | } 30 | } else { 31 | throw new Error('`url` parameter is mandatory if no hostname is provided') 32 | } 33 | } 34 | 35 | async function fastifyAmqp (fastify, options) { 36 | const connection = await amqpClient.connect(getTarget(options), options.socket) 37 | fastify.addHook('onClose', () => connection.close()) 38 | 39 | const channel = await connection.createChannel() 40 | 41 | fastify.decorate('amqp', { 42 | connection, 43 | channel 44 | }) 45 | } 46 | 47 | module.exports = fp(fastifyAmqp, { 48 | fastify: '>=1.0.0', 49 | name: 'fastify-amqp' 50 | }) 51 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Rafael Gonzaga 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | *.pid.lock 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # nyc test coverage 21 | .nyc_output 22 | 23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 24 | .grunt 25 | 26 | # Bower dependency directory (https://bower.io/) 27 | bower_components 28 | 29 | # node-waf configuration 30 | .lock-wscript 31 | 32 | # Compiled binary addons (https://nodejs.org/api/addons.html) 33 | build/Release 34 | 35 | # Dependency directories 36 | node_modules/ 37 | jspm_packages/ 38 | 39 | # TypeScript v1 declaration files 40 | typings/ 41 | 42 | # Optional npm cache directory 43 | .npm 44 | 45 | # Optional eslint cache 46 | .eslintcache 47 | 48 | # Optional REPL history 49 | .node_repl_history 50 | 51 | # Output of 'npm pack' 52 | *.tgz 53 | 54 | # Yarn Integrity file 55 | .yarn-integrity 56 | 57 | # dotenv environment variables file 58 | .env 59 | 60 | # next.js build output 61 | .next 62 | 63 | package-lock.json 64 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "fastify-amqp", 3 | "version": "1.1.0", 4 | "description": "Fastify AMQP connection plugin, to use with RabbitMQ", 5 | "main": "index.js", 6 | "scripts": { 7 | "lint": "standard", 8 | "test": "npm run unit && npm run typescript", 9 | "unit": "tap test.js", 10 | "typescript": "tsd" 11 | }, 12 | "repository": { 13 | "type": "git", 14 | "url": "git+https://github.com/RafaelGSS/fastify-amqp.git" 15 | }, 16 | "keywords": [ 17 | "rabbitmq", 18 | "connection", 19 | "amqp", 20 | "messager", 21 | "queue", 22 | "fastify" 23 | ], 24 | "author": "Rafael Gonzaga - @rafaelgss", 25 | "license": "MIT", 26 | "bugs": { 27 | "url": "https://github.com/RafaelGSS/fastify-amqp/issues" 28 | }, 29 | "homepage": "https://github.com/RafaelGSS/fastify-amqp#readme", 30 | "dependencies": { 31 | "amqplib": "^0.10.0", 32 | "fastify-plugin": "^4.0.0" 33 | }, 34 | "devDependencies": { 35 | "@types/amqplib": "^0.10.0", 36 | "fastify": "^4.0.0", 37 | "pre-commit": "^1.2.2", 38 | "standard": "^17.0.0", 39 | "tap": "^16.0.0", 40 | "tsd": "^0.28.0", 41 | "typescript": "^5.0.2" 42 | }, 43 | "pre-commit": [ 44 | "lint", 45 | "test" 46 | ] 47 | } 48 | -------------------------------------------------------------------------------- /index.d.ts: -------------------------------------------------------------------------------- 1 | import { Connection, Channel } from 'amqplib'; 2 | import { FastifyPluginAsync } from 'fastify'; 3 | 4 | declare namespace fastifyAmqp { 5 | type FastifyAmqpConnObject = Connection; 6 | 7 | type FastifyAmqpChannelObject = Channel; 8 | 9 | interface FastifyAmqpOptions { 10 | /** 11 | * Full connection URL 12 | */ 13 | url?: string; 14 | /** 15 | * Host of connection 16 | */ 17 | hostname?: string; 18 | /** 19 | * Port to connect 20 | * @default 5672 21 | */ 22 | port?: number; 23 | /** 24 | * User to connect 25 | * @default 'guest' 26 | */ 27 | username?: string; 28 | /** 29 | * Password to connect 30 | * @default 'guest' 31 | */ 32 | password?: string; 33 | /** 34 | * The desired locale for error messages 35 | * @default 'en_US' 36 | */ 37 | locale?: string; 38 | /** 39 | * @default 4kb 40 | */ 41 | frameMax?: number; 42 | /** 43 | * The period of the connection heartbeat 44 | * @default 0 45 | */ 46 | heartbeat?: number; 47 | /** 48 | * @default '/' 49 | */ 50 | vhost?: string; 51 | /** 52 | * Socket options 53 | */ 54 | socket?: any; 55 | } 56 | } 57 | 58 | declare module 'fastify' { 59 | interface FastifyInstance { 60 | amqp: { 61 | connection: fastifyAmqp.FastifyAmqpConnObject; 62 | channel: fastifyAmqp.FastifyAmqpChannelObject; 63 | } 64 | } 65 | } 66 | 67 | declare const fastifyAmqp: FastifyPluginAsync; 68 | 69 | export default fastifyAmqp; 70 | -------------------------------------------------------------------------------- /test.js: -------------------------------------------------------------------------------- 1 | const { test } = require('tap') 2 | 3 | const Fastify = require('fastify') 4 | const fastifyAmqp = require('./index') 5 | 6 | const PORT_OK = 5672 7 | const HOST_OK = 'localhost' 8 | const HOST_INVALID = '1234' 9 | const PROTOCOL_OK = 'amqp' 10 | 11 | test('undefined connection', t => { 12 | t.plan(3) 13 | const app = build(t) 14 | 15 | app.register(fastifyAmqp, {}).ready(err => { 16 | t.equal(typeof err, typeof {}) 17 | t.assert(err instanceof Error) 18 | 19 | t.notOk(app.amqp, 'Should not have amqp decorator') 20 | }) 21 | }) 22 | 23 | test('invalid connection', t => { 24 | t.plan(3) 25 | const app = build(t) 26 | 27 | app.register(fastifyAmqp, { 28 | hostname: HOST_INVALID, 29 | socket: { 30 | timeout: 10000 31 | } 32 | }).ready(err => { 33 | t.equal(typeof err, typeof {}) 34 | t.assert(err instanceof Error) 35 | 36 | t.notOk(app.amqp, 'Should not have amqp decorator') 37 | }) 38 | }) 39 | 40 | test('connection ok without send port', t => { 41 | t.plan(3) 42 | const app = build(t) 43 | 44 | app.register(fastifyAmqp, { 45 | hostname: HOST_OK 46 | }).ready(err => { 47 | t.error(err) 48 | t.ok(app.amqp.connection) 49 | t.ok(app.amqp.channel) 50 | }) 51 | }) 52 | 53 | test('connection object', t => { 54 | t.plan(3) 55 | const app = build(t) 56 | 57 | app.register(fastifyAmqp, { 58 | hostname: HOST_OK, 59 | port: PORT_OK 60 | }).ready(err => { 61 | t.error(err) 62 | t.ok(app.amqp.connection) 63 | t.ok(app.amqp.channel) 64 | }) 65 | }) 66 | 67 | test('connection url', t => { 68 | t.plan(3) 69 | const app = build(t) 70 | 71 | app.register(fastifyAmqp, { 72 | url: `${PROTOCOL_OK}://${HOST_OK}:${PORT_OK}` 73 | }).ready(err => { 74 | t.error(err) 75 | t.ok(app.amqp.connection) 76 | t.ok(app.amqp.channel) 77 | }) 78 | }) 79 | 80 | test('connection with protocol ok', t => { 81 | t.plan(3) 82 | const app = build(t) 83 | 84 | app.register(fastifyAmqp, { 85 | hostname: HOST_OK, 86 | protocol: PROTOCOL_OK 87 | }).ready(err => { 88 | t.error(err) 89 | t.ok(app.amqp.connection) 90 | t.ok(app.amqp.channel) 91 | }) 92 | }) 93 | 94 | function build (t) { 95 | const app = Fastify() 96 | 97 | t.teardown(app.close.bind(app)) 98 | 99 | return app 100 | } 101 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # fastify-amqp 2 | [![js-standard-style](https://img.shields.io/badge/code%20style-standard-brightgreen.svg?style=flat)](http://standardjs.com/) 3 | ![CI workflow](https://github.com/RafaelGSS/fastify-amqp/workflows/CI%20workflow/badge.svg?branch=master) 4 | 5 | Fastify AMQP connection plugin wrapper to amqplib, to use with RabbitMQ 6 | 7 | ## Installation 8 | 9 | This is a [Node.js](https://nodejs.org/) module available through the 10 | [npm registry](https://www.npmjs.com/). It can be installed using the 11 | [`npm`](https://docs.npmjs.com/getting-started/installing-npm-packages-locally) 12 | or 13 | [`yarn`](https://yarnpkg.com/en/) 14 | command line tools. 15 | 16 | ```sh 17 | npm install fastify-amqp --save 18 | ``` 19 | 20 | ## Tests 21 | 22 | ```sh 23 | npm install 24 | npm test 25 | ``` 26 | 27 | ## Usage 28 | 29 | ```js 30 | const fastify = require('fastify')() 31 | 32 | fastify.register(require('fastify-amqp'), { 33 | // the default value is amqp 34 | protocol: 'amqp', 35 | hostname: 'localhost', 36 | // the default value is 5672 37 | port: 5672, 38 | // the default value is guest 39 | username: 'guest', 40 | // the default value is guest 41 | password: 'guest' 42 | // the default value is empty 43 | vhost: '' 44 | }) 45 | 46 | fastify.get('/', function (request, reply) { 47 | const channel = this.amqp.channel 48 | 49 | const queue = 'hello' 50 | const msg = 'Hello world' 51 | 52 | channel.assertQueue(queue, { 53 | durable: false 54 | }) 55 | 56 | channel.sendToQueue(queue, Buffer.from(msg)) 57 | reply.send(' [x] Sent ' + msg) 58 | }) 59 | 60 | fastify.listen(3000, err => { 61 | if (err) throw err 62 | }) 63 | ``` 64 | 65 | ## Reference 66 | 67 | This plugin is just a wrapper to [amqplib](https://github.com/squaremo/amqp.node). 68 | 69 | Contains: 70 | 71 | - `amqp.connection` API to [here](http://www.squaremobius.net/amqp.node/channel_api.html#api_reference) 72 | - `amqp.channel` API to [here](http://www.squaremobius.net/amqp.node/channel_api.html#channel) 73 | 74 | ## Dependencies 75 | 76 | - [amqplib](https://ghub.io/amqplib): An AMQP 0-9-1 (e.g., RabbitMQ) library and client. 77 | - [fastify-plugin](https://ghub.io/fastify-plugin): Plugin helper for Fastify 78 | 79 | ## Dev Dependencies 80 | 81 | - [fastify](https://ghub.io/fastify): Fast and low overhead web framework, for Node.js 82 | - [pre-commit](https://ghub.io/pre-commit): Automatically install pre-commit hooks for your npm modules. 83 | - [standard](https://ghub.io/standard): JavaScript Standard Style 84 | - [tap](https://ghub.io/tap): A Test-Anything-Protocol library for JavaScript 85 | - [typescript](https://ghub.io/typescript): TypeScript is a language for application scale JavaScript development 86 | 87 | ## License 88 | 89 | MIT 90 | --------------------------------------------------------------------------------