├── .eslintignore ├── Dockerfile ├── examples ├── .env_sample └── example.js ├── .env_sample ├── .eslintrc.json ├── Makefile ├── docker-compose.yml ├── .codeclimate.yml ├── .esdoc.json ├── USAGE.md ├── ISSUE_TEMPLATE.md ├── .gitignore ├── TROUBLESHOOTING.md ├── LICENSE.md ├── package.json ├── lib ├── client.d.ts └── client.js ├── PULL_REQUEST_TEMPLATE.md ├── .travis.yml ├── CODE_OF_CONDUCT.md ├── README.md ├── CONTRIBUTING.md ├── .eslintrc.yml ├── CHANGELOG.md ├── USE_CASES.md └── test └── test.js /.eslintignore: -------------------------------------------------------------------------------- 1 | **/*{.,-}min.js 2 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:onbuild 2 | -------------------------------------------------------------------------------- /examples/.env_sample: -------------------------------------------------------------------------------- 1 | export SENDGRID_API_KEY='' -------------------------------------------------------------------------------- /.env_sample: -------------------------------------------------------------------------------- 1 | SENDGRID_API_KEY=''; -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "standard", 3 | "plugins": [ 4 | "standard" 5 | ] 6 | } -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: clean install test 2 | 3 | clean: 4 | @rm -rf node_modules 5 | 6 | install: clean 7 | npm install 8 | 9 | test: install 10 | npm test 11 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3" 2 | services: 3 | 4 | node-test: 5 | image: "node:4.5.0" 6 | working_dir: /srv/www 7 | environment: 8 | - NODE_ENV=production 9 | volumes: 10 | - ./:/srv/www 11 | command: "npm run test" 12 | -------------------------------------------------------------------------------- /.codeclimate.yml: -------------------------------------------------------------------------------- 1 | --- 2 | engines: 3 | duplication: 4 | enabled: true 5 | config: 6 | languages: 7 | - javascript 8 | eslint: 9 | enabled: true 10 | fixme: 11 | enabled: true 12 | ratings: 13 | paths: 14 | - "**.js" 15 | exclude_paths: 16 | - node_modules/ 17 | - test/ 18 | -------------------------------------------------------------------------------- /.esdoc.json: -------------------------------------------------------------------------------- 1 | { 2 | "source": "./lib", 3 | "destination": "./docs", 4 | "plugins": [ 5 | { 6 | "name": "esdoc-coverage-plugin", 7 | "option": { 8 | "enable": true, 9 | "kind": [ 10 | "class", 11 | "method", 12 | "member", 13 | "get", 14 | "set", 15 | "constructor", 16 | "function", 17 | "variable" 18 | ] 19 | } 20 | } 21 | ] 22 | } -------------------------------------------------------------------------------- /USAGE.md: -------------------------------------------------------------------------------- 1 | Following is an example using SendGrid. You can get your free account [here](https://sendgrid.com/free?source=nodejs-http-client). 2 | 3 | First, update your environment with your [SENDGRID_API_KEY](https://app.sendgrid.com/settings/api_keys). 4 | 5 | ```bash 6 | echo "export SENDGRID_API_KEY='YOUR_API_KEY'" > sendgrid.env 7 | echo "sendgrid.env" >> .gitignore 8 | source ./sendgrid.env 9 | ``` 10 | 11 | Here is the [full working code](https://github.com/sendgrid/nodejs-http-client/blob/master/examples/example.js). 12 | 13 | To run the example: 14 | 15 | ```bash 16 | node examples/example 17 | ``` 18 | -------------------------------------------------------------------------------- /ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 4 | 5 | ### Issue Summary 6 | A summary of the issue and the environment in which it occurs. If suitable, include the steps required to reproduce the bug. Please feel free to include screenshots, screencasts, or code examples. 7 | 8 | ### Steps to Reproduce 9 | 1. This is the first step 10 | 2. This is the second step 11 | 3. Further steps, etc. 12 | 13 | ### Code Snippet 14 | ```node 15 | # paste code here 16 | ``` 17 | 18 | ### Exception/Log 19 | ``` 20 | # paste exception/log here 21 | ``` 22 | 23 | ### Technical details: 24 | * nodejs-http-client version: 25 | * node version: 26 | 27 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # environment variables 2 | .env 3 | 4 | # Logs 5 | logs 6 | *.log 7 | npm-debug.log* 8 | 9 | # Runtime data 10 | pids 11 | *.pid 12 | *.seed 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 | docs 20 | 21 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 22 | .grunt 23 | 24 | # node-waf configuration 25 | .lock-wscript 26 | 27 | # Compiled binary addons (http://nodejs.org/api/addons.html) 28 | build/Release 29 | 30 | # Dependency directory 31 | node_modules 32 | 33 | # Optional npm cache directory 34 | .npm 35 | 36 | # Optional REPL history 37 | .node_repl_history 38 | 39 | # Editor 40 | .vscode* 41 | 42 | # Environment files 43 | .env/*.* 44 | 45 | # Backup package.json files created during release ### 46 | *.bak 47 | -------------------------------------------------------------------------------- /TROUBLESHOOTING.md: -------------------------------------------------------------------------------- 1 | If you have a non-library SendGrid issue, please contact our [support team](https://support.sendgrid.com). 2 | 3 | If you can't find a solution below, please open an [issue](https://github.com/sendgrid/nodejs-http-client/issues). 4 | 5 | ## Table of Contents 6 | * [Viewing the Request Body](#request-body) 7 | 8 | 9 | ## Viewing the Request Body 10 | 11 | When debugging or testing, it may be useful to examine the raw request body to compare against the [documented format](https://sendgrid.com/docs/API_Reference/api_v3.html). 12 | 13 | You can do this with something like: 14 | ```javascript 15 | var requestPost = client.emptyRequest() 16 | requestPost.method = 'POST' 17 | requestPost.path = '/v3/api_keys' 18 | requestPost.body = { data: 'some test data' } 19 | requestPost.headers['X-Test'] = 'test' 20 | 21 | // Log request body before sending POST request. 22 | console.log(requestPost.body) 23 | 24 | client.API(requestPost, (response) => { 25 | // Log the response. 26 | console.log(response.statusCode) 27 | console.log(response.body) 28 | console.log(response.headers) 29 | }) 30 | ``` 31 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (C) 2020, Twilio SendGrid, Inc. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 9 | of the Software, and to permit persons to whom the Software is furnished to do 10 | 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 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "author": "SendGrid (SendGrid.com)", 3 | "contributors": [ 4 | "Elmer Thomas " 5 | ], 6 | "name": "sendgrid-rest", 7 | "description": "HTTP REST client, simplified for Node.js.", 8 | "version": "2.6.1", 9 | "homepage": "https://sendgrid.com", 10 | "repository": { 11 | "type": "git", 12 | "url": "git://github.com/sendgrid/nodejs-http-client.git" 13 | }, 14 | "bugs": { 15 | "url": "https://github.com/sendgrid/nodejs-http-client/issues" 16 | }, 17 | "main": "./lib/client", 18 | "engines": { 19 | "node": ">= 0.10" 20 | }, 21 | "dependencies": { 22 | "core-js": "^3.5.0", 23 | "dotenv": "^4.0.0" 24 | }, 25 | "devDependencies": { 26 | "chai": "^3.5.0", 27 | "eslint": "^4.18.2", 28 | "eslint-config-standard": "^5.1.0", 29 | "eslint-plugin-standard": "^1.3.2", 30 | "eslint-plugin-promise": "^1.0.8", 31 | "mocha": "^5.2.0", 32 | "nock": "^9.0.14" 33 | }, 34 | "scripts": { 35 | "test": "mocha" 36 | }, 37 | "tags": [ 38 | "http", 39 | "rest", 40 | "api" 41 | ], 42 | "license": "MIT", 43 | "optionalDependencies": {} 44 | } 45 | -------------------------------------------------------------------------------- /lib/client.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'sendgrid-rest' { 2 | /** 3 | * request holds the request to an API Call 4 | * @field `test` use this to allow for http calls 5 | * @field `port` set the port for http calls 6 | */ 7 | export interface Request { 8 | host: string, 9 | method: string, 10 | path: string, 11 | headers: {[key: string]: any}, 12 | body: object | string, 13 | queryParams: {[key: string]: any}, 14 | test: boolean, 15 | port: string, 16 | } 17 | 18 | /** 19 | * response holds the response from an API call, use this as an initializer 20 | * like so: JSON.parse(JSON.stringify(response)) 21 | */ 22 | export interface Response { 23 | statusCode: string, 24 | body: object | string, 25 | headers: {[key: string]: any}, 26 | } 27 | 28 | /** 29 | * Client allows for quick and easy access any REST or REST-like API. 30 | */ 31 | export class Client { 32 | constructor(globalRequest: Request) 33 | /** 34 | * utility function to create an empty request object 35 | */ 36 | public emptyRequest(): Request 37 | /** 38 | * API is the main interface to the API. 39 | */ 40 | public API(endpointRequest: Request, callback: (response: Response) => void): void 41 | } 42 | 43 | export var emptyRequest: Request 44 | export var request: Request 45 | } -------------------------------------------------------------------------------- /PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 16 | 17 | # Fixes # 18 | 19 | A short description of what this PR does. 20 | 21 | ### Checklist 22 | - [ ] I acknowledge that all my contributions will be made under the project's license 23 | - [ ] I have made a material change to the repo (functionality, testing, spelling, grammar) 24 | - [ ] I have read the [Contribution Guidelines](CONTRIBUTING.md) and my PR follows them 25 | - [ ] I have titled the PR appropriately 26 | - [ ] I have updated my branch with the master branch 27 | - [ ] I have added tests that prove my fix is effective or that my feature works 28 | - [ ] I have added necessary documentation about the functionality in the appropriate .md file 29 | - [ ] I have added inline documentation to the code I modified 30 | 31 | If you have questions, please file a [support ticket](https://twilio.com/help/contact), or create a GitHub Issue in this repository. 32 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - 4 4 | - 5 5 | - 6 6 | - 7 7 | - 8 8 | - 10 9 | - lts/* 10 | - node 11 | deploy: 12 | - provider: npm 13 | email: twilio-ci@twilio.com 14 | api_key: 15 | secure: EQjq/aPzjHfKGhZE7Lh47DHcGYsnYXL9aEjEPX03CjhLy1QOjVH+qHeb5Ud5t+EVlmsTyK+xMkDuECgA4wb6n4rjaH7XZebMGrkijdQ5zg09qPD8TF5+/gBHIKPdRxlIXoinimsuYDhxvYf3Cq1YSFzZ4+/f/oJOqCjtcNraqQQrdm63WV12tp9fBB8Za2XUo0JTNs0zA4q1qfxp2NSicU9Wf7Cq8ppaV6mngQVd4Q/w/uyGUkOAq/zAjfVYMM0MUmzsPShEI/KaX9/XiUyTIJw+L4SNDHK+zq0Lj3w90oKWaIIioVcB4qi07d0aj0s5xZ8ZxZDr6640p5LpN/lZf5eCMb9ge81OL9Z7CBCtCe1AGk7EJAFBB4WZ9q6MFLfOv5TjEbdADSjbp+0NfhwdPbvrYsN5Z0TkV7sFnQ2LjAwo2CXUu7JItDqKDVuuB36PjPBSAkVN3gxPgUJsBSs1KSFb88ZoVIHLLBfE/vAQGXteBg9e/ScXmzk/59H45gMQozIOggI/3qcK6xaTVk5+IR76tgc1b+G3MGDUpqn4AQyX1wDdWJiIl8jXAJQ27ugqZr0PCKGf3sx/ZUGW03ax6vnb3vUaMce2E5ytLibNDU9vLDPz39gEVQVkV430+qCOC/WPYTOxGBblQLQXOVf8cIY42yzr4IApARs4gbOtllE= 16 | on: 17 | tags: true 18 | node: 10 19 | 20 | notifications: 21 | slack: 22 | if: branch = master 23 | on_pull_requests: false 24 | on_success: never 25 | on_failure: change 26 | rooms: 27 | - secure: QawILOoaJQWghcHWYxFfibatqvka0INzDboLuzWEvdDpCbfHUd4FXXvMGLHBUoTiB2vvey0edCCaCsrMoqJEJ1fyYZYS4XuYN+XGN+FH2GAoKi+j07om9V1ChuUDcXGB+sqMTM09mGvRGk95hLzkI/bRzQVA+ITaRpdWKJYnD0zZWPuQXi6sLVyMQrHqVOYLyf3avN5mJyqncatZkCpMlhQJvn/aIM0wmToifM6HC1xp4lNU3Rq6h+gHyJP+TZZ5zBc1b388UQDjpLHAoB8ZpIqOlvQJ9cwRvSfqQUXWXZrAYS4wBZvq5Y2YpRm6sHZ6pfs/aCJpIVZ3tyTctqTnHlddesBfGyxzbVW/Wl7ewJUhtphxcaVNweuzVnVVj4ooQr58hKlvJtZlrE1wmEluQ0OL0zF4tfBmq3fonCgvWXiQGgGwEC/DmDSxZInGnyHGg3Ew/7SPBhoGWB+g1B90Og5RtyMe/IUbyRXM4jFPCPdv8IiE3zmDyzDVkbjh+YX06F2pYYFPoyFRNawKtx6vGrV0Ta/o08E3tPrtQKxGkwcn+6zIQVuXw9onswnkiZwCDajcI+Yyi/NP9+OK5bSDPIqnuFsMZoEROKGGRUfUFDGyEStw2WdGmMCGiSJjCEHP75l4u4nPhft8sk28/xUC6NjTWoJahthYW08dW+0MuQQ= 28 | -------------------------------------------------------------------------------- /examples/example.js: -------------------------------------------------------------------------------- 1 | var Client = require('../lib/client.js').Client 2 | 3 | // These values persist across of subsequent calls, unless overidden. 4 | var globalRequest = require('../lib/client.js').emptyRequest 5 | globalRequest.host = 'api.sendgrid.com' 6 | // You must add your SendGrid API Key to your OS Environment 7 | globalRequest.headers['Authorization'] = 'Bearer '.concat(process.env.SENDGRID_API_KEY) 8 | var client = new Client(globalRequest) 9 | 10 | function logResponse(response) { 11 | console.log(response.statusCode) 12 | console.log(response.body) 13 | console.log(response.headers) 14 | } 15 | 16 | // GET Collection 17 | var requestGet = client.emptyRequest() 18 | requestGet.method = 'GET' 19 | requestGet.path = '/v3/api_keys' 20 | requestGet.queryParams['limit'] = 100 21 | requestGet.queryParams['offset'] = 0 22 | client.API(requestGet,function (response){ 23 | logResponse(response) 24 | }) 25 | 26 | // POST 27 | var requestBody = { 28 | 'name': 'My API Key from Node.js', 29 | 'scopes': [ 30 | 'mail.send', 31 | 'alerts.create', 32 | 'alerts.read' 33 | ] 34 | } 35 | var requestPost = client.emptyRequest() 36 | requestPost.method = 'POST' 37 | requestPost.path = '/v3/api_keys' 38 | requestPost.body = requestBody 39 | requestPost.headers['X-Test'] = 'test' 40 | function createAPIKey (callback) { 41 | client.API(requestPost, function (response) { 42 | logResponse(response) 43 | var body = JSON.parse(response.body) 44 | callback(body.apiKeyId) 45 | }) 46 | } 47 | 48 | createAPIKey(function (returnValue) { // This ensures we POST a new key first, to get the apiKeyId 49 | var apiKeyId = '/'.concat(returnValue) 50 | 51 | // GET SINGLE 52 | var requestGetSingle = client.emptyRequest() 53 | requestGetSingle.method = 'GET' 54 | requestGetSingle.path = '/v3/api_keys'.concat(apiKeyId) 55 | client.API(requestGetSingle, function (response) { 56 | logResponse(response) 57 | }) 58 | 59 | // PATCH 60 | requestBody = { 61 | 'name': 'A New Hope' 62 | } 63 | var requestPatch = client.emptyRequest() 64 | requestPatch.method = 'PATCH' 65 | requestPatch.path = '/v3/api_keys'.concat(apiKeyId) 66 | requestPatch.body = requestBody 67 | client.API(requestPatch, function (response) { 68 | logResponse(response) 69 | }) 70 | 71 | // PUT 72 | requestBody = { 73 | 'name': 'A New Hope', 74 | 'scopes': [ 75 | 'user.profile.read', 76 | 'user.profile.update' 77 | ] 78 | } 79 | var requestPut = client.emptyRequest() 80 | requestPut.method = 'PUT' 81 | requestPut.path = '/v3/api_keys'.concat(apiKeyId) 82 | requestPut.body = requestBody 83 | client.API(requestPut, function (response) { 84 | logResponse(response) 85 | }) 86 | 87 | // DELETE 88 | var requestDelete = client.emptyRequest() 89 | requestDelete.method = 'DELETE' 90 | requestDelete.path = '/v3/api_keys'.concat(apiKeyId) 91 | client.API(requestDelete, function (response) { 92 | logResponse(response) 93 | }) 94 | }) 95 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, sex characteristics, gender identity and expression, 9 | level of experience, education, socio-economic status, nationality, personal 10 | appearance, race, religion, or sexual identity and orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | - Using welcoming and inclusive language 18 | - Being respectful of differing viewpoints and experiences 19 | - Gracefully accepting constructive criticism 20 | - Focusing on what is best for the community 21 | - Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | - The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | - Trolling, insulting/derogatory comments, and personal or political attacks 28 | - Public or private harassment 29 | - Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | - Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at open-source@twilio.com. All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 72 | 73 | [homepage]: https://www.contributor-covenant.org 74 | -------------------------------------------------------------------------------- /lib/client.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | require('dotenv').config(); 4 | var https = require('https') 5 | var http = require('http') 6 | var queryString = require('querystring') 7 | 8 | // request holds the request to an API Call 9 | var request = { 10 | host: '', 11 | method: '', 12 | path: '', 13 | headers: {}, 14 | body: {}, 15 | queryParams: {}, 16 | test: false, // use this to allow for http calls 17 | port: '' // set the port for http calls 18 | } 19 | 20 | var emptyRequest = JSON.parse(JSON.stringify(request)) 21 | 22 | // response holds the response from an API call, use this as an initializer 23 | // like so: JSON.parse(JSON.stringify(response)) 24 | var response = { 25 | 'statusCode': '', 26 | 'body': {}, 27 | 'headers': {} 28 | } 29 | 30 | // Client allows for quick and easy access any REST or REST-like API. 31 | function Client (globalRequest, maxSockets) { 32 | var emptyResponse = JSON.parse(JSON.stringify(response)) 33 | var body = '' 34 | var httpAgent = null 35 | var httpsAgent = null 36 | 37 | if (maxSockets) { 38 | httpAgent = new http.Agent({ maxSockets: maxSockets }) 39 | httpsAgent = new https.Agent({ maxSockets: maxSockets }) 40 | } 41 | 42 | // utility function to create an empty request object 43 | this.emptyRequest = function () { 44 | return JSON.parse(JSON.stringify(request)) 45 | } 46 | 47 | // utility function to detect empty objects 48 | function isEmpty (obj) { 49 | for (var key in obj) { 50 | if (obj.hasOwnProperty(key)) { 51 | return false 52 | } 53 | } 54 | return true 55 | } 56 | 57 | // add query paramaters to a URL 58 | function buildPath (basePath, queryParams) { 59 | basePath = basePath.concat('?') 60 | var url = basePath.concat(queryString.stringify(queryParams)) 61 | return url 62 | } 63 | 64 | function buildRequest (globalRequest, endpointRequest) { 65 | var request = JSON.parse(JSON.stringify(globalRequest)) 66 | request.host = endpointRequest.host || globalRequest.host 67 | request.method = endpointRequest.method 68 | 69 | if (endpointRequest.port) { 70 | request.port = endpointRequest.port 71 | } 72 | 73 | // build URL 74 | request.path = !isEmpty(endpointRequest.queryParams) 75 | ? buildPath(endpointRequest.path, endpointRequest.queryParams) 76 | : endpointRequest.path 77 | 78 | // add headers 79 | if (!isEmpty(endpointRequest.headers)) { 80 | for (var attrname in endpointRequest.headers) { 81 | request.headers[attrname] = endpointRequest.headers[attrname] 82 | } 83 | } 84 | 85 | // add the request body's content length 86 | if (!isEmpty(endpointRequest.body)) { 87 | body = JSON.stringify(endpointRequest.body) 88 | request.headers['Content-Length'] = Buffer.byteLength(body) 89 | request.headers['Content-Type'] = 'application/json' 90 | } 91 | 92 | // if maxsockets where provided use the apropriate agent 93 | if (maxSockets) { 94 | request.agent = endpointRequest.test === true ? httpAgent : httpsAgent 95 | } 96 | return request 97 | } 98 | 99 | // API is the main interface to the API. 100 | this.API = function (endpointRequest, callback) { 101 | var request = buildRequest(globalRequest, endpointRequest) 102 | 103 | var requestProtocol = null; 104 | 105 | if (endpointRequest.test === true) { 106 | requestProtocol = http 107 | request.port = endpointRequest.port 108 | } else { 109 | requestProtocol = https 110 | } 111 | 112 | var httpRequest = requestProtocol.request(request, function (httpResponse) { 113 | var responseBody = '' 114 | 115 | // cature the response from the API 116 | httpResponse.on('data', function (chunk) { 117 | responseBody += chunk 118 | }) 119 | 120 | // after the call is complete, build the response object 121 | httpResponse.on('end', function () { 122 | var response = JSON.parse(JSON.stringify(emptyResponse)) 123 | response.statusCode = httpResponse.statusCode 124 | response.body = responseBody 125 | response.headers = httpResponse.headers 126 | callback(response) 127 | }) 128 | }) 129 | 130 | httpRequest.on('error', function (e) { 131 | var response = JSON.parse(JSON.stringify(emptyResponse)) 132 | response.statusCode = e.statusCode || 500 133 | response.body = JSON.stringify({ 134 | message: e.message, 135 | name: e.name, 136 | stack: e.stack 137 | }) 138 | callback(response) 139 | }) 140 | 141 | // if thre is a request body, sent it 142 | if (!isEmpty(endpointRequest.body)) { 143 | httpRequest.write(body) 144 | } 145 | 146 | httpRequest.end() 147 | } 148 | 149 | return this 150 | } 151 | 152 | module.exports = 153 | { 154 | Client: Client, 155 | request: request, 156 | emptyRequest: emptyRequest 157 | } 158 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | **This repo is no longer maintained. Please use https://github.com/sendgrid/sendgrid-nodejs/tree/HEAD/packages/client instead.** 2 | 3 | 4 | ![SendGrid Logo](https://uiux.s3.amazonaws.com/2016-logos/email-logo%402x.png) 5 | 6 | [![Build Status](https://travis-ci.org/sendgrid/nodejs-http-client.svg?branch=master)](https://travis-ci.org/sendgrid/nodejs-http-client) 7 | [![Email Notifications Badge](https://dx.sendgrid.com/badge/nodejs)](https://dx.sendgrid.com/newsletter/nodejs) 8 | [![npm version](https://badge.fury.io/js/sendgrid-rest.svg)](https://www.npmjs.com/package/sendgrid-rest) 9 | [![Twitter Follow](https://img.shields.io/twitter/follow/sendgrid.svg?style=social&label=Follow)](https://twitter.com/sendgrid) 10 | [![GitHub contributors](https://img.shields.io/github/contributors/sendgrid/nodejs-http-client.svg)](https://github.com/sendgrid/nodejs-http-client/graphs/contributors) 11 | [![MIT license](https://img.shields.io/badge/license-MIT-blue.svg)](./LICENSE.md) 12 | 13 | **Quickly and easily access any RESTful or RESTful-like API.** 14 | 15 | If you are looking for the SendGrid API client library, please see [this repo](https://github.com/sendgrid/sendgrid-nodejs). 16 | 17 | # Announcements 18 | 19 | All updates to this library are documented in our [CHANGELOG](https://github.com/sendgrid/nodejs-http-client/blob/master/CHANGELOG.md). 20 | 21 | # Table of Contents 22 | - [Installation](#installation) 23 | - [Quick Start](#quick-start) 24 | - [Usage](#usage) 25 | - [Roadmap](#roadmap) 26 | - [How to Contribute](#contribute) 27 | - [About](#about) 28 | - [License](#license) 29 | 30 | 31 | # Installation 32 | 33 | ## Prerequisites 34 | 35 | - Node.js version 0.10, 0.12 or 4 36 | 37 | You need to have a API key to use the app. To configure the API key in the environment variables follow these steps. 38 | - create .env file in the root directory of the project. 39 | - Copy the contents of .env_sample file in to the .env file 40 | - Once you have obtained the API key, find the environment variable SENDGRID_API_KEY and assign your API key as it's value. 41 | As an example it should look like this 42 | ``` 43 | SENDGRID_API_KEY=''; 44 | ``` 45 | 46 | 47 | ## Install Package 48 | 49 | ```bash 50 | npm install sendgrid-rest 51 | ``` 52 | 53 | 54 | # Quick Start 55 | 56 | `GET /your/api/{param}/call` 57 | 58 | ```javascript 59 | var Client = require('sendgrid-rest').Client 60 | var client = new Client() 61 | var request = client.emptyRequest() 62 | var param = 'myparam' 63 | request.host = 'api.example.com' 64 | request.method = 'GET' 65 | request.path = '/your/api/' + param + '/call' 66 | client.API(request, function (response) { 67 | console.log(response.statusCode) 68 | console.log(response.body) 69 | console.log(response.headers) 70 | }) 71 | ``` 72 | 73 | `POST /your/api/{param}/call` with headers, query parameters and a request body. 74 | 75 | ```javascript 76 | var Client = require('sendgrid-rest').Client 77 | var client = new Client() 78 | var request = client.emptyRequest() 79 | request.host = 'api.example.com' 80 | request.headers['Authorization'] = 'Bearer XXXXXX' 81 | request.queryParams['limit'] = 100 82 | request.queryParams['offset'] = 0 83 | request.method = 'POST' 84 | var param = 'myparam' 85 | request.path = '/your/api/' + param + '/call' 86 | requestBody = { 87 | 'some': 0, 88 | 'awesome': 1, 89 | 'data': 3 90 | } 91 | request.body = requestBody 92 | client.API(request, function (response) { 93 | console.log(response.statusCode) 94 | console.log(response.body) 95 | console.log(response.headers) 96 | }) 97 | ``` 98 | 99 | 100 | # Usage 101 | 102 | Following is an example using SendGrid. You can get your free account [here](https://sendgrid.com/free?source=nodejs-http-client). 103 | 104 | First, update your environment with your [SENDGRID_API_KEY](https://app.sendgrid.com/settings/api_keys). 105 | 106 | You can copy the .env_example file located in the "examples" folder to ```.env``` in your project's root. 107 | 108 | ```cp examples/.env_sample .env``` 109 | 110 | Once you have edited the file and added your API Key, you can add the variable to your environment: 111 | ```source .env``` 112 | 113 | 114 | Here is the [full working code](https://github.com/sendgrid/nodejs-http-client/blob/master/examples/example.js). 115 | 116 | To run the example: 117 | 118 | ```bash 119 | node examples/example 120 | ``` 121 | ======= 122 | [Library Usage Documentation](https://github.com/sendgrid/nodejs-http-client/blob/master/USAGE.md) 123 | 124 | # Tests 125 | 126 | Tests can be run through a [Docker](https://www.docker.com) container which is defined in the [docker-compose.yml](docker-compose.yml) file. 127 | 128 | To run the tests, simply run `docker-compose up`. 129 | 130 | 131 | # Roadmap 132 | 133 | If you are interested in the future direction of this project, please take a look at our [milestones](https://github.com/sendgrid/nodejs-http-client/milestones). We would love to hear your feedback. 134 | 135 | 136 | # How to Contribute 137 | 138 | We encourage contribution to our libraries, please see our [CONTRIBUTING](https://github.com/sendgrid/nodejs-http-client/blob/master/CONTRIBUTING.md) guide for details. 139 | 140 | * [Feature Request](https://github.com/sendgrid/nodejs-http-client/blob/master/CONTRIBUTING.md#feature-request) 141 | * [Bug Reports](https://github.com/sendgrid/nodejs-http-client/blob/master/CONTRIBUTING.md#submit-a-bug-report) 142 | * [Improvements to the Codebase](https://github.com/sendgrid/nodejs-http-client/blob/master/CONTRIBUTING.md#improvements-to-the-codebase) 143 | 144 | 145 | # About 146 | 147 | nodejs-http-client is maintained and funded by Twilio SendGrid, Inc. The names and logos for nodejs-http-client are trademarks of Twilio SendGrid, Inc. 148 | 149 | If you need help installing or using the library, please check the [Twilio SendGrid Support Help Center](https://support.sendgrid.com). 150 | 151 | If you've instead found a bug in the library or would like new features added, go ahead and open issues or pull requests against this repo! 152 | 153 | 154 | # License 155 | [The MIT License (MIT)](LICENSE.md) 156 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | Hello! Thank you for choosing to help contribute to one of the SendGrid open source libraries. There are many ways you can contribute and help is always welcome. We simply ask that you follow the following contribution policies. 2 | 3 | - [Feature Request](#feature-request) 4 | - [Submit a Bug Report](#submit-a-bug-report) 5 | - [Improvements to the Codebase](#improvements-to-the-codebase) 6 | - [Understanding the Code Base](#understanding-the-codebase) 7 | - [Testing](#testing) 8 | - [Style Guidelines & Naming Conventions](#style-guidelines-and-naming-conventions) 9 | - [Creating a Pull Request](#creating-a-pull-request) 10 | 11 | We use [Milestones](https://github.com/sendgrid/nodejs-http-client/milestones) to help define current roadmaps, please feel free to grab an issue from the current milestone. Please indicate that you have begun work on it to avoid collisions. Once a PR is made, community review, comments, suggestions and additional PRs are welcomed and encouraged. 12 | 13 | 14 | ## Feature Request 15 | 16 | If you'd like to make a feature request, please read this section. 17 | 18 | The GitHub issue tracker is the preferred channel for library feature requests, but please respect the following restrictions: 19 | 20 | - Please **search for existing issues** in order to ensure we don't have duplicate bugs/feature requests. 21 | - Please be respectful and considerate of others when commenting on issues 22 | 23 | 24 | ## Submit a Bug Report 25 | 26 | Note: DO NOT include your credentials in ANY code examples, descriptions, or media you make public. 27 | 28 | A software bug is a demonstrable issue in the code base. In order for us to diagnose the issue and respond as quickly as possible, please add as much detail as possible into your bug report. 29 | 30 | Before you decide to create a new issue, please try the following: 31 | 32 | 1. Check the Github issues tab if the identified issue has already been reported, if so, please add a +1 to the existing post. 33 | 2. Update to the latest version of this code and check if issue has already been fixed 34 | 3. Copy and fill in the Bug Report Template we have provided below 35 | 36 | ### Please use our Bug Report Template 37 | 38 | In order to make the process easier, we've included a [sample bug report template](ISSUE_TEMPLATE.md). 39 | 40 | 41 | ## Improvements to the Codebase 42 | 43 | We welcome direct contributions to the nodejs-http-client code base. Thank you! 44 | 45 | ### Development Environment ### 46 | 47 | #### Install and Run Locally #### 48 | 49 | ##### Prerequisites ##### 50 | 51 | - Node.js version 0.10, 0.12 or 4 52 | - Please see [package.json](https://github.com/sendgrid/nodejs-http-client/blob/master/package.json) 53 | 54 | ##### Initial setup: ##### 55 | 56 | ```bash 57 | git clone https://github.com/sendgrid/nodejs-http-client.git 58 | cd nodejs-http-client 59 | npm install 60 | ``` 61 | 62 | ##### Execute: ##### 63 | 64 | See the [examples folder](https://github.com/sendgrid/nodejs-http-client/tree/master/examples) to get started quickly. 65 | 66 | You will need to setup the following environment to use the SendGrid example: 67 | 68 | ```bash 69 | echo "export SENDGRID_API_KEY='YOUR_API_KEY'" > sendgrid.env 70 | echo "sendgrid.env" >> .gitignore 71 | source ./sendgrid.env 72 | node examples/example.js 73 | ``` 74 | 75 | To run the example: 76 | 77 | ```bash 78 | node ./examples/example.js 79 | ``` 80 | 81 | 82 | ## Understanding the Code Base 83 | 84 | **/examples** 85 | 86 | Working examples that demonstrate usage. 87 | 88 | **client.js** 89 | 90 | There is an object to hold both the request and response to the API server. 91 | 92 | The main function that does the heavy lifting (and external entry point) is `API`. 93 | 94 | 95 | ## Testing 96 | 97 | All PRs require passing tests before the PR will be reviewed. 98 | 99 | All test files are in [`test/test.js`](https://github.com/sendgrid/nodejs-http-client/blob/master/test/test.js). 100 | 101 | For the purposes of contributing to this repo, please update the [`test.js`](https://github.com/sendgrid/nodejs-http-client/blob/master/test/test.js) file with unit tests as you modify the code. 102 | 103 | Run the test: 104 | 105 | `mocha` 106 | 107 | 108 | ## Style Guidelines & Naming Conventions 109 | 110 | Generally, we follow the style guidelines as suggested by the official language. However, we ask that you conform to the styles that already exist in the library. If you wish to deviate, please explain your reasoning. 111 | 112 | - [Unofficial Style Guide](https://github.com/felixge/node-style-guide) 113 | 114 | Please run your code through: 115 | 116 | - [ESLint](http://eslint.org/) with the standard style guide. 117 | - [esdoc](https://github.com/sendgrid/nodejs-http-client/blob/master/USAGE.md) to check the documentation coverage of your added code. 118 | 119 | 120 | ## Creating a Pull Request 121 | 122 | 1. [Fork](https://help.github.com/fork-a-repo/) the project, clone your fork, 123 | and configure the remotes: 124 | 125 | ```bash 126 | # Clone your fork of the repo into the current directory 127 | git clone https://github.com/sendgrid/nodejs-http-client 128 | # Navigate to the newly cloned directory 129 | cd nodejs-http-client 130 | # Assign the original repo to a remote called "upstream" 131 | git remote add upstream https://github.com/sendgrid/nodejs-http-client 132 | ``` 133 | 134 | 2. If you cloned a while ago, get the latest changes from upstream: 135 | 136 | ```bash 137 | git checkout 138 | git pull upstream 139 | ``` 140 | 141 | 3. Create a new topic branch (off the main project development branch) to 142 | contain your feature, change, or fix: 143 | 144 | ```bash 145 | git checkout -b 146 | ``` 147 | 148 | 4. Commit your changes in logical chunks. Please adhere to these [git commit 149 | message guidelines](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html) 150 | or your code is unlikely to be merged into the main project. Use Git's 151 | [interactive rebase](https://help.github.com/articles/interactive-rebase) 152 | feature to tidy up your commits before making them public. 153 | 154 | 4a. Create tests. 155 | 156 | 4b. Create or update the example code that demonstrates the functionality of this change to the code. 157 | 158 | 5. Locally merge (or rebase) the upstream development branch into your topic branch: 159 | 160 | ```bash 161 | git pull [--rebase] upstream master 162 | ``` 163 | 164 | 6. Push your topic branch up to your fork: 165 | 166 | ```bash 167 | git push origin 168 | ``` 169 | 170 | 7. [Open a Pull Request](https://help.github.com/articles/using-pull-requests/) 171 | with a clear title and description against the `master` branch. All tests must be passing before we will review the PR. 172 | -------------------------------------------------------------------------------- /.eslintrc.yml: -------------------------------------------------------------------------------- 1 | --- 2 | parserOptions: 3 | sourceType: module 4 | ecmaFeatures: 5 | jsx: true 6 | 7 | env: 8 | amd: true 9 | browser: true 10 | es6: true 11 | jquery: true 12 | node: true 13 | 14 | # http://eslint.org/docs/rules/ 15 | rules: 16 | # Possible Errors 17 | no-await-in-loop: off 18 | no-cond-assign: error 19 | no-console: off 20 | no-constant-condition: error 21 | no-control-regex: error 22 | no-debugger: error 23 | no-dupe-args: error 24 | no-dupe-keys: error 25 | no-duplicate-case: error 26 | no-empty-character-class: error 27 | no-empty: error 28 | no-ex-assign: error 29 | no-extra-boolean-cast: error 30 | no-extra-parens: off 31 | no-extra-semi: error 32 | no-func-assign: error 33 | no-inner-declarations: 34 | - error 35 | - functions 36 | no-invalid-regexp: error 37 | no-irregular-whitespace: error 38 | no-negated-in-lhs: error 39 | no-obj-calls: error 40 | no-prototype-builtins: off 41 | no-regex-spaces: error 42 | no-sparse-arrays: error 43 | no-template-curly-in-string: off 44 | no-unexpected-multiline: error 45 | no-unreachable: error 46 | no-unsafe-finally: off 47 | no-unsafe-negation: off 48 | use-isnan: error 49 | valid-jsdoc: off 50 | valid-typeof: error 51 | 52 | # Best Practices 53 | accessor-pairs: error 54 | array-callback-return: off 55 | block-scoped-var: off 56 | class-methods-use-this: off 57 | complexity: 58 | - error 59 | - 6 60 | consistent-return: off 61 | curly: off 62 | default-case: off 63 | dot-location: off 64 | dot-notation: off 65 | eqeqeq: error 66 | guard-for-in: error 67 | no-alert: error 68 | no-caller: error 69 | no-case-declarations: error 70 | no-div-regex: error 71 | no-else-return: off 72 | no-empty-function: off 73 | no-empty-pattern: error 74 | no-eq-null: error 75 | no-eval: error 76 | no-extend-native: error 77 | no-extra-bind: error 78 | no-extra-label: off 79 | no-fallthrough: error 80 | no-floating-decimal: off 81 | no-global-assign: off 82 | no-implicit-coercion: off 83 | no-implied-eval: error 84 | no-invalid-this: off 85 | no-iterator: error 86 | no-labels: 87 | - error 88 | - allowLoop: true 89 | allowSwitch: true 90 | no-lone-blocks: error 91 | no-loop-func: error 92 | no-magic-number: off 93 | no-multi-spaces: off 94 | no-multi-str: off 95 | no-native-reassign: error 96 | no-new-func: error 97 | no-new-wrappers: error 98 | no-new: error 99 | no-octal-escape: error 100 | no-octal: error 101 | no-param-reassign: off 102 | no-proto: error 103 | no-redeclare: error 104 | no-restricted-properties: off 105 | no-return-assign: error 106 | no-return-await: off 107 | no-script-url: error 108 | no-self-assign: off 109 | no-self-compare: error 110 | no-sequences: off 111 | no-throw-literal: off 112 | no-unmodified-loop-condition: off 113 | no-unused-expressions: error 114 | no-unused-labels: off 115 | no-useless-call: error 116 | no-useless-concat: error 117 | no-useless-escape: off 118 | no-useless-return: off 119 | no-void: error 120 | no-warning-comments: off 121 | no-with: error 122 | prefer-promise-reject-errors: off 123 | radix: error 124 | require-await: off 125 | vars-on-top: off 126 | wrap-iife: error 127 | yoda: off 128 | 129 | # Strict 130 | strict: off 131 | 132 | # Variables 133 | init-declarations: off 134 | no-catch-shadow: error 135 | no-delete-var: error 136 | no-label-var: error 137 | no-restricted-globals: off 138 | no-shadow-restricted-names: error 139 | no-shadow: off 140 | no-undef-init: error 141 | no-undef: off 142 | no-undefined: off 143 | no-unused-vars: off 144 | no-use-before-define: off 145 | 146 | # Node.js and CommonJS 147 | callback-return: error 148 | global-require: error 149 | handle-callback-err: error 150 | no-mixed-requires: off 151 | no-new-require: off 152 | no-path-concat: error 153 | no-process-env: off 154 | no-process-exit: error 155 | no-restricted-modules: off 156 | no-sync: off 157 | 158 | # Stylistic Issues 159 | array-bracket-spacing: off 160 | block-spacing: off 161 | brace-style: off 162 | camelcase: off 163 | capitalized-comments: off 164 | comma-dangle: 165 | - error 166 | - never 167 | comma-spacing: off 168 | comma-style: off 169 | computed-property-spacing: off 170 | consistent-this: off 171 | eol-last: off 172 | func-call-spacing: off 173 | func-name-matching: off 174 | func-names: off 175 | func-style: off 176 | id-length: off 177 | id-match: off 178 | indent: off 179 | jsx-quotes: off 180 | key-spacing: off 181 | keyword-spacing: off 182 | line-comment-position: off 183 | linebreak-style: off 184 | lines-around-comment: off 185 | lines-around-directive: off 186 | max-depth: off 187 | max-len: off 188 | max-nested-callbacks: off 189 | max-params: off 190 | max-statements-per-line: off 191 | max-statements: 192 | - error 193 | - 30 194 | multiline-ternary: off 195 | new-cap: off 196 | new-parens: off 197 | newline-after-var: off 198 | newline-before-return: off 199 | newline-per-chained-call: off 200 | no-array-constructor: off 201 | no-bitwise: off 202 | no-continue: off 203 | no-inline-comments: off 204 | no-lonely-if: off 205 | no-mixed-operators: off 206 | no-mixed-spaces-and-tabs: off 207 | no-multi-assign: off 208 | no-multiple-empty-lines: off 209 | no-negated-condition: off 210 | no-nested-ternary: off 211 | no-new-object: off 212 | no-plusplus: off 213 | no-restricted-syntax: off 214 | no-spaced-func: off 215 | no-tabs: off 216 | no-ternary: off 217 | no-trailing-spaces: off 218 | no-underscore-dangle: off 219 | no-unneeded-ternary: off 220 | object-curly-newline: off 221 | object-curly-spacing: off 222 | object-property-newline: off 223 | one-var-declaration-per-line: off 224 | one-var: off 225 | operator-assignment: off 226 | operator-linebreak: off 227 | padded-blocks: off 228 | quote-props: off 229 | quotes: off 230 | require-jsdoc: off 231 | semi-spacing: off 232 | semi: off 233 | sort-keys: off 234 | sort-vars: off 235 | space-before-blocks: off 236 | space-before-function-paren: off 237 | space-in-parens: off 238 | space-infix-ops: off 239 | space-unary-ops: off 240 | spaced-comment: off 241 | template-tag-spacing: off 242 | unicode-bom: off 243 | wrap-regex: off 244 | 245 | # ECMAScript 6 246 | arrow-body-style: off 247 | arrow-parens: off 248 | arrow-spacing: off 249 | constructor-super: off 250 | generator-star-spacing: off 251 | no-class-assign: off 252 | no-confusing-arrow: off 253 | no-const-assign: off 254 | no-dupe-class-members: off 255 | no-duplicate-imports: off 256 | no-new-symbol: off 257 | no-restricted-imports: off 258 | no-this-before-super: off 259 | no-useless-computed-key: off 260 | no-useless-constructor: off 261 | no-useless-rename: off 262 | no-var: off 263 | object-shorthand: off 264 | prefer-arrow-callback: off 265 | prefer-const: off 266 | prefer-destructuring: off 267 | prefer-numeric-literals: off 268 | prefer-rest-params: off 269 | prefer-reflect: off 270 | prefer-spread: off 271 | prefer-template: off 272 | require-yield: off 273 | rest-spread-spacing: off 274 | sort-imports: off 275 | symbol-description: off 276 | template-curly-spacing: off 277 | yield-star-spacing: off 278 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | All notable changes to this project will be documented in this file. 3 | 4 | This project adheres to [Semantic Versioning](http://semver.org/). 5 | 6 | [2020-03-18] Version 2.6.1 7 | -------------------------- 8 | **Library - Docs** 9 | - [PR #73](https://github.com/sendgrid/nodejs-http-client/pull/73): Update example.js. Thanks to [@flaredragon](https://github.com/flaredragon)! 10 | 11 | 12 | [2020-02-19] Version 2.6.0 13 | -------------------------- 14 | **Library - Feature** 15 | - [PR #93](https://github.com/sendgrid/nodejs-http-client/pull/93): Added type definitions. Thanks to [@Strum355](https://github.com/Strum355)! 16 | 17 | 18 | [2020-01-22] Version 2.5.2 19 | -------------------------- 20 | **Library - Docs** 21 | - [PR #120](https://github.com/sendgrid/nodejs-http-client/pull/120): baseline all the templated markdown docs. Thanks to [@childish-sambino](https://github.com/childish-sambino)! 22 | 23 | 24 | [2020-01-15] Version 2.5.1 25 | -------------------------- 26 | **Library - Chore** 27 | - [PR #119](https://github.com/sendgrid/nodejs-http-client/pull/119): prep the repo for automated releasing. Thanks to [@childish-sambino](https://github.com/childish-sambino)! 28 | 29 | 30 | [2019-12-20] Version 2.5.0 31 | -------------------------- 32 | **Library - Chore** 33 | - [PR #113](https://github.com/sendgrid/nodejs-http-client/pull/113): Bump eslint from 2.13.1 to 4.18.2. Thanks to [@dependabot](https://github.com/dependabot)! 34 | - [PR #112](https://github.com/sendgrid/nodejs-http-client/pull/112): Bump stringstream from 0.0.5 to 0.0.6. Thanks to [@dependabot](https://github.com/dependabot)! 35 | - [PR #101](https://github.com/sendgrid/nodejs-http-client/pull/101): #94 | Upgrade dev dependency mocha to patch security vulnerabilitiy. Thanks to [@robincher](https://github.com/robincher)! 36 | - [PR #88](https://github.com/sendgrid/nodejs-http-client/pull/88): update LICENSE - update year to 2018. Thanks to [@myzeprog](https://github.com/myzeprog)! 37 | - [PR #71](https://github.com/sendgrid/nodejs-http-client/pull/71): code refactor to remove duplicate definition of http_request. Thanks to [@skshelar](https://github.com/skshelar)! 38 | - [PR #63](https://github.com/sendgrid/nodejs-http-client/pull/63): Closes #59 by adding a docker-compose file to spin up a container fr…. Thanks to [@onefastsnail](https://github.com/onefastsnail)! 39 | - [PR #56](https://github.com/sendgrid/nodejs-http-client/pull/56): Adds test to check license end year. Thanks to [@mukulmishra18](https://github.com/mukulmishra18)! 40 | - [PR #61](https://github.com/sendgrid/nodejs-http-client/pull/61): Idiomatic changes reported by CodeClimate. Thanks to [@mithunsasidharan](https://github.com/mithunsasidharan)! 41 | - [PR #58](https://github.com/sendgrid/nodejs-http-client/pull/58): Refactored unittest to check for specific repo files to use assert. Thanks to [@mptap](https://github.com/mptap)! 42 | - [PR #54](https://github.com/sendgrid/nodejs-http-client/pull/54): Create Dockerfile. Thanks to [@luiscoms](https://github.com/luiscoms)! 43 | - [PR #55](https://github.com/sendgrid/nodejs-http-client/pull/55): [issue#52] Added unit tests to check some files exist. Thanks to [@luan-cestari](https://github.com/luan-cestari)! 44 | - [PR #53](https://github.com/sendgrid/nodejs-http-client/pull/53): change year for the license file. Thanks to [@luiscobits](https://github.com/luiscobits)! 45 | - [PR #48](https://github.com/sendgrid/nodejs-http-client/pull/48): added code climate config fixes #47. Thanks to [@t2013anurag](https://github.com/t2013anurag)! 46 | - [PR #44](https://github.com/sendgrid/nodejs-http-client/pull/44): Added esdoc. Thanks to [@maxtotterman](https://github.com/maxtotterman)! 47 | - [PR #22](https://github.com/sendgrid/nodejs-http-client/pull/22): Updated travis config. Thanks to [@gr8shivam](https://github.com/gr8shivam)! 48 | 49 | **Library - Docs** 50 | - [PR #64](https://github.com/sendgrid/nodejs-http-client/pull/64): Create USE_CASES.md. Thanks to [@flaredragon](https://github.com/flaredragon)! 51 | - [PR #62](https://github.com/sendgrid/nodejs-http-client/pull/62): update README - fix links to license file. Thanks to [@krlevkirill](https://github.com/krlevkirill)! 52 | - [PR #41](https://github.com/sendgrid/nodejs-http-client/pull/41): Added example file, updated .gitignore and README. Thanks to [@dhsrocha](https://github.com/dhsrocha)! 53 | - [PR #46](https://github.com/sendgrid/nodejs-http-client/pull/46): related to #36 : added the .env_sample and instructions in the readme to configure it. Thanks to [@psnmissaka](https://github.com/psnmissaka)! 54 | - [PR #30](https://github.com/sendgrid/nodejs-http-client/pull/30): Adds example to review request body for troubleshooting. Thanks to [@mukulmishra18](https://github.com/mukulmishra18)! 55 | - [PR #34](https://github.com/sendgrid/nodejs-http-client/pull/34): Add pull request template. Thanks to [@jeffgerlach](https://github.com/jeffgerlach)! 56 | - [PR #40](https://github.com/sendgrid/nodejs-http-client/pull/40): Add USAGE.md file. Thanks to [@Tonkpils](https://github.com/Tonkpils)! 57 | - [PR #20](https://github.com/sendgrid/nodejs-http-client/pull/20): Add badges and move logo to top. Thanks to [@annaelde](https://github.com/annaelde)! 58 | - [PR #18](https://github.com/sendgrid/nodejs-http-client/pull/18): Update .md files for SEO-ness. Thanks to [@jppferguson](https://github.com/jppferguson)! 59 | - [PR #14](https://github.com/sendgrid/nodejs-http-client/pull/14): Fix typos and grammar. Thanks to [@aaronang](https://github.com/aaronang)! 60 | - [PR #12](https://github.com/sendgrid/nodejs-http-client/pull/12): 📖 Added CODE_OF_CONDUCT.md. Thanks to [@derekkramer](https://github.com/derekkramer)! 61 | 62 | **Library - Feature** 63 | - [PR #15](https://github.com/sendgrid/nodejs-http-client/pull/15): Added maxSockets support. Thanks to [@andreicioban](https://github.com/andreicioban)! 64 | 65 | **Library - Fix** 66 | - [PR #29](https://github.com/sendgrid/nodejs-http-client/pull/29): update contributing.md - fix typo. Thanks to [@pushkyn](https://github.com/pushkyn)! 67 | - [PR #26](https://github.com/sendgrid/nodejs-http-client/pull/26): Fixed failing unit test. Thanks to [@iifeoluwa](https://github.com/iifeoluwa)! 68 | - [PR #24](https://github.com/sendgrid/nodejs-http-client/pull/24): update readme - added license and ToC, fix contribute links. Thanks to [@pushkyn](https://github.com/pushkyn)! 69 | 70 | ## [2.4.0] - 2017-07-14 71 | ### Added 72 | - Pull #8 73 | - Ability to optionally assign port for requests when calling client API 74 | - Thanks [Anand Patel](https://github.com/apat183)! 75 | 76 | ## [2.3.0] - 2016-10-12 77 | ### Added 78 | - Pull #6, Solves #5 79 | - Invoke the API callback with a mocked response upon Error 80 | - Thanks [Dan Foley](https://github.com/cantremember)! 81 | 82 | ## [2.2.2] - 2016-09-27 83 | ### Fixed 84 | - Fix GitHub URLs in package.json #4: https://github.com/sendgrid/sendgrid-nodejs/pull/4 85 | - Thanks [Guilherme Souza](https://github.com/sitegui)! 86 | 87 | ## [2.2.1] - 2016-06-15 88 | ### Fixed 89 | - Sending email with accents: https://github.com/sendgrid/sendgrid-nodejs/issues/239 90 | - Thanks [eaparango](https://github.com/eaparango)! 91 | 92 | ## [2.2.0] - 2016-06-10 93 | ### Added 94 | - Automatically add Content-Type: application/json when there is a request body 95 | 96 | ## [2.1.0] - 2016-06-08 97 | ### Added 98 | - Cleaner request object initialization 99 | - Ability to use http for testing 100 | 101 | ## [2.0.0] - 2016-06-06 102 | ### Changed 103 | - Made the Request and Response variables non-redundant. e.g. request.requestBody becomes request.body 104 | 105 | ## [1.0.1] - 2016-04-08 106 | ### Added 107 | - We are live! -------------------------------------------------------------------------------- /USE_CASES.md: -------------------------------------------------------------------------------- 1 | Following Document provides several use cases of how to make RESTful method calls for an http-client. Please [open an issue](https://github.com/sendgrid/nodejs-http-client/issues) or make a pull request for any use cases you would like us to document here. Thank you! 2 | 3 | # RESTful API Calls- 4 | 5 | - GET 6 | - POST 7 | - PATCH 8 | - PUT 9 | - DEL 10 | 11 | In the following examples, it assumed you have got your own unique Sendgrid API key. 12 | 13 | The Following Requests are made using Python. 14 | 15 | Please Import these libraries at the start of the program and install them using pip command if not already done before. 16 | 17 | ```python 18 | import sendgrid 19 | import json 20 | import os 21 | ``` 22 | 23 | Use your unique API key to complete the final setup for making calls. 24 | 25 | ```python 26 | sg = sendgrid.SendGridAPIClient(apikey=os.environ.get('SENDGRID_API_KEY')) 27 | ``` 28 | 29 | # GET Requests 30 | 31 | ### Retrieve all custom fields # 32 | ##### GET /contactdb/custom_fields # 33 | 34 | ```python 35 | response = sg.client.contactdb.custom_fields.get() 36 | print(response.status_code) 37 | print(response.body) 38 | print(response.headers) 39 | ``` 40 | 41 | ### Retrieve a Custom Field # 42 | ##### GET /contactdb/custom_fields/{custom_field_id} # 43 | 44 | ```python 45 | custom_field_id = "test_url_param" 46 | response = sg.client.contactdb.custom_fields._(custom_field_id).get() 47 | print(response.status_code) 48 | print(response.body) 49 | print(response.headers) 50 | ``` 51 | 52 | ### Retrieve all lists # 53 | ##### GET /contactdb/lists # 54 | 55 | ```python 56 | response = sg.client.contactdb.lists.get() 57 | print(response.status_code) 58 | print(response.body) 59 | print(response.headers) 60 | ``` 61 | 62 | ### Retrieve all recipients on a List # 63 | ##### GET /contactdb/lists/{list_id}/recipients # 64 | 65 | ```python 66 | params = {'page': 1, 'page_size': 1} 67 | list_id = "test_url_param" 68 | response = sg.client.contactdb.lists._(list_id).recipients.get(query_params=params) 69 | print(response.status_code) 70 | print(response.body) 71 | print(response.headers) 72 | ``` 73 | 74 | ### Retrieve recipients # 75 | ##### GET /contactdb/recipients # 76 | 77 | ```python 78 | params = {'page': 1, 'page_size': 1} 79 | response = sg.client.contactdb.recipients.get(query_params=params) 80 | print(response.status_code) 81 | print(response.body) 82 | print(response.headers) 83 | ``` 84 | 85 | ### Retrieve the count of billable recipients # 86 | ##### GET /contactdb/recipients/billable_count # 87 | 88 | ```python 89 | response = sg.client.contactdb.recipients.billable_count.get() 90 | print(response.status_code) 91 | print(response.body) 92 | print(response.headers) 93 | ``` 94 | 95 | ### Retrieve a Count of Recipients # 96 | ##### GET /contactdb/recipients/count # 97 | 98 | ```python 99 | response = sg.client.contactdb.recipients.count.get() 100 | print(response.status_code) 101 | print(response.body) 102 | print(response.headers) 103 | ``` 104 | 105 | ### Retrieve recipients matching search criteria # 106 | ##### GET /contactdb/recipients/search # 107 | 108 | ```python 109 | params = {'{field_name}': 'test_string'} 110 | response = sg.client.contactdb.recipients.search.get(query_params=params) 111 | print(response.status_code) 112 | print(response.body) 113 | print(response.headers) 114 | ``` 115 | 116 | ### Retrieve a single recipient # 117 | ##### GET /contactdb/recipients/{recipient_id} # 118 | 119 | ```python 120 | recipient_id = "test_url_param" 121 | response = sg.client.contactdb.recipients._(recipient_id).get() 122 | print(response.status_code) 123 | print(response.body) 124 | print(response.headers) 125 | ``` 126 | 127 | ### Retrieve the lists that a recipient is on # 128 | ##### GET /contactdb/recipients/{recipient_id}/lists # 129 | 130 | ```python 131 | recipient_id = "test_url_param" 132 | response = sg.client.contactdb.recipients._(recipient_id).lists.get() 133 | print(response.status_code) 134 | print(response.body) 135 | print(response.headers) 136 | ``` 137 | 138 | ### Retrieve reserved fields # 139 | ##### GET /contactdb/reserved_fields # 140 | 141 | ```python 142 | response = sg.client.contactdb.reserved_fields.get() 143 | print(response.status_code) 144 | print(response.body) 145 | print(response.headers) 146 | ``` 147 | 148 | ### Retrieve all segments # 149 | ##### GET /contactdb/segments # 150 | 151 | ```python 152 | response = sg.client.contactdb.segments.get() 153 | print(response.status_code) 154 | print(response.body) 155 | print(response.headers) 156 | ``` 157 | 158 | ### Retrieve a segment # 159 | ##### GET /contactdb/segments/{segment_id} # 160 | 161 | ```python 162 | params = {'segment_id': 1} 163 | segment_id = "test_url_param" 164 | response = sg.client.contactdb.segments._(segment_id).get(query_params=params) 165 | print(response.status_code) 166 | print(response.body) 167 | print(response.headers) 168 | ``` 169 | 170 | ### Retrieve recipients on a segment # 171 | ##### GET /contactdb/segments/{segment_id}/recipients # 172 | 173 | ```python 174 | params = {'page': 1, 'page_size': 1} 175 | segment_id = "test_url_param" 176 | response = sg.client.contactdb.segments._(segment_id).recipients.get(query_params=params) 177 | print(response.status_code) 178 | print(response.body) 179 | print(response.headers) 180 | ``` 181 | 182 | # POST Requests 183 | 184 | ### Create a Custom Field # 185 | ##### POST /contactdb/custom_fields # 186 | 187 | ```python 188 | data = { 189 | "name": "pet", 190 | "type": "text" 191 | } 192 | response = sg.client.contactdb.custom_fields.post(request_body=data) 193 | print(response.status_code) 194 | print(response.body) 195 | print(response.headers) 196 | ``` 197 | 198 | 199 | ### Create a List # 200 | ##### POST /contactdb/lists # 201 | 202 | ```python 203 | data = { 204 | "name": "your list name" 205 | } 206 | response = sg.client.contactdb.lists.post(request_body=data) 207 | print(response.status_code) 208 | print(response.body) 209 | print(response.headers) 210 | ``` 211 | 212 | ### Add a Single Recipient to a List # 213 | ##### POST /contactdb/lists/{list_id}/recipients/{recipient_id} # 214 | 215 | ```python 216 | list_id = "test_url_param" 217 | recipient_id = "test_url_param" 218 | response = sg.client.contactdb.lists._(list_id).recipients._(recipient_id).post() 219 | print(response.status_code) 220 | print(response.body) 221 | print(response.headers) 222 | ``` 223 | 224 | ### Add Multiple Recipients to a List # 225 | ##### POST /contactdb/lists/{list_id}/recipients # 226 | 227 | ```python 228 | data = [ 229 | "recipient_id1", 230 | "recipient_id2" 231 | ] 232 | list_id = "test_url_param" 233 | response = sg.client.contactdb.lists._(list_id).recipients.post(request_body=data) 234 | print(response.status_code) 235 | print(response.body) 236 | print(response.headers) 237 | ``` 238 | 239 | ### Create a Segment # 240 | ##### POST /contactdb/segments # 241 | 242 | ```python 243 | data = { 244 | "conditions": [ 245 | { 246 | "and_or": "", 247 | "field": "last_name", 248 | "operator": "eq", 249 | "value": "Miller" 250 | }, 251 | { 252 | "and_or": "and", 253 | "field": "last_clicked", 254 | "operator": "gt", 255 | "value": "01/02/2015" 256 | }, 257 | { 258 | "and_or": "or", 259 | "field": "clicks.campaign_identifier", 260 | "operator": "eq", 261 | "value": "513" 262 | } 263 | ], 264 | "list_id": 4, 265 | "name": "Last Name Miller" 266 | } 267 | response = sg.client.contactdb.segments.post(request_body=data) 268 | print(response.status_code) 269 | print(response.body) 270 | print(response.headers) 271 | ``` 272 | 273 | # PATCH Request 274 | 275 | ### Update a List # 276 | ##### PATCH /contactdb/lists/{list_id} # 277 | 278 | ```python 279 | data = { 280 | "name": "newlistname" 281 | } 282 | params = {'list_id': 1} 283 | list_id = "test_url_param" 284 | response = sg.client.contactdb.lists._(list_id).patch(request_body=data, query_params=params) 285 | print(response.status_code) 286 | print(response.body) 287 | print(response.headers) 288 | ``` 289 | 290 | ### Update Recipient # 291 | ##### PATCH /contactdb/recipients # 292 | 293 | ```python 294 | data = [ 295 | { 296 | "email": "jones@example.com", 297 | "first_name": "Guy", 298 | "last_name": "Jones" 299 | } 300 | ] 301 | response = sg.client.contactdb.recipients.patch(request_body=data) 302 | print(response.status_code) 303 | print(response.body) 304 | print(response.headers) 305 | ``` 306 | 307 | ### Update a segment # 308 | ##### PATCH /contactdb/segments/{segment_id} # 309 | 310 | ```python 311 | data = { 312 | "conditions": [ 313 | { 314 | "and_or": "", 315 | "field": "last_name", 316 | "operator": "eq", 317 | "value": "Miller" 318 | } 319 | ], 320 | "list_id": 5, 321 | "name": "The Millers" 322 | } 323 | params = {'segment_id': 'test_string'} 324 | segment_id = "test_url_param" 325 | response = sg.client.contactdb.segments._(segment_id).patch(request_body=data, query_params=params) 326 | print(response.status_code) 327 | print(response.body) 328 | print(response.headers) 329 | ``` 330 | 331 | # DELETE Request 332 | 333 | ### Delete a Custom Field # 334 | ##### DELETE /contactdb/custom_fields/{custom_field_id} # 335 | 336 | ```python 337 | custom_field_id = "test_url_param" 338 | response = sg.client.contactdb.custom_fields._(custom_field_id).delete() 339 | print(response.status_code) 340 | print(response.body) 341 | print(response.headers) 342 | ``` 343 | 344 | ### Delete a List # 345 | ##### DELETE /contactdb/lists/{list_id} # 346 | 347 | ```python 348 | params = {'delete_contacts': 'true'} 349 | list_id = "test_url_param" 350 | response = sg.client.contactdb.lists._(list_id).delete(query_params=params) 351 | print(response.status_code) 352 | print(response.body) 353 | print(response.headers) 354 | ``` 355 | 356 | ### Delete Multiple lists # 357 | ##### DELETE /contactdb/lists # 358 | 359 | ```python 360 | data = [ 361 | 1, 362 | 2, 363 | 3, 364 | 4 365 | ] 366 | response = sg.client.contactdb.lists.delete(request_body=data) 367 | print(response.status_code) 368 | print(response.body) 369 | print(response.headers) 370 | ``` 371 | 372 | ### Delete Recipient # 373 | ##### DELETE /contactdb/recipients # 374 | 375 | ```python 376 | data = [ 377 | "recipient_id1", 378 | "recipient_id2" 379 | ] 380 | response = sg.client.contactdb.recipients.delete(request_body=data) 381 | print(response.status_code) 382 | print(response.body) 383 | print(response.headers) 384 | ``` 385 | 386 | ### Delete a Recipient # 387 | ##### DELETE /contactdb/recipients/{recipient_id} # 388 | 389 | ```python 390 | recipient_id = "test_url_param" 391 | response = sg.client.contactdb.recipients._(recipient_id).delete() 392 | print(response.status_code) 393 | print(response.body) 394 | print(response.headers) 395 | ``` 396 | 397 | ### Delete a Single Recipient from a Single List # 398 | ##### DELETE /contactdb/lists/{list_id}/recipients/{recipient_id} # 399 | 400 | ```python 401 | params = {'recipient_id': 1, 'list_id': 1} 402 | list_id = "test_url_param" 403 | recipient_id = "test_url_param" 404 | response = sg.client.contactdb.lists._(list_id).recipients._(recipient_id).delete(query_params=params) 405 | print(response.status_code) 406 | print(response.body) 407 | print(response.headers) 408 | ``` 409 | 410 | ### Delete a segment # 411 | ##### DELETE /contactdb/segments/{segment_id} # 412 | 413 | ```python 414 | params = {'delete_contacts': 'true'} 415 | segment_id = "test_url_param" 416 | response = sg.client.contactdb.segments._(segment_id).delete(query_params=params) 417 | print(response.status_code) 418 | print(response.body) 419 | print(response.headers) 420 | ``` 421 | -------------------------------------------------------------------------------- /test/test.js: -------------------------------------------------------------------------------- 1 | var assert = require('chai').assert 2 | var nock = require('nock') 3 | var fs = require('fs') 4 | 5 | var TEST_HOST = 'https://api.test.com' 6 | 7 | var Client = require('../lib/client.js').Client 8 | var globalRequest = require('../lib/client.js').emptyRequest 9 | globalRequest.host = 'api.test.com' 10 | 11 | describe('Client', function () { 12 | var client = new Client(globalRequest) 13 | // Make sure the URL path is correctly formed when adding query parameters 14 | describe('#buildPath()', function () { 15 | it('should create a properly encoded URL', function (done) { 16 | nock(TEST_HOST) 17 | .get('/test') 18 | .query({limit: 100, offset: 0}) 19 | .reply(200, { 20 | message: 'Success' 21 | }) 22 | 23 | var requestGet = client.emptyRequest() 24 | requestGet.method = 'GET' 25 | requestGet.path = '/test' 26 | requestGet.queryParams['limit'] = 100 27 | requestGet.queryParams['offset'] = 0 28 | client.API(requestGet, function (response) { 29 | assert.equal(response.statusCode, '200', 'response.StatusCode equal 200') 30 | assert.equal(response.body, 31 | '{"message":"Success"}', 'response.body equal {"message":"Success"}') 32 | assert.equal(JSON.stringify(response.headers), 33 | '{"content-type":"application/json"}', 34 | 'response.headers equal {"content-type": "application/json"}') 35 | done() 36 | }) 37 | }) 38 | }) 39 | 40 | // Make ure the request object is created correctly when using all request parameters 41 | describe('#buildRequest()', function () { 42 | it('should create a valid request object', function (done) { 43 | nock(TEST_HOST) 44 | .post('/test') 45 | .query({limit: 100, offset: 0}) 46 | .reply(201, function (uri, requestBody) { 47 | var response = {} 48 | response.path = this.req.path 49 | response.headers = this.req.headers 50 | return response 51 | }) 52 | 53 | var requestBody = { 54 | 'test': 'Test Body' 55 | } 56 | var requestPost = client.emptyRequest() 57 | requestPost.method = 'POST' 58 | requestPost.path = '/test' 59 | requestPost.body = requestBody 60 | requestPost.queryParams['limit'] = 100 61 | requestPost.queryParams['offset'] = 0 62 | requestPost.headers['X-Test'] = 'test' 63 | client.API(requestPost, function (response) { 64 | assert.equal(response.statusCode, '201', 'response.StatusCode equal 200') 65 | assert.equal(JSON.parse(response.body).path, 66 | '/test?limit=100&offset=0', 67 | 'path equal to /test?limit=100&offset=0') 68 | assert.equal(JSON.stringify(JSON.parse(response.body).headers), 69 | '{"x-test":"test","content-length":20,"content-type":"application/json","host":"api.test.com"}', 70 | 'headers equal {"x-test":"test","content-length":20,"content-type":"application/json","host":"api.test.com"}') 71 | assert.equal(JSON.stringify(response.headers), 72 | '{"content-type":"application/json"}', 73 | 'response.headers equal {"content-type":"application/json"}') 74 | done() 75 | }) 76 | }) 77 | }) 78 | 79 | // Make sure all HTTP verbs are working 80 | describe('#API()', function () { 81 | it('should create a valid API call', function (done) { 82 | nock(TEST_HOST) 83 | .get('/test') 84 | .reply(200, { 85 | message: 'Success' 86 | }) 87 | var requestGet = client.emptyRequest() 88 | requestGet.method = 'GET' 89 | requestGet.path = '/test' 90 | client.API(requestGet, function (response) { 91 | assert.equal(response.statusCode, '200', 'response.StatusCode equal 200') 92 | assert.equal(response.body, '{"message":"Success"}', 93 | 'response.body equal {"message":"Success"}') 94 | assert.equal(JSON.stringify(response.headers), 95 | '{"content-type":"application/json"}', 96 | 'response.headers equal {"content-type":"application/json"}') 97 | }) 98 | 99 | nock(TEST_HOST) 100 | .post('/test') 101 | .reply(201, { 102 | message: 'Success' 103 | }) 104 | var requestBody = { 105 | 'test': 'Test Body' 106 | } 107 | var requestPost = client.emptyRequest() 108 | requestPost.body = requestBody 109 | requestPost.method = 'POST' 110 | requestPost.path = '/test' 111 | client.API(requestPost, function (response) { 112 | assert.equal(response.statusCode, '201', 'response.StatusCode equal 201') 113 | assert.equal(response.body, '{"message":"Success"}', 114 | 'response.body equal {"message":"Success"}') 115 | assert.equal(JSON.stringify(response.headers), 116 | '{"content-type":"application/json"}', 117 | 'response.headers equal {"content-type":"application/json"}') 118 | }) 119 | nock(TEST_HOST) 120 | .patch('/test') 121 | .reply(200, { 122 | message: 'Success' 123 | }) 124 | var requestPatch = client.emptyRequest() 125 | requestPatch.body = requestBody 126 | requestPatch.method = 'PATCH' 127 | requestPatch.path = '/test' 128 | client.API(requestPatch, function (response) { 129 | assert.equal(response.statusCode, '200', 'response.StatusCode equal 200') 130 | assert.equal(response.body, '{"message":"Success"}', 131 | 'response.body equal {"message":"Success"}') 132 | assert.equal(JSON.stringify(response.headers), 133 | '{"content-type":"application/json"}', 134 | 'response.headers equal {"content-type":"application/json"}') 135 | }) 136 | 137 | nock(TEST_HOST) 138 | .put('/test') 139 | .reply(200, { 140 | message: 'Success' 141 | }) 142 | var requestPut = client.emptyRequest() 143 | requestPut.body = requestBody 144 | requestPut.method = 'PUT' 145 | requestPut.path = '/test' 146 | client.API(requestPut, function (response) { 147 | assert.equal(response.statusCode, '200', 'response.StatusCode equal 200') 148 | assert.equal(response.body, '{"message":"Success"}', 149 | 'response.body equal {"message":"Success"}') 150 | assert.equal(JSON.stringify(response.headers), 151 | '{"content-type":"application/json"}', 152 | 'response.headers equal {"content-type":"application/json"}') 153 | }) 154 | 155 | nock(TEST_HOST) 156 | .delete('/test') 157 | .reply(204, { 158 | message: 'Success' 159 | }) 160 | var requestDelete = client.emptyRequest() 161 | requestDelete.method = 'DELETE' 162 | requestDelete.path = '/test' 163 | client.API(requestDelete, function (response) { 164 | assert.equal(response.statusCode, '204', 'response.StatusCode equal 204') 165 | assert.equal(response.body, '{"message":"Success"}', 166 | 'response.body equal {"message":"Success"}') 167 | assert.equal(JSON.stringify(response.headers), 168 | '{"content-type":"application/json"}', 169 | 'response.headers equal {"content-type":"application/json"}') 170 | }) 171 | done() 172 | }) 173 | 174 | it('should consider non-HTTP-200 repsonses to be valid', function (done) { 175 | nock(TEST_HOST) 176 | .get('/test') 177 | .delay(100) // it('should wait for the response before invoking the callback') 178 | .reply(503) 179 | var requestGet = client.emptyRequest() 180 | requestGet.method = 'GET' 181 | requestGet.path = '/test' 182 | client.API(requestGet, function (response) { 183 | assert.equal(response.statusCode, '503', 'response.StatusCode equal 503') 184 | assert.equal(response.body, '', 185 | 'response.body blank') 186 | assert.equal(JSON.stringify(response.headers), 187 | '{}', 188 | 'response.headers blank') 189 | done() 190 | }) 191 | }) 192 | 193 | it('should respond with a mock HTTP 500 response upon Error', function (done) { 194 | nock(TEST_HOST) 195 | .get('/test') 196 | .replyWithError('ERROR') 197 | var requestGet = client.emptyRequest() 198 | requestGet.method = 'GET' 199 | requestGet.path = '/test' 200 | client.API(requestGet, function (response) { 201 | assert.equal(response.statusCode, '500', 'response.StatusCode equal 500') 202 | var body = JSON.parse(response.body) 203 | assert.equal(body.message, 'ERROR', 'response.body.message equal ERROR') 204 | assert.equal(body.name, Error.name, 'response.body.name equal Error.name') 205 | assert.equal(typeof body.stack, 'string', 'response.body.stack is a String') 206 | assert.equal(JSON.stringify(response.headers), 207 | '{}', 208 | 'response.headers blank') 209 | done() 210 | }) 211 | }) 212 | }) 213 | 214 | // limit maxSockets 215 | describe('#API()', function () { 216 | it('should limit maxSockets', function (done) { 217 | var expectedSockets = 10 218 | var maxSocketsClient = new Client(globalRequest, expectedSockets) 219 | 220 | nock(TEST_HOST) 221 | .get('/testMax') 222 | .reply(200) 223 | 224 | // monkey patch the http.request 225 | var http = require('http') 226 | var originalRequest = http.request 227 | http.request = function(options, callback){ 228 | assert.isDefined(options.agent, 'the request should use a custom agent'); 229 | assert.equal(options.agent.maxSockets, expectedSockets, 'agent.maxSockets should equal expectedSockets') 230 | return originalRequest(options, callback) 231 | } 232 | 233 | var requestGet = maxSocketsClient.emptyRequest() 234 | requestGet.method = 'GET' 235 | requestGet.test = true 236 | requestGet.path = '/testMax' 237 | maxSocketsClient.API(requestGet, function (response) { 238 | //restore the opriginal request 239 | http.request = originalRequest 240 | done() 241 | }) 242 | }) 243 | }) 244 | }) 245 | 246 | describe('nodejs-http-client repo', function() { 247 | it('should have ./Dockerfile or docker/Dockerfile', function() { 248 | assert(fileExists('Dockerfile') || fileExists('docker/Dockerfile')); 249 | }); 250 | 251 | it('should have ./docker-compose.yml or ./docker/docker-compose.yml file', function() { 252 | assert(fileExists('docker-compose.yml') || fileExists('docker/docker-compose.yml')); 253 | }); 254 | 255 | it('should have ./.env_sample file', function() { 256 | assert(fileExists('.env_sample')); 257 | }); 258 | 259 | it('should have ./.gitignore file', function() { 260 | assert(fileExists('.gitignore')); 261 | }); 262 | 263 | it('should have ./.travis.yml file', function() { 264 | assert(fileExists('.travis.yml')); 265 | }); 266 | 267 | it('should have ./.codeclimate.yml file', function() { 268 | assert(fileExists('.codeclimate.yml')); 269 | }); 270 | 271 | it('should have ./CHANGELOG.md file', function() { 272 | assert(fileExists('CHANGELOG.md')); 273 | }); 274 | 275 | it('should have ./CODE_OF_CONDUCT.md file', function() { 276 | assert(fileExists('CODE_OF_CONDUCT.md')); 277 | }); 278 | 279 | it('should have ./CONTRIBUTING.md file', function() { 280 | assert(fileExists('CONTRIBUTING.md')); 281 | }); 282 | 283 | it('should have ./ISSUE_TEMPLATE.md file', function() { 284 | assert(fileExists('ISSUE_TEMPLATE.md')); 285 | }); 286 | 287 | it('should have ./LICENSE.md file', function() { 288 | assert(fileExists('LICENSE.md')); 289 | }); 290 | 291 | it('should have ./PULL_REQUEST_TEMPLATE.md file', function() { 292 | assert(fileExists('PULL_REQUEST_TEMPLATE.md')); 293 | }); 294 | 295 | it('should have ./README.md file', function() { 296 | assert(fileExists('README.md')); 297 | }); 298 | 299 | it('should have ./TROUBLESHOOTING.md file', function() { 300 | assert(fileExists('TROUBLESHOOTING.md')); 301 | }); 302 | 303 | it('should have ./USAGE.md file', function() { 304 | assert(fileExists('USAGE.md')); 305 | }); 306 | 307 | it('should have ./USE_CASES.md file', function() { 308 | assert(fileExists('USE_CASES.md')); 309 | }); 310 | 311 | function fileExists(filepath) { 312 | try { 313 | return fs.statSync(filepath).isFile(); 314 | } catch(e) { 315 | if (e.code === 'ENOENT') { 316 | console.log('' + filepath + ' doesn\'t exist.'); 317 | return false; 318 | } 319 | throw e; 320 | } 321 | } 322 | }) 323 | 324 | describe('LICENSE', function() { 325 | it('should have correct year', function(done) { 326 | var licenseFile = fs.readFileSync('LICENSE.md', 'utf8'); 327 | var licenseYear = licenseFile.split('\n')[2].split(/[ ,]/)[2]; 328 | var thisYear = (new Date()).getFullYear(); 329 | 330 | if (licenseYear != thisYear) { 331 | assert.fail(thisYear, licenseYear, "LICENSE year is not correct") 332 | } else { 333 | done() 334 | } 335 | }) 336 | }); 337 | --------------------------------------------------------------------------------