@openaddresses/batch-schema 7.6.0 → 8.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -10,6 +10,14 @@
10
10
 
11
11
  ## Version History
12
12
 
13
+ ### v8.0.0
14
+
15
+ - :data: Remove APIDoc support in favour of OpenAPI Route
16
+
17
+ ### v7.6.1
18
+
19
+ - :bug: Explicit AJV strict: false
20
+
13
21
  ### v7.6.0
14
22
 
15
23
  - :tada: Update Core Deps
package/README.md CHANGED
@@ -4,12 +4,6 @@
4
4
 
5
5
  ## Installation
6
6
 
7
- ```sh
8
- yarn add @openaddresses/batch-schema
9
- ```
10
-
11
- or
12
-
13
7
  ```sh
14
8
  npm i @openaddresses/batch-schema
15
9
  ```
@@ -75,6 +69,8 @@ Adds a route called `GET /schema` which allows the caller to get a list of endpo
75
69
  as well as full schema details for every route. If your API is public we recommend enabling this feature, however
76
70
  if you do not wish for API routes to be published, this feature is disabled unless called.
77
71
 
72
+ Adds a route called `GET /openapi` which returns an OpenAPI / Swagger JSON Object
73
+
78
74
  ### schema.not_found
79
75
 
80
76
  Adds a middlware which will catch all routes that have not been defined and return
package/lib/middleware.js CHANGED
@@ -6,6 +6,7 @@ import { ValidationError } from 'express-json-validator-middleware';
6
6
  import Generic from '@openaddresses/batch-generic';
7
7
 
8
8
  const ajv = addFormats(new Ajv({
9
+ strict: false,
9
10
  allErrors: true,
10
11
  removeAdditional: true
11
12
  }));
package/lib/openapi.js ADDED
@@ -0,0 +1,96 @@
1
+ /**
2
+ * @class
3
+ */
4
+ export default class Docs {
5
+ constructor(info) {
6
+ this.base = {
7
+ openapi: '3.0.3',
8
+ info: info || {
9
+ title: 'OpenAPI Schema',
10
+ version: '1.0.0'
11
+ },
12
+ paths: {}
13
+ };
14
+ }
15
+
16
+ push(parsed, schemas) {
17
+ let path = [];
18
+ const method = parsed[0].toLowerCase();
19
+
20
+ for (let sec of parsed[1].split('/')) {
21
+ for (const lit of ['.', '-']) { // These chars are used literally and can't be part of a param name
22
+ const mini = [];
23
+ for (const s of sec.split(lit)) {
24
+ if (s[0] === ':') mini.push(`{${s}}`);
25
+ else mini.push(s);
26
+ }
27
+ sec = mini.join(lit);
28
+ }
29
+ path.push(sec);
30
+ }
31
+ path = path.join('/');
32
+
33
+
34
+ if (!this.base.paths[path]) this.base.paths[path] = {};
35
+
36
+ if (this.base.paths[path][method]) throw new Error(`Duplicate Path: ${parsed.join(' ')}`);
37
+
38
+ const document = {
39
+ summary: schemas.description || 'No Description',
40
+ tags: [schemas.group || 'Default'],
41
+ parameters: [],
42
+ responses: {
43
+ 200: {
44
+ description: 'Successful Response'
45
+ }
46
+ }
47
+ };
48
+
49
+ for (const key in schemas) {
50
+ if (key[0] === ':') {
51
+ document.parameters.push({
52
+ in: 'path',
53
+ name: key,
54
+ schema: {
55
+ type: schemas[key]
56
+ },
57
+ required: true
58
+ });
59
+ }
60
+ }
61
+
62
+ if (schemas.query && schemas.query.type === 'object') {
63
+ for (const name in (schemas.query.properties || {})) {
64
+ const query = schemas.query.properties[name];
65
+ document.parameters.push({
66
+ in: 'query',
67
+ name,
68
+ schema: query,
69
+ required: query.required || (schemas.query.required || []).includes(name),
70
+ description: query.description || 'No Description'
71
+ });
72
+ }
73
+ }
74
+
75
+ if (schemas.res) {
76
+ document.responses['200'].content = {
77
+ 'application/json': {
78
+ schema: schemas.res
79
+ }
80
+ };
81
+ }
82
+
83
+ if (schemas.body) {
84
+ document.requestBody = {
85
+ required: true,
86
+ content: {
87
+ 'application/json': {
88
+ schema: schemas.body
89
+ }
90
+ }
91
+ };
92
+ }
93
+
94
+ this.base.paths[path][method] = document;
95
+ }
96
+ }
package/lib/schema.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { Validator } from 'express-json-validator-middleware';
2
- import $RefParser from 'json-schema-ref-parser';
2
+ import $RefParser from '@apidevtools/json-schema-ref-parser';
3
3
  import fs from 'fs';
4
4
  import path from 'path';
5
5
  import morgan from 'morgan';
@@ -7,7 +7,7 @@ import bodyparser from 'body-parser';
7
7
 
8
8
  import SchemaRoute from '../routes/schema.js';
9
9
  import Param from './param.js';
10
- import Docs from './docs.js';
10
+ import Docs from './openapi.js';
11
11
  import Middleware from './middleware.js';
12
12
 
