From 573ddd8d07a5ea291d5f617712eed944545c70a7 Mon Sep 17 00:00:00 2001 From: Joost de Bruijn Date: Fri, 29 Dec 2023 19:59:48 +0000 Subject: [PATCH] wip: v2 --- README.md | 3 -- lib/requestApi.js | 70 +++++++++++++++--------------------- package-lock.json | 75 ++++++++++++++++++++++++--------------- package.json | 3 +- test/global.requestApi.js | 62 ++++++++++---------------------- 5 files changed, 96 insertions(+), 117 deletions(-) diff --git a/README.md b/README.md index e54025c..407a921 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,4 @@ # node-postcode-nl - -[![npm version](https://badge.fury.io/js/postcode-nl.svg)](https://badge.fury.io/js/postcode-nl) [![Build Status](https://travis-ci.org/joostdebruijn/node-postcode-nl.svg?branch=master)](https://travis-ci.org/joostdebruijn/node-postcode-nl) [![Coverage Status](https://coveralls.io/repos/github/joostdebruijn/node-postcode-nl/badge.svg?branch=master)](https://coveralls.io/github/joostdebruijn/node-postcode-nl?branch=master) [![dependencies Status](https://david-dm.org/joostdebruijn/node-postcode-nl/status.svg)](https://david-dm.org/joostdebruijn/node-postcode-nl) [![Known Vulnerabilities](https://snyk.io/test/github/joostdebruijn/node-postcode-nl/badge.svg)](https://snyk.io/test/github/joostdebruijn/node-postcode-nl) - Node module to obtain Dutch postcodes via [postcodeapi.nu](https://www.postcodeapi.nu). The module is able to perform requests to the v2 API, does some basic validation before the call is performed, handles errors from the API and returns the results as a json for further processing within your own application. To use this module, requesting an API-key at postcodeapi.nu is required. ## Using the module diff --git a/lib/requestApi.js b/lib/requestApi.js index 68287ec..739eb63 100644 --- a/lib/requestApi.js +++ b/lib/requestApi.js @@ -21,54 +21,40 @@ const helpers = require('./helpers.js') * @returns {Function} callback */ async function get (options, callback) { - // Preparing options for request - const requestOptions = { - url: options.url, - headers: options.headers, - json: true, - qs: options.qs || {} + const url = new URL(options.url) + + if (options.qs) { + for (const [key, value] of Object.entries(options.qs)) { + url.searchParams.set(key, value) + } } - /** - * This is the callback invoked by the request module, it follows it's parameters - * @callback requestCallback - * @private - * @since 1.1.0 - * @param {Error} error - Error object from request - * @param {Object} response - Response object from request - * @param {Object} body - Body object from request - * @returns {Function} callback - */ - function requestCallback (error, response, body) { - if (!error) { - // If requested, prepare rateLimit statistics from response - let rateLimit - if (options.returnRateLimit === true) { - rateLimit = { - limit: response.headers['x-ratelimit-limit'], - remaining: response.headers['x-ratelimit-remaining'] - } - } + if (!options.headers) { + options.headers = {} + } + + options.headers.Accept = 'application/json' - switch (response.statusCode) { - // Response received without errors - case 200: - return callback(null, body, rateLimit) - // No response received - case 404: - return callback(null, null) - // In other cases, there is some kind of an error or unexpected return - default: - helpers.handleOtherResponses(response, body, callback) + const res = await fetch(options.url, { + headers: options.headers + }) + + if (res.ok) { + // If requested, prepare rateLimit statistics from response + let rateLimit + if (options.returnRateLimit === true) { + rateLimit = { + limit: res.headers['x-ratelimit-limit'], + remaining: res.headers['x-ratelimit-remaining'] } - } else { - // There was an error with the request-module - return callback(new Error(error), null) } - } - // Executing API-request - request.get(requestOptions, requestCallback) + const body = await res.json() + + return callback(null, body, rateLimit) + } else { + return callback(new Error(`Something went wrong executing the request, statuscode: ${res.status}`), null) + } } exports.get = get diff --git a/package-lock.json b/package-lock.json index 92f1c12..851764c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,11 +9,12 @@ "version": "1.7.0", "license": "MIT", "devDependencies": { - "chai": "^5.0.0", + "chai": "^4.2.0", "minami": "^1.2.3", "mocha": "^10.2.0", "nyc": "^15.1.0", "sinon": "^17.0.1", + "sinon-chai": "^3.3.0", "standard": "^17.1.0" }, "engines": { @@ -1118,12 +1119,12 @@ } }, "node_modules/assertion-error": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", - "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", "dev": true, "engines": { - "node": ">=12" + "node": "*" } }, "node_modules/asynciterator.prototype": { @@ -1331,19 +1332,21 @@ ] }, "node_modules/chai": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/chai/-/chai-5.0.0.tgz", - "integrity": "sha512-HO5p0oEKd5M6HEcwOkNAThAE3j960vIZvVcc0t2tI06Dd0ATu69cEnMB2wOhC5/ZyQ6m67w3ePjU/HzXsSsdBA==", + "version": "4.3.10", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.10.tgz", + "integrity": "sha512-0UXG04VuVbruMUYbJ6JctvH0YnC/4q3/AkT18q4NaITo91CUm0liMS9VqzT9vZhVQ/1eqPanMWjBM+Juhfb/9g==", "dev": true, "dependencies": { - "assertion-error": "^2.0.1", - "check-error": "^2.0.0", - "deep-eql": "^5.0.1", - "loupe": "^3.0.0", - "pathval": "^2.0.0" + "assertion-error": "^1.1.0", + "check-error": "^1.0.3", + "deep-eql": "^4.1.3", + "get-func-name": "^2.0.2", + "loupe": "^2.3.6", + "pathval": "^1.1.1", + "type-detect": "^4.0.8" }, "engines": { - "node": ">=12" + "node": ">=4" } }, "node_modules/chalk": { @@ -1375,12 +1378,15 @@ } }, "node_modules/check-error": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.0.0.tgz", - "integrity": "sha512-tjLAOBHKVxtPoHe/SA7kNOMvhCRdCJ3vETdeY0RuAc9popf+hyaSV6ZEg9hr4cpWF7jmo/JSWEnLDrnijS9Tog==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz", + "integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==", "dev": true, + "dependencies": { + "get-func-name": "^2.0.2" + }, "engines": { - "node": ">= 16" + "node": "*" } }, "node_modules/chokidar": { @@ -1513,10 +1519,13 @@ } }, "node_modules/deep-eql": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.1.tgz", - "integrity": "sha512-nwQCf6ne2gez3o1MxWifqkciwt0zhl0LO1/UwVu4uMBuPmflWM4oQ70XMqHqnBJA+nhzncaqL9HVL6KkHJ28lw==", + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz", + "integrity": "sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==", "dev": true, + "dependencies": { + "type-detect": "^4.0.0" + }, "engines": { "node": ">=6" } @@ -3748,9 +3757,9 @@ } }, "node_modules/loupe": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.0.1.tgz", - "integrity": "sha512-phbaE2fPsRe8cQ7Cy5Ze5p9JLmpiaqGT45RCUWYYjZgYPBoeC3vqrlYPj4BQ82ln60ZtM3Iq00PPC3FyUdS4Kw==", + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz", + "integrity": "sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==", "dev": true, "dependencies": { "get-func-name": "^2.0.1" @@ -4375,12 +4384,12 @@ } }, "node_modules/pathval": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.0.tgz", - "integrity": "sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", + "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", "dev": true, "engines": { - "node": ">= 14.16" + "node": "*" } }, "node_modules/picocolors": { @@ -4956,6 +4965,16 @@ "url": "https://opencollective.com/sinon" } }, + "node_modules/sinon-chai": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/sinon-chai/-/sinon-chai-3.7.0.tgz", + "integrity": "sha512-mf5NURdUaSdnatJx3uhoBOrY9dtL19fiOtAdT1Azxg3+lNJFiuN0uzaU3xX1LeAfL17kHQhTAJgpsfhbMJMY2g==", + "dev": true, + "peerDependencies": { + "chai": "^4.0.0", + "sinon": ">=4.0.0" + } + }, "node_modules/sinon/node_modules/diff": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/diff/-/diff-5.1.0.tgz", diff --git a/package.json b/package.json index bbe2790..aa2060c 100644 --- a/package.json +++ b/package.json @@ -24,11 +24,12 @@ }, "homepage": "https://github.com/joostdebruijn/node-postcode-nl#readme", "devDependencies": { - "chai": "^5.0.0", + "chai": "^4.2.0", "minami": "^1.2.3", "mocha": "^10.2.0", "nyc": "^15.1.0", "sinon": "^17.0.1", + "sinon-chai": "^3.3.0", "standard": "^17.1.0" }, "engines": { diff --git a/test/global.requestApi.js b/test/global.requestApi.js index c5876fc..1b27bea 100644 --- a/test/global.requestApi.js +++ b/test/global.requestApi.js @@ -2,10 +2,21 @@ const sinon = require('sinon') const chai = require('chai') const sinonChai = require('sinon-chai') -const request = require('request') const requestApi = require('../lib/requestApi.js') const expect = chai.expect +function fakeResponse (status = 200) { + const mockResponse = new window.Response(JSON.stringify({}), { + status, + headers: { + 'Content-type': 'application/json' + } + }); + + return Promise.resolve(mockResponse); +} + + before(() => { chai.use(sinonChai) }) @@ -34,9 +45,8 @@ describe('global/requestApi()', () => { json: true, qs: {} } - const requestStub = sandbox.stub(request, 'get').callsFake((options, callback) => { - callback(null, { statusCode: 200 }, 'test') - }) + const requestStub = sandbox.stub(window, 'fetch') + requestStub.onCall(0).returns(fakeResponse()) return requestApi.get(options, (error, body, rateLimit) => { expect(error).to.eql(null) @@ -62,50 +72,16 @@ describe('global/requestApi()', () => { remaining: response.headers['x-ratelimit-remaining'] } - sandbox.stub(request, 'get').callsFake((options, callback) => { - callback(null, response, null) - }) + const requestStub = sandbox.stub(window, 'fetch') + requestStub.onCall(0).returns(fakeResponse()) return requestApi.get(options, (error, body, rateLimit) => { expect(rateLimit).to.eql(rateLimitReturn) }) }) - it('should return null if a 404 was responded by the API', () => { - // Setting up the test data - const response = { - statusCode: 404 - } - - sandbox.stub(request, 'get').callsFake((options, callback) => { - callback(null, response, null) - }) - - return requestApi.get({}, (error, body, rateLimit) => { - expect(error).to.eql(null) - expect(body).to.eql(null) - expect(rateLimit).to.eql(undefined) - }) - }) - it('should return a error when the statusCode is not 200 or 404', () => { - // Setting up the test data - const response = { - statusCode: 403 - } - - sandbox.stub(request, 'get').callsFake((options, callback) => { - callback(null, response, null) - }) - - return requestApi.get({}, (error, body, rateLimit) => { - expect(error).to.instanceof(Error) - expect(body).to.eql(null) - expect(rateLimit).to.eql(undefined) - }) - }) - it('should be able to handle errors from the request module and pass them through', () => { - sandbox.stub(request, 'get').callsFake((options, callback) => { - callback(new Error(''), null, null) - }) + it('should return a error when the statusCode is not ok', () => { + const requestStub = sandbox.stub(window, 'fetch') + requestStub.onCall(0).returns(fakeResponse(403)) return requestApi.get({}, (error, body, rateLimit) => { expect(error).to.instanceof(Error)