confluent-schema-registry 3.3.5 → 3.6.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. package/CHANGELOG.md +42 -1
  2. package/bin/avdlToAVSC.sh +1 -1
  3. package/dist/JsonSchema.js +1 -1
  4. package/dist/JsonSchema.js.map +1 -1
  5. package/dockest-error.json +3 -7
  6. package/jest.setup.ts +23 -13
  7. package/package.json +11 -17
  8. package/src/@types.ts +6 -13
  9. package/src/AvroHelper.ts +2 -3
  10. package/src/JsonSchema.ts +27 -15
  11. package/src/SchemaRegistry.json.spec.ts +18 -1
  12. package/src/SchemaRegistry.newApi.spec.ts +1 -1
  13. package/src/SchemaRegistry.spec.ts +15 -0
  14. package/src/SchemaRegistry.ts +16 -17
  15. package/src/api/index.spec.ts +24 -2
  16. package/src/api/index.ts +11 -2
  17. package/src/api/middleware/errorMiddleware.ts +1 -1
  18. package/src/constants.ts +1 -1
  19. package/src/index.ts +2 -1
  20. package/src/schemaTypeResolver.ts +2 -1
  21. package/src/utils/avdlToAVSC.spec.ts +28 -5
  22. package/src/utils/avdlToAVSC.ts +3 -3
  23. package/tmp/Array.avsc +22 -0
  24. package/tmp/Array1.avsc +28 -0
  25. package/tmp/Array2.avsc +17 -0
  26. package/tmp/Array3.avsc +17 -0
  27. package/tmp/ArrayUnion.avsc +23 -0
  28. package/tmp/Bam.avsc +9 -0
  29. package/tmp/Bar.avsc +46 -0
  30. package/tmp/Baz.avsc +39 -0
  31. package/tmp/Complex.avsc +81 -0
  32. package/tmp/Enum.avsc +13 -0
  33. package/tmp/EnumUnion.avsc +14 -0
  34. package/tmp/Foos.avsc +6 -0
  35. package/tmp/ImportMultipleNamespaces.avsc +35 -0
  36. package/tmp/KeyValue.avsc +12 -0
  37. package/tmp/Metadata.avsc +27 -0
  38. package/tmp/Multiple.avsc +26 -0
  39. package/tmp/MultipleNamespaces.avsc +44 -0
  40. package/tmp/MultipleUnion.avsc +28 -0
  41. package/tmp/Simple.avsc +9 -0
  42. package/tmp/Two.avsc +19 -0
  43. package/tmp/Union.avsc +20 -0
  44. package/dockest.ts +0 -30
package/CHANGELOG.md CHANGED
@@ -9,7 +9,48 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
9
9
 
10
10
  ### Added
11
11
 