13
13
  /**
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "type": "module",
4
4
  "root": true,
5
5
  "main": "index.js",
6
- "version": "7.6.0",
6
+ "version": "8.0.0",
7
7
  "description": "Strongly Validated JSON Schema support for address",
8
8
  "repository": "git@github.com:openaddresses/batch-schema",
9
9
  "author": "ingalls <nick@ingalls.ca>",
@@ -18,23 +18,23 @@
18
18
  "doc": "documentation build index.js -f html -o docs && documentation lint index.js"
19
19
  },
20
20
  "dependencies": {
21
+ "@apidevtools/json-schema-ref-parser": "^10.0.0",
21
22
  "@openaddresses/batch-error": "^2.1.2",
22
23
  "ajv": "^8.6.3",
23
24
  "ajv-formats": "^2.1.1",
24
25
  "body-parser": "^1.20.0",
25
26
  "express": "^4.17.1",
26
27
  "express-json-validator-middleware": "^3.0.0",
27
- "glob": "^8.0.0",
28
- "json-schema-ref-parser": "^9.0.9",
29
- "morgan": "^1.10.0",
30
- "tape": "^5.3.1"
28
+ "glob": "^9.0.0",
29
+ "morgan": "^1.10.0"
31
30
  },
32
31
  "peerDependencies": {
33
32
  "@openaddresses/batch-generic": "x.x.x"
34
33
  },
35
34
  "devDependencies": {
36
- "documentation": "^13.2.5",
35
+ "documentation": "^14.0.1",
37
36
  "eslint": "^8.0.1",
38
- "eslint-plugin-node": "^11.0.0"
37
+ "eslint-plugin-node": "^11.0.0",
38
+ "tape": "^5.3.1"
39
39
  }
40
40
  }
package/routes/schema.js CHANGED
@@ -1,26 +1,16 @@
1
1
  import Err from '@openaddresses/batch-error';
2
2
 
3
3
  export default async function router(schema) {
4
- /**
5
- * @api {get} /api/schema List Schemas
6
- * @apiVersion 1.0.0
7
- * @apiName ListSchemas
8
- * @apiGroup Schemas
9
- * @apiPermission public
10
- *
11
- * @apiDescription
12
- * List all JSON Schemas in use
13
- * With no parameters this API will return a list of all the endpoints that have a form of schema validation
14
- * If the url/method params are used, the schemas themselves are returned
15
- *
16
- * Note: If url or method params are used, they must be used together
17
- *
18
- * @apiSchema (Query) {jsonschema=../schema/req.query.ListSchema.json} apiParam
19
- * @apiSchema {jsonschema=../schema/res.ListSchema.json} apiSuccess
20
- */
21
4
  await schema.get('/schema', {
22
5
  query: 'req.query.ListSchema.json',
23
- res: 'res.ListSchema.json'
6
+ res: 'res.ListSchema.json',
7
+ description: `
8
+ List all JSON Schemas in use
9
+ With no parameters this API will return a list of all the endpoints that have a form of schema validation
10
+ If the url/method params are used, the schemas themselves are returned
11
+
12
+ Note: If url or method params are used, they must be used together
13
+ `
24
14
  }, async (req, res) => {
25
15
  try {
26
16
  if (req.query.url && req.query.method) {
@@ -34,4 +24,14 @@ export default async function router(schema) {
34
24
  return Err.respond(err, res);
35
25
  }
36
26
  });
27
+
28
+ await schema.get('/openapi', {
29
+ description: 'Return a OpenAPI Schema for the API'
30
+ }, async (req, res) => {
31
+ try {
32
+ return res.json(schema.docs.base);
33
+ } catch (err) {
34
+ return Err.respond(err, res);
35
+ }
36
+ });
37
37
  }
@@ -31,6 +31,11 @@ test('GET: api/schema', async (t) => {
31
31
  body: false,
32
32
  query: true,
33
33
  res: true
34
+ },
35
+ 'GET /openapi': {
36
+ body: false,
37
+ query: false,
38
+ res: false
34
39
  }
35
40
  });
36
41
  } catch (err) {
@@ -3,7 +3,7 @@ import path from 'path';
3
3
  import test from 'tape';
4
4
 
5
5
  import glob from 'glob';
6
- import $RefParser from 'json-schema-ref-parser';
6
+ import $RefParser from '@apidevtools/json-schema-ref-parser';
7
7
  import Ajv from 'ajv';
8
8
 
9
9
  const ajv = new Ajv({
package/lib/docs.js DELETED
@@ -1,36 +0,0 @@
1
- /**
2
- * @class Docs
3
- */
4
- export default class Docs extends Array {
5
- push(parsed, schemas) {
6
- const apiParams = [];
7
- for (const key in schemas) {
8
- if (key[0] === ':') {
9
- apiParams.push(`* @apiParam {${schemas[key]}} ${key.slice(1)} param`);
10
- }
11
- }
12
-
13
- super.push(
14
- `
15
- /**
16
- * @api {${parsed[0].toLowerCase()}} ${parsed[1]} ${schemas.name || parsed.join(' ')}
17
- * @apiVersion ${schemas.version || '1.0.0'}
18
- * @apiName ${parsed.join('-')}
19
- * @apiGroup ${schemas.group || 'Default'}
20
- * @apiPermission ${schemas.auth || 'Unknown'}
21
- *
22
- * @apidescription
23
- * ${schemas.description || 'No Description'}
24
- *
25
- ${apiParams.join('\n')}
26
- *
27
- * ${schemas.query_url ? `@apiSchema (Query) {jsonschema=${schemas.query_url}} apiParam` : ''}
28
- * ${schemas.body_url ? `@apiSchema (Body) {jsonschema=${schemas.body_url}} apiParam` : ''}
29
- * ${schemas.res_url ? `@apiSchema {jsonschema=${schemas.res_url}} apiSuccess` : ''}
30
- */
31
- `.split('\n')
32
- .map((l) => l.trim())
33
- .join('\n')
34
- );
35
- }
36
- }