Skip to content

Commit 9e856ac

Browse files
authored
[schema registry] Return undefined for not found (Azure#15149)
1 parent d286ddd commit 9e856ac

File tree

16 files changed

+135
-72
lines changed

16 files changed

+135
-72
lines changed

sdk/schemaregistry/schema-registry-avro/samples/v1/typescript/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ npm run build
4545
4. Run whichever samples you like (note that some samples may require additional setup, see the table above):
4646

4747
```bash
48-
node dist/schemaRegistryAvroSample.ts
48+
node dist/schemaRegistryAvroSample.js
4949
```
5050

5151
Alternatively, run a single sample with the correct environment variables set (setting up the `.env` file is not required if you do this), for example (cross-platform):

sdk/schemaregistry/schema-registry-avro/samples/v1/typescript/tsconfig.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
{
22
"compilerOptions": {
3-
"target": "ES6",
3+
"target": "ES2018",
44
"module": "commonjs",
55
"moduleResolution": "node",
6+
"resolveJsonModule": true,
67
"esModuleInterop": true,
78
"allowSyntheticDefaultImports": true,
89
"strict": true,

sdk/schemaregistry/schema-registry-avro/src/schemaRegistryAvroSerializer.ts

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ import * as avro from "avsc";
2626
// - [Remaining bytes: Avro payload (in general, format-specific payload)]
2727
// - Avro Binary Encoding
2828
// - NOT Avro Object Container File, which includes the schema and defeats
29-
// the purpose of this serialzer to move the schema out of the message
29+
// the purpose of this serializer to move the schema out of the message
3030
// payload and into the schema registry.
3131
//
3232
const FORMAT_INDICATOR = 0;
@@ -137,7 +137,7 @@ export class SchemaRegistryAvroSerializer {
137137

138138
const format = buffer.readUInt32BE(0);
139139
if (format !== FORMAT_INDICATOR) {
140-
throw new TypeError(`Buffer has unknown format indicator: 0x${format.toString(16)}`);
140+
throw new TypeError(`Buffer has unknown format indicator: 0x${format.toString(16)}.`);
141141
}
142142

143143
const schemaIdBuffer = buffer.slice(SCHEMA_ID_OFFSET, PAYLOAD_OFFSET);
@@ -167,6 +167,10 @@ export class SchemaRegistryAvroSerializer {
167167
}
168168

169169
const schemaResponse = await this.registry.getSchemaById(schemaId);
170+
if (!schemaResponse) {
171+
throw new Error(`Schema with ID '${schemaId}' not found.`);
172+
}
173+
170174
if (!schemaResponse.serializationType.match(/^avro$/i)) {
171175
throw new Error(
172176
`Schema with ID '${schemaResponse.id}' has serialization type '${schemaResponse.serializationType}', not 'avro'.`
@@ -195,11 +199,20 @@ export class SchemaRegistryAvroSerializer {
195199
content: schema
196200
};
197201

198-
const schemaIdResponse = this.autoRegisterSchemas
199-
? await this.registry.registerSchema(description)
200-
: await this.registry.getSchemaId(description);
202+
let id: string;
203+
if (this.autoRegisterSchemas) {
204+
id = (await this.registry.registerSchema(description)).id;
205+
} else {
206+
const response = await this.registry.getSchemaId(description);
207+
if (!response) {
208+
throw new Error(
209+
`Schema '${description.name}' not found in registry group '${description.group}', or not found to have matching content.`
210+
);
211+
}
212+
id = response.id;
213+
}
201214

202-
return this.cache(schemaIdResponse.id, schema, avroType);
215+
return this.cache(id, schema, avroType);
203216
}
204217

205218
private cache(id: string, schema: string, type: avro.Type): CacheEntry {

sdk/schemaregistry/schema-registry-avro/test/schemaRegistryAvroSerializer.spec.ts

Lines changed: 28 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,26 @@ describe("SchemaRegistryAvroSerializer", function() {
8888
);
8989
});
9090

91+
it("rejects serialization when schema is not found", async () => {
92+
const serializer = await createTestSerializer(false);
93+
const schema = JSON.stringify({
94+
type: "record",
95+
name: "NeverRegistered",
96+
namespace: "my.example",
97+
fields: [{ name: "count", type: "int" }]
98+
});
99+
await assert.isRejected(serializer.serialize({ count: 42 }, schema), /not found/);
100+
});
101+
102+
it("rejects deserialization when schema is not found", async () => {
103+
const serializer = await createTestSerializer(false);
104+
const payload = testAvroType.toBuffer(testValue);
105+
const buffer = Buffer.alloc(36 + payload.length);
106+
buffer.write(testSchemaIds[1], 4, 32, "utf-8");
107+
payload.copy(buffer, 36);
108+
await assert.isRejected(serializer.deserialize(buffer), /not found/);
109+
});
110+
91111
it("serializes to the expected format", async () => {
92112
const registry = createTestRegistry();
93113
const schemaId = await registerTestSchema(registry);
@@ -124,7 +144,7 @@ describe("SchemaRegistryAvroSerializer", function() {
124144
serializer = await createTestSerializer(false);
125145
assert.deepStrictEqual(await serializer.deserialize(buffer), testValue);
126146

127-
// thow away serializer again and cover getSchemaId instead of registerSchema
147+
// throw away serializer again and cover getSchemaId instead of registerSchema
128148
serializer = await createTestSerializer(false);
129149
assert.deepStrictEqual(await serializer.serialize(testValue, testSchema), buffer);
130150
});
@@ -221,19 +241,14 @@ function createTestRegistry(neverLive = false): SchemaRegistry {
221241
async function getSchemaId(
222242
schema: SchemaDescription,
223243
_options?: GetSchemaIdOptions
224-
): Promise<SchemaId> {
225-
const result = mapByContent.get(schema.content);
226-
if (!result) {
227-
throw new Error("No such schema is registered.");
228-
}
229-
return result;
244+
): Promise<SchemaId | undefined> {
245+
return mapByContent.get(schema.content);
230246
}
231247

232-
async function getSchemaById(id: string, _options?: GetSchemaByIdOptions): Promise<Schema> {
233-
const result = mapById.get(id);
234-
if (!result) {
235-
throw new Error("No such schema is registered.");
236-
}
237-
return result;
248+
async function getSchemaById(
249+
id: string,
250+
_options?: GetSchemaByIdOptions
251+
): Promise<Schema | undefined> {
252+
return mapById.get(id);
238253
}
239254
}

sdk/schemaregistry/schema-registry/README.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,9 @@ const description = {
104104
}
105105

106106
const found = await client.getSchemaId(description);
107-
console.log(`Got schema ID=${found.id}`);
107+
if (found) {
108+
console.log(`Got schema ID=${found.id}`);
109+
}
108110
```
109111

110112
### Get content of existing schema by ID
@@ -115,7 +117,9 @@ const { SchemaRegistryClient } = require("@azure/schema-registry");
115117

116118
const client = new SchemaRegistryClient("<endpoint>", new DefaultAzureCredential());
117119
const foundSchema = await client.getSchemaById("<id>");
118-
console.log(`Got schema content=${foundSchema.content}`);
120+
if (foundSchema) {
121+
console.log(`Got schema content=${foundSchema.content}`);
122+
}
119123
```
120124

121125
## Troubleshooting

sdk/schemaregistry/schema-registry/review/schema-registry.api.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,17 +44,17 @@ export interface SchemaId {
4444

4545
// @public
4646
export interface SchemaRegistry {
47-
getSchemaById(id: string, options?: GetSchemaByIdOptions): Promise<Schema>;
48-
getSchemaId(schema: SchemaDescription, options?: GetSchemaIdOptions): Promise<SchemaId>;
47+
getSchemaById(id: string, options?: GetSchemaByIdOptions): Promise<Schema | undefined>;
48+
getSchemaId(schema: SchemaDescription, options?: GetSchemaIdOptions): Promise<SchemaId | undefined>;
4949
registerSchema(schema: SchemaDescription, options?: RegisterSchemaOptions): Promise<SchemaId>;
5050
}
5151

5252
// @public
5353
export class SchemaRegistryClient implements SchemaRegistry {
5454
constructor(endpoint: string, credential: TokenCredential, options?: SchemaRegistryClientOptions);
5555
readonly endpoint: string;
56-
getSchemaById(id: string, options?: GetSchemaByIdOptions): Promise<Schema>;
57-
getSchemaId(schema: SchemaDescription, options?: GetSchemaIdOptions): Promise<SchemaId>;
56+
getSchemaById(id: string, options?: GetSchemaByIdOptions): Promise<Schema | undefined>;
57+
getSchemaId(schema: SchemaDescription, options?: GetSchemaIdOptions): Promise<SchemaId | undefined>;
5858
registerSchema(schema: SchemaDescription, options?: RegisterSchemaOptions): Promise<SchemaId>;
5959
}
6060

sdk/schemaregistry/schema-registry/samples-dev/schemaRegistrySample.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,14 +49,18 @@ export async function main() {
4949
const registered = await client.registerSchema(schemaDescription);
5050
console.log(`Registered schema with ID=${registered.id}`);
5151

52-
// Get ID for exisiting schema by its description.
52+
// Get ID for existing schema by its description.
5353
// Note that this would throw if it had not been previously registered.
5454
const found = await client.getSchemaId(schemaDescription);
55-
console.log(`Got schema ID=${found.id}`);
55+
if (found) {
56+
console.log(`Got schema ID=${found.id}`);
57+
}
5658

5759
// Get content of existing schema by its ID
5860
const foundSchema = await client.getSchemaById(registered.id);
59-
console.log(`Got schema content=${foundSchema.content}`);
61+
if (foundSchema) {
62+
console.log(`Got schema content=${foundSchema.content}`);
63+
}
6064
}
6165

6266
main().catch((err) => {

sdk/schemaregistry/schema-registry/samples/v1/javascript/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,6 @@
2525
"dependencies": {
2626
"@azure/schema-registry": "next",
2727
"dotenv": "latest",
28-
"@azure/identity": "^1.1.0"
28+
"@azure/identity": "2.0.0-beta.3"
2929
}
3030
}

sdk/schemaregistry/schema-registry/samples/v1/javascript/schemaRegistrySample.js

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,14 +49,18 @@ async function main() {
4949
const registered = await client.registerSchema(schemaDescription);
5050
console.log(`Registered schema with ID=${registered.id}`);
5151

52-
// Get ID for exisiting schema by its description.
52+
// Get ID for existing schema by its description.
5353
// Note that this would throw if it had not been previously registered.
5454
const found = await client.getSchemaId(schemaDescription);
55-
console.log(`Got schema ID=${found.id}`);
55+
if (found) {
56+
console.log(`Got schema ID=${found.id}`);
57+
}
5658

5759
// Get content of existing schema by its ID
5860
const foundSchema = await client.getSchemaById(registered.id);
59-
console.log(`Got schema content=${foundSchema.content}`);
61+
if (foundSchema) {
62+
console.log(`Got schema content=${foundSchema.content}`);
63+
}
6064
}
6165

6266
main().catch((err) => {

sdk/schemaregistry/schema-registry/samples/v1/typescript/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ npm run build
4545
4. Run whichever samples you like (note that some samples may require additional setup, see the table above):
4646

4747
```bash
48-
node dist/schemaRegistrySample.ts
48+
node dist/schemaRegistrySample.js
4949
```
5050

5151
Alternatively, run a single sample with the correct environment variables set (setting up the `.env` file is not required if you do this), for example (cross-platform):

0 commit comments

Comments
 (0)