12
- -field for error validation , and the issue of failing
12
+ - Support [schema references](https://docs.confluent.io/platform/current/schema-registry/serdes-develop/index.html#schema-references) for Avro, Protocol Buffer, and JSON schema [#197](https://github.com/kafkajs/confluent-schema-registry/pull/197)
13
+
14
+ ### Fixed
15
+
16
+ - Fix Apicurio compatibility with register function [#201](https://github.com/kafkajs/confluent-schema-registry/pull/201)
17
+
18
+ ## [3.2.1] - 2022-01-28
19
+
20
+ ### Fixed
21
+
22
+ - Don't swallow error message from client-side errors from registry requests [#176](https://github.com/kafkajs/confluent-schema-registry/pull/176)
23
+
24
+ ## [3.2.0] - 2021-11-22
25
+
26
+ ### Added
27
+
28
+ - Add reader schema option when decoding Avro messages [#166](https://github.com/kafkajs/confluent-schema-registry/pull/166)
29
+
30
+ ## [3.1.1] - 2021-11-03
31
+
32
+ ### Fixed
33
+
34
+ - Support backwards incompatible changes in Ajv 8 when passing in Ajv instance in JSON Schema options [#163](https://github.com/kafkajs/confluent-schema-registry/pull/163)
35
+
36
+ ## [3.1.0] - 2021-11-03
37
+
38
+ ### Added
39
+
40
+ - Allow passing in Ajv instance in JSON Schema options [#133](https://github.com/kafkajs/confluent-schema-registry/pull/133)
41
+
42
+ ### Fixed
43
+
44
+ - Fix backwards compatibility with older Schema Registry versions [#158](https://github.com/kafkajs/confluent-schema-registry/pull/158)
45
+
46
+ ### Fixed
47
+
48
+ - Fix gateway config for when setting HTTP agent [#127](https://github.com/kafkajs/confluent-schema-registry/pull/127)
49
+
50
+ ## [3.0.1] - 2021-06-11
51
+ ### Fixed
52
+
53
+ - Fix gateway config for when setting HTTP agent [#127](https://github.com/kafkajs/confluent-schema-registry/pull/127)
13
54
 
14
55
  ## [3.0.0] - 2021-05-20
15
56
 
package/bin/avdlToAVSC.sh CHANGED
@@ -6,4 +6,4 @@ if [ -z "${avdl_path}" ]; then
6
6
  exit;
7
7
  fi
8
8
 
9
- docker run --rm -v ${PWD}:/share coderfi/avro-tools:1.7.7 idl2schemata ${avdl_path} tmp && cat tmp/${avsc_name}.avsc
9
+ docker run --rm -v "$(pwd)":/avro kpnnl/avro-tools:1.12.0 idl2schemata ${avdl_path} tmp && cat tmp/${avsc_name}.avsc
@@ -42,7 +42,7 @@ class JsonSchema {
42
42
  if (opts === null || opts === void 0 ? void 0 : opts.errorHook) {
43
43
  for (const err of this.validate.errors) {
44
44
  const path = this.isOldAjvValidationError(err) ? err.dataPath : err.instancePath;
45
- opts === null || opts === void 0 ? void 0 : opts.errorHook([path], err.data, err.schema);
45
+ opts.errorHook([err], err.data, err.schema);
46
46
  }
47
47
  }
48
48
  return false;
@@ -1 +1 @@
1
- {"version":3,"file":"JsonSchema.js","sourceRoot":"","sources":["../src/JsonSchema.ts"],"names":[],"mappings":";;;;;AACA,8CAAqB;AACrB,qCAAiE;AAoBjE,MAAqB,UAAU;IAG7B,YAAY,MAA2B,EAAE,IAAkB;QACzD,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,aAAa,CAAC,MAAM,EAAE,IAAI,CAAC,CAAA;IAClD,CAAC;IAEO,aAAa,CAAC,MAA2B,EAAE,IAAkB;;QACnE,MAAM,GAAG,SAAG,IAAI,aAAJ,IAAI,uBAAJ,IAAI,CAAE,WAAW,mCAAI,IAAI,aAAG,CAAC,IAAI,CAAC,CAAA;QAC9C,MAAM,iBAAiB,GAAG,IAAI,aAAJ,IAAI,uBAAJ,IAAI,CAAE,iBAAiB,CAAA;QACjD,IAAI,iBAAiB,EAAE;YACrB,iBAAiB,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE;gBACpC,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,CAAA;gBAC5C,GAAG,CAAC,SAAS,CAAC,OAAO,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC,CAAA;YACxC,CAAC,CAAC,CAAA;SACH;QACD,MAAM,QAAQ,GAAG,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAA;QACvD,OAAO,QAAQ,CAAA;IACjB,CAAC;IAEO,eAAe,CAAC,OAAY;QAClC,MAAM,KAAK,GAAe,EAAE,CAAA;QAC5B,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE;YACnE,MAAM,IAAI,+CAAsC,CAAC,iBAAiB,EAAE,KAAK,CAAC,CAAA;SAC3E;IACH,CAAC;IAEM,QAAQ,CAAC,OAAe;QAC7B,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC,CAAA;QAC7B,OAAO,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAA;IAC7C,CAAC;IAEM,UAAU,CAAC,MAAc;QAC9B,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAA;QAC7C,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC,CAAA;QAC7B,OAAO,OAAO,CAAA;IAChB,CAAC;IACM,OAAO,CAAC,OAAe,EAAE,IAA2E;QACzG,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE;YAC3B,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,EAAE;gBAC9D,KAAK,MAAM,GAAG,IAAK,IAAI,CAAC,QAAQ,CAAC,MAAc,EAAE;oBAC/C,MAAM,IAAI,GAAG,IAAI,CAAC,uBAAuB,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,YAAY,CAAC;oBACjF,IAAI,aAAJ,IAAI,uBAAJ,IAAI,CAAE,SAAS,CAAC,CAAC,IAAI,CAAC,EAAE,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,MAAM,EAAE;iBAC/C;aACF;YACD,OAAO,KAAK,CAAC;SACd;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAEO,uBAAuB,CAAC,KAAyB;QACvD,OAAQ,KAA+B,CAAC,QAAQ,IAAI,IAAI,CAAA;IAC1D,CAAC;CACF;AArDD,6BAqDC"}
1
+ {"version":3,"file":"JsonSchema.js","sourceRoot":"","sources":["../src/JsonSchema.ts"],"names":[],"mappings":";;;;;AACA,8CAAqB;AACrB,qCAAiE;AAoBjE,MAAqB,UAAU;IAG7B,YAAY,MAA2B,EAAE,IAAkB;QACzD,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,aAAa,CAAC,MAAM,EAAE,IAAI,CAAC,CAAA;IAClD,CAAC;IAEO,aAAa,CAAC,MAA2B,EAAE,IAAkB;;QACnE,MAAM,GAAG,SAAG,IAAI,aAAJ,IAAI,uBAAJ,IAAI,CAAE,WAAW,mCAAI,IAAI,aAAG,CAAC,IAAI,CAAC,CAAA;QAC9C,MAAM,iBAAiB,GAAG,IAAI,aAAJ,IAAI,uBAAJ,IAAI,CAAE,iBAAiB,CAAA;QACjD,IAAI,iBAAiB,EAAE;YACrB,iBAAiB,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE;gBACpC,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,CAAA;gBAC5C,GAAG,CAAC,SAAS,CAAC,OAAO,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC,CAAA;YACxC,CAAC,CAAC,CAAA;SACH;QACD,MAAM,QAAQ,GAAG,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAA;QACvD,OAAO,QAAQ,CAAA;IACjB,CAAC;IAEO,eAAe,CAAC,OAAY;QAClC,MAAM,KAAK,GAAe,EAAE,CAAA;QAC5B,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE;YACnE,MAAM,IAAI,+CAAsC,CAAC,iBAAiB,EAAE,KAAK,CAAC,CAAA;SAC3E;IACH,CAAC;IAEM,QAAQ,CAAC,OAAe;QAC7B,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC,CAAA;QAC7B,OAAO,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAA;IAC7C,CAAC;IAEM,UAAU,CAAC,MAAc;QAC9B,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAA;QAC7C,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC,CAAA;QAC7B,OAAO,OAAO,CAAA;IAChB,CAAC;IACM,OAAO,CAAC,OAAe,EAAE,IAA2E;QACzG,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE;YAC3B,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,EAAE;gBAC9D,KAAK,MAAM,GAAG,IAAK,IAAI,CAAC,QAAQ,CAAC,MAAc,EAAE;oBAC/C,MAAM,IAAI,GAAG,IAAI,CAAC,uBAAuB,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,YAAY,CAAC;oBACjF,IAAI,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,EAAE,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;iBAC7C;aACF;YACD,OAAO,KAAK,CAAC;SACd;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAEO,uBAAuB,CAAC,KAAyB;QACvD,OAAQ,KAA+B,CAAC,QAAQ,IAAI,IAAI,CAAA;IAC1D,CAAC;CACF;AArDD,6BAqDC"}
@@ -1,11 +1,7 @@
1
1
  {
2
2
  "errorPayload": {
3
- "trap": "unhandledRejection",
4
- "reason": {
5
- "payload": {},
6
- "name": "DockestError"
7
- },
8
- "promise": {}
3
+ "trap": "SIGINT",
4
+ "signal": "SIGINT"
9
5
  },
10
- "timestamp": "2024-09-03T14:42:35.241Z"
6
+ "timestamp": "2024-12-18T22:39:59.117Z"
11
7
  }
package/jest.setup.ts CHANGED
@@ -1,8 +1,12 @@
1
1
  import { MAGIC_BYTE } from './src/wireEncoder'
2
2
  import decode from './src/wireDecoder'
3
+ import { MatcherFunction } from 'expect'
3
4
 
4
- const toMatchConfluentEncodedPayload = context => (received, { payload: expectedPayload }) => {
5
- const { printExpected, printReceived, printWithType } = context.utils
5
+ const toMatchConfluentEncodedPayload: MatcherFunction<[{ payload: Buffer }]> = function(
6
+ received,
7
+ { payload: expectedPayload },
8
+ ) {
9
+ const { printExpected, printReceived, printWithType } = this.utils
6
10
 
7
11
  if (!Buffer.isBuffer(expectedPayload)) {
8
12
  const error = [
@@ -13,16 +17,17 @@ const toMatchConfluentEncodedPayload = context => (received, { payload: expected
13
17
  throw new Error(error)
14
18
  }
15
19
 
16
- const { magicByte, payload } = decode(received)
20
+ const { magicByte, payload } = decode(received as Buffer)
17
21
  const expectedMessage = decode(expectedPayload)
18
22
 
19
23
  if (!Buffer.isBuffer(received)) {
20
24
  return {
21
25
  pass: false,
22
- message: () => [
23
- 'Received value must be a Buffer',
24
- printWithType('Received', received, printReceived),
25
- ],
26
+ message: () =>
27
+ [
28
+ 'Received value must be a Buffer',
29
+ printWithType('Received', received, printReceived),
30
+ ].join('\n'),
26
31
  }
27
32
  }
28
33
 
@@ -40,7 +45,7 @@ const toMatchConfluentEncodedPayload = context => (received, { payload: expected
40
45
  }
41
46
 
42
47
  return {
43
- pass: context.equals(payload, expectedMessage.payload),
48
+ pass: this.equals(payload, expectedMessage.payload),
44
49
  message: () =>
45
50
  [
46
51
  'expected payload',
@@ -52,9 +57,14 @@ const toMatchConfluentEncodedPayload = context => (received, { payload: expected
52
57
  }
53
58
 
54
59
  expect.extend({
55
- toMatchConfluentEncodedPayload(...args) {
56
- // eslint-disable-next-line @typescript-eslint/ban-ts-ignore
57
- // @ts-ignore
58
- return toMatchConfluentEncodedPayload(this)(...args)
59
- },
60
+ toMatchConfluentEncodedPayload,
60
61
  })
62
+
63
+ declare global {
64
+ // eslint-disable-next-line @typescript-eslint/no-namespace
65
+ namespace jest {
66
+ interface Matchers<R, T = {}> {
67
+ toMatchConfluentEncodedPayload(args: { registryId: number; payload: Buffer }): R
68
+ }
69
+ }
70
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "confluent-schema-registry",
3
- "version": "3.3.5",
3
+ "version": "3.6.2",
4
4
  "main": "dist/index.js",
5
5
  "description": "ConfluentSchemaRegistry is a library that makes it easier to interact with the Confluent schema registry, it provides convenient methods to encode, decode and register new schemas using the Apache Avro serialization format.",
6
6
  "keywords": [
@@ -17,40 +17,34 @@
17
17
  "build:watch": "rm -rf ./dist && tsc --watch",
18
18
  "test:unit:watch": "yarn test:unit --watch",
19
19
  "test:unit": "jest",
20
- "test": "ts-node ./dockest.ts",
21
- "test:debug": "ts-node ./dockest.ts debug",
20
+ "test": "docker compose up -d --wait schemaRegistry && jest",
22
21
  "lint": "eslint './src/**/*.ts'",
22
+ "check:types": "tsc --noEmit",
23
23
  "format": "yarn lint --fix"
24
24
  },
25
25
  "dependencies": {
26
26
  "ajv": "^7.1.0",
27
27
  "avsc": ">= 5.4.13 < 6",
28
- "mappersmith": ">= 2.30.1 < 3",
29
- "protobufjs": "^6.11.4"
28
+ "mappersmith": ">= 2.44.0 < 3",
29
+ "protobufjs": ">= 6.11.4 < 8"
30
30
  },
31
31
  "devDependencies": {
32
- "@types/execa": "^2.0.0",
33
- "@types/fs-extra": "^8.0.0",
34
- "@types/jest": "^25.2.1",
35
- "@types/node": "^12.7.3",
32
+ "@types/jest": "^29.5.14",
33
+ "@types/node": "^18.19.70",
36
34
  "@types/prettier": "^1.18.2",
37
- "@types/uuid": "^3.4.5",
38
35
  "@typescript-eslint/eslint-plugin": "^2.1.0",
39
36
  "@typescript-eslint/parser": "^2.1.0",
40
37
  "@typescript-eslint/typescript-estree": "^2.1.0",
41
38
  "ajv8": "npm:ajv@^8.6.3",
42
- "dockest": "^2.1.0",
43
39
  "eslint": "^6.3.0",
44
40
  "eslint-config-prettier": "^6.1.0",
45
41
  "eslint-plugin-no-only-tests": "^2.3.1",
46
42
  "eslint-plugin-prettier": "^3.1.0",
47
- "execa": "^2.0.4",
48
- "fs-extra": "^8.1.0",
49
- "jest": "^25.2.7",
43
+ "jest": "^29.7.0",
50
44
  "prettier": "^1.18.2",
51
- "ts-jest": "^24.0.2",
45
+ "ts-jest": "^29.2.5",
52
46
  "ts-node": "^8.3.0",
53
- "typescript": "^3.6.2",
54
- "uuid": "^3.3.3"
47
+ "typescript": "^5.7.3",
48
+ "uuid": "^11.0.5"
55
49
  }
56
50
  }
package/src/@types.ts CHANGED
@@ -23,10 +23,12 @@ export type AvroOptions = Partial<ForSchemaOptions> & {
23
23
  }
24
24
 
25
25
  export type JsonOptions = ConstructorParameters<typeof Ajv>[0] & {
26
- ajvInstance?: {
27
- addSchema: Ajv['addSchema']
28
- compile: (schema: any) => ValidateFunction
29
- }
26
+ ajvInstance?:
27
+ | {
28
+ addSchema: Ajv['addSchema']
29
+ compile: (schema: any) => ValidateFunction
30
+ }
31
+ | Ajv
30
32
  referencedSchemas?: JsonConfluentSchema[]
31
33
  }
32
34
  export type ProtoOptions = { messageName?: string; referencedSchemas?: ProtoConfluentSchema[] }
@@ -94,12 +96,3 @@ export interface SchemaResponse {
94
96
  }
95
97
 
96
98
  export type ConfluentSchema = AvroConfluentSchema | ProtoConfluentSchema | JsonConfluentSchema
97
-
98
- declare global {
99
- // eslint-disable-next-line @typescript-eslint/no-namespace
100
- namespace jest {
101
- interface Matchers<R, T = {}> {
102
- toMatchConfluentEncodedPayload(args: { registryId: number; payload: Buffer }): R
103
- }
104
- }
105
- }
package/src/AvroHelper.ts CHANGED
@@ -12,7 +12,7 @@ import { ConfluentSchemaRegistryArgumentError } from './errors'
12
12
  import avro, { ForSchemaOptions, Schema, Type } from 'avsc'
13
13
  import { SchemaResponse, SchemaType } from './@types'
14
14
 
15
- type TypeHook = (schema: Schema, opts: ForSchemaOptions) => Type
15
+ type TypeHook = (schema: Schema, opts: ForSchemaOptions) => Type | undefined
16
16
  export default class AvroHelper implements SchemaHelper {
17
17
  private getRawAvroSchema(schema: ConfluentSchema): RawAvroSchema {
18
18
  return (typeof schema.schema === 'string'
@@ -57,8 +57,7 @@ export default class AvroHelper implements SchemaHelper {
57
57
 
58
58
  public getSubject(
59
59
  schema: AvroConfluentSchema,
60
- // @ts-ignore
61
- avroSchema: AvroSchema,
60
+ _avroSchema: AvroSchema,
62
61
  separator: string,
63
62
  ): ConfluentSubject {
64
63
  const rawSchema: RawAvroSchema = this.getRawAvroSchema(schema)
package/src/JsonSchema.ts CHANGED
@@ -5,6 +5,7 @@ import { ConfluentSchemaRegistryValidationError } from './errors'
5
5
  interface BaseAjvValidationError {
6
6
  data?: unknown
7
7
  schema?: unknown
8
+ message?: string
8
9
  }
9
10
  interface OldAjvValidationError extends BaseAjvValidationError {
10
11
  dataPath: string
@@ -41,8 +42,15 @@ export default class JsonSchema implements Schema {
41
42
  }
42
43
 
43
44
  private validatePayload(payload: any) {
44
- const paths: string[][] = []
45
- if (!this.isValid(payload, { errorHook: path => paths.push(path) })) {
45
+ const paths: any[] = []
46
+
47
+ if (
48
+ !this.isValid(payload, {
49
+ errorHook: (path, message) => {
50
+ paths.push({ path, message })
51
+ },
52
+ })
53
+ ) {
46
54
  throw new ConfluentSchemaRegistryValidationError('invalid payload', paths)
47
55
  }
48
56
  }
@@ -57,19 +65,23 @@ export default class JsonSchema implements Schema {
57
65
  this.validatePayload(payload)
58
66
  return payload
59
67
  }
60
- public isValid(payload: object, opts?: { errorHook: (path: Array<string>, value: any, type?: any) => void }): boolean {
61
- if (!this.validate(payload)) {
62
- if (opts === null || opts === void 0 ? void 0 : opts.errorHook) {
63
- for (const err of (this.validate.errors as any)) {
64
- const path = this.isOldAjvValidationError(err) ? err.dataPath : err.instancePath;
65
- opts?.errorHook([path], err.data, err.schema);
66
- }
67
- }
68
- return false;
69
- }
70
- return true;
71
- }
72
-
68
+
69
+ public isValid(
70
+ payload: object,
71
+ opts?: { errorHook: (path: Array<string>, value: any, type?: any) => void },
72
+ ): boolean {
73
+ if (!this.validate(payload)) {
74
+ if (opts?.errorHook) {
75
+ for (const err of this.validate.errors as AjvValidationError[]) {
76
+ const path = this.isOldAjvValidationError(err) ? err.dataPath : err.instancePath
77
+ opts.errorHook([path], err.message ?? err.data, err.schema)
78
+ }
79
+ return false
80
+ }
81
+ }
82
+ return true
83
+ }
84
+
73
85
  private isOldAjvValidationError(error: AjvValidationError): error is OldAjvValidationError {
74
86
  return (error as OldAjvValidationError).dataPath != null
75
87
  }
@@ -1,6 +1,8 @@
1
1
  import SchemaRegistry, { RegisteredSchema } from './SchemaRegistry'
2
2
  import API from './api'
3
3
  import { JsonConfluentSchema, SchemaType } from './@types'
4
+ import Ajv from 'ajv'
5
+ import { ConfluentSchemaRegistryValidationError } from './errors'
4
6
 
5
7
  const REGISTRY_HOST = 'http://localhost:8982'
6
8
  const schemaRegistryAPIClientArgs = { host: REGISTRY_HOST }
@@ -100,8 +102,13 @@ describe('SchemaRegistry', () => {
100
102
  let api
101
103
 
102
104
  beforeEach(async () => {
105
+ const options = {
106
+ [SchemaType.JSON]: {
107
+ allErrors: true,
108
+ },
109
+ }
103
110
  api = API(schemaRegistryAPIClientArgs)
104
- schemaRegistry = new SchemaRegistry(schemaRegistryArgs)
111
+ schemaRegistry = new SchemaRegistry(schemaRegistryArgs, options)
105
112
  })
106
113
 
107
114
  describe('when register', () => {
@@ -161,6 +168,16 @@ describe('SchemaRegistry', () => {
161
168
 
162
169
  expect(resultObj).toEqual(obj)
163
170
  })
171
+
172
+ it('should return error message', async () => {
173
+ const obj = { id2a: 'sdfsdfsdf', level2a: 1 }
174
+ try {
175
+ await schemaRegistry.encode(registeredSchema.id, obj)
176
+ } catch (ex) {
177
+ expect(ex.paths[0].message).toBeDefined()
178
+ expect(ex.paths[0].message).toEqual('should be number')
179
+ }
180
+ })
164
181
  })
165
182
 
166
183
  describe('with multiple reference', () => {
@@ -587,7 +587,7 @@ describe('SchemaRegistry - new Api', () => {
587
587
  } catch (error) {
588
588
  expect(error).toBeInstanceOf(ConfluentSchemaRegistryValidationError)
589
589
  expect(error.message).toEqual('invalid payload')
590
- expect(error.paths).toEqual([['/fullName']])
590
+ expect(error.paths[0].path).toEqual(['/fullName'])
591
591
  }
592
592
  },
593
593
  )
@@ -250,3 +250,18 @@ describe('SchemaRegistry - old AVRO api', () => {
250
250
  })
251
251
  })
252
252
  })
253
+
254
+ describe('SchemaRegistry - Custom Middleware', () => {
255
+ const customMiddleware = jest.fn()
256
+
257
+ const schemaRegistry = new SchemaRegistry({
258
+ ...schemaRegistryArgs,
259
+ middlewares: [customMiddleware],
260
+ })
261
+
262
+ it('should have called the custom middleware', async () => {
263
+ await schemaRegistry.register(personSchema)
264
+
265
+ expect(customMiddleware).toHaveBeenCalled()
266
+ })
267
+ })
@@ -3,7 +3,7 @@ import { Response } from 'mappersmith'
3
3
 
4
4
  import { encode, MAGIC_BYTE } from './wireEncoder'
5
5
  import decode from './wireDecoder'
6
- import { COMPATIBILITY, DEFAULT_SEPERATOR } from './constants'
6
+ import { COMPATIBILITY, DEFAULT_SEPARATOR } from './constants'
7
7
  import API, { SchemaRegistryAPIClientArgs, SchemaRegistryAPIClient } from './api'
8
8
  import Cache from './cache'
9
9
  import {
@@ -46,13 +46,13 @@ interface Opts {
46
46
  interface AvroDecodeOptions {
47
47
  readerSchema?: RawAvroSchema | AvroSchema | Schema
48
48
  }
49
- interface DecodeOptions {
49
+ export interface DecodeOptions {
50
50
  [SchemaType.AVRO]?: AvroDecodeOptions
51
51
  }
52
52
 
53
53
  const DEFAULT_OPTS = {
54
54
  compatibility: COMPATIBILITY.BACKWARD,
55
- separator: DEFAULT_SEPERATOR,
55
+ separator: DEFAULT_SEPARATOR,
56
56
  }
57
57
  export default class SchemaRegistry {
58
58
  private api: SchemaRegistryAPIClient
@@ -62,10 +62,10 @@ export default class SchemaRegistry {
62
62
  public cache: Cache
63
63
 
64
64
  constructor(
65
- { auth, clientId, host, retry, agent }: SchemaRegistryAPIClientArgs,
65
+ { auth, clientId, host, retry, agent, middlewares }: SchemaRegistryAPIClientArgs,
66
66
  options?: SchemaRegistryAPIClientOptions,
67
67
  ) {
68
- this.api = API({ auth, clientId, host, retry, agent })
68
+ this.api = API({ auth, clientId, host, retry, agent, middlewares })
69
69
  this.cache = new Cache()
70
70
  this.options = options
71
71
  }
@@ -138,7 +138,7 @@ export default class SchemaRegistry {
138
138
  )
139
139
  }
140
140
  } catch (error) {
141
- if (error.status !== 404) {
141
+ if (!error || typeof error !== 'object' || !('status' in error) || error.status !== 404) {
142
142
  throw error
143
143
  } else {
144
144
  isFirstTimeRegistration = true
@@ -355,7 +355,7 @@ export default class SchemaRegistry {
355
355
 
356
356
  return id
357
357
  } catch (error) {
358
- if (error.status && error.status === 404) {
358
+ if (error && typeof error === 'object' && 'status' in error && error.status === 404) {
359
359
  throw new ConfluentSchemaRegistryError(error)
360
360
  }
361
361
 
@@ -370,18 +370,17 @@ export default class SchemaRegistry {
370
370
  return id
371
371
  }
372
372
 
373
- private getSchemaOriginRequest(registryId: number) {
373
+ private async getSchemaOriginRequest(registryId: number): Promise<Response> {
374
374
  // ensure that cache-misses result in a single origin request
375
- if (this.cacheMissRequests[registryId]) {
376
- return this.cacheMissRequests[registryId]
377
- } else {
378
- const request = this.api.Schema.find({ id: registryId }).finally(() => {
379
- delete this.cacheMissRequests[registryId]
380
- })
375
+ const req = this.cacheMissRequests[registryId]
376
+ if (req) return req
381
377
 
382
- this.cacheMissRequests[registryId] = request
378
+ const request = this.api.Schema.find({ id: registryId }).finally(() => {
379
+ delete this.cacheMissRequests[registryId]
380
+ })
383
381
 
384
- return request
385
- }
382
+ this.cacheMissRequests[registryId] = request
383
+
384
+ return request
386
385
  }
387
386
  }
@@ -1,7 +1,27 @@
1
+ import { Middleware } from 'mappersmith'
1
2
  import API from '.'
2
3
  import { mockClient, install, uninstall } from 'mappersmith/test'
3
4
 
4
- const client = API({ clientId: 'test-client', host: 'http://example.com' })
5
+ const customMiddleware: Middleware = jest.fn(() => {
6
+ return {
7
+ async request(request) {
8
+ return request.enhance({
9
+ headers: {
10
+ Authorization: 'Bearer Random',
11
+ },
12
+ })
13
+ },
14
+ async response(next) {
15
+ return next()
16
+ },
17
+ }
18
+ })
19
+
20
+ const client = API({
21
+ clientId: 'test-client',
22
+ host: 'http://example.com',
23
+ middlewares: [customMiddleware],
24
+ })
5
25
  const mock = mockClient<typeof client>(client)
6
26
  .resource('Schema')
7
27
  .method('find')
@@ -14,10 +34,12 @@ describe('API Client', () => {
14
34
 
15
35
  afterEach(() => uninstall())
16
36
 
17
- it('should include a user agent header', async () => {
37
+ it('should include a user agent header and call custom middleware', async () => {
18
38
  const response = await client.Schema.find({ id: 'abc' })
19
39
 
20
40
  expect(mock.callsCount()).toBe(1)
21
41
  expect(response.request().header('User-Agent')).not.toBeUndefined()
42
+ expect(response.request().header('Authorization')).toBe('Bearer Random')
43
+ expect(customMiddleware).toHaveBeenCalled()
22
44
  })
23
45
  })
package/src/api/index.ts CHANGED
@@ -1,5 +1,11 @@
1
1
  import { Agent } from 'http'
2
- import forge, { Authorization, Client, Options, GatewayConfiguration } from 'mappersmith'
2
+ import forge, {
3
+ Authorization,
4
+ Client,
5
+ GatewayConfiguration,
6
+ Middleware,
7
+ ManifestOptions,
8
+ } from 'mappersmith'
3
9
  import RetryMiddleware, { RetryMiddlewareOptions } from 'mappersmith/middleware/retry/v2'
4
10
  import BasicAuthMiddleware from 'mappersmith/middleware/basic-auth'
5
11
 
@@ -23,6 +29,7 @@ export interface SchemaRegistryAPIClientArgs {
23
29
  retry?: Partial<RetryMiddlewareOptions>
24
30
  /** HTTP Agent that will be passed to underlying API calls */
25
31
  agent?: Agent
32
+ middlewares?: Middleware[]
26
33
  }
27
34
 
28
35
  // TODO: Improve typings
@@ -48,10 +55,11 @@ export default ({
48
55
  host,
49
56
  retry = {},
50
57
  agent,
58
+ middlewares = [],
51
59
  }: SchemaRegistryAPIClientArgs): SchemaRegistryAPIClient => {
52
60
  const clientId = userClientId || DEFAULT_API_CLIENT_ID
53
61
  // FIXME: ResourcesType typings is not exposed by mappersmith
54
- const manifest: Options<any> = {
62
+ const manifest: ManifestOptions<any> = {
55
63
  clientId,
56
64
  ignoreGlobalMiddleware: true,
57
65
  host,
@@ -61,6 +69,7 @@ export default ({
61
69
  RetryMiddleware(Object.assign(DEFAULT_RETRY, retry)),
62
70
  errorMiddleware,
63
71
  ...(auth ? [BasicAuthMiddleware(auth)] : []),
72
+ ...middlewares,
64
73
  ],
65
74
  resources: {
66
75
  Schema: {
@@ -30,7 +30,7 @@ const errorMiddleware: Middleware = ({ clientId }) => ({
30
30
  new Promise((resolve, reject) =>
31
31
  next()
32
32
  .then(resolve)
33
- .catch((response: Response) => reject(new ResponseError(clientId, response))),
33
+ .catch((response: Response) => reject(new ResponseError(clientId ?? '', response))),
34
34
  ),
35
35
  })
36
36
 
package/src/constants.ts CHANGED
@@ -8,6 +8,6 @@ export enum COMPATIBILITY {
8
8
  FULL_TRANSITIVE = 'FULL_TRANSITIVE',
9
9
  }
10
10
 
11
- export const DEFAULT_SEPERATOR = '.'
11
+ export const DEFAULT_SEPARATOR = '.'
12
12
 
13
13
  export const DEFAULT_API_CLIENT_ID = 'Confluent_Schema_Registry'
package/src/index.ts CHANGED
@@ -1,4 +1,5 @@
1
- export { default as SchemaRegistry } from './SchemaRegistry'
1
+ import { default as SchemaRegistry, DecodeOptions } from './SchemaRegistry'
2
+ export { SchemaRegistry, DecodeOptions }
2
3
  export * from './utils'
3
4
  export { SchemaType } from './@types'
4
5
  export { COMPATIBILITY } from './constants'
@@ -96,6 +96,7 @@ export const schemaFromConfluentSchema = (
96
96
 
97
97
  return schema
98
98
  } catch (err) {
99
- throw new ConfluentSchemaRegistryArgumentError(err.message)
99
+ if (err instanceof Error) throw new ConfluentSchemaRegistryArgumentError(err.message)
100
+ throw err
100
101
  }
101
102
  }