UNPKG

@biorate/schema-registry

Version:

Schema registry connector

240 lines (209 loc) 7.19 kB
import { AxiosPrometheus, AxiosInstance } from '@biorate/axios-prometheus'; import { Type } from 'avsc'; import { ICompatibilities, ISchemaRegistryConfig } from './interfaces'; import { SchemaRegistryAvroSchemaParseError } from './errors'; export const create = (config: ISchemaRegistryConfig) => { const cache = new Map<number, Type>(); class SchemaRegistryApi extends AxiosPrometheus { public baseURL = config.baseURL; public headers = config.headers; public url: string; public method: string; private '#client': AxiosInstance; } class Ping extends SchemaRegistryApi { public url = '/'; public method = 'get'; public static fetch() { return this._fetch<Record<string, unknown>>({}); } } class GetSchemasById extends SchemaRegistryApi { public url = '/schemas/ids/:id'; public method = 'get'; public static fetch(id: number) { return this._fetch<{ schema: string }>({ path: { id } }); } } class GetSchemasTypes extends SchemaRegistryApi { public url = '/schemas/types'; public method = 'get'; public static fetch() { return this._fetch<string[]>({}); } } class GetSchemasVersionsById extends SchemaRegistryApi { public url = '/schemas/ids/:id/versions'; public method = 'get'; public static fetch(id: number) { return this._fetch<{ subject: string; version: number }[]>({ path: { id } }); } } class GetSubjects extends SchemaRegistryApi { public url = '/subjects'; public method = 'get'; public static fetch() { return this._fetch<string[]>({}); } } class GetSubjectsVersions extends SchemaRegistryApi { public url = '/subjects/:subject/versions'; public method = 'get'; public static fetch(subject: string) { return this._fetch<number[]>({ path: { subject } }); } } class DeleteSubjects extends SchemaRegistryApi { public url = '/subjects/:subject'; public method = 'delete'; public static fetch(data: { subject: string; permanent?: boolean }) { return this._fetch<number[]>({ path: { subject: data.subject }, params: { permanent: !!data.permanent }, }); } } class GetSubjectsByVersion extends SchemaRegistryApi { public url = '/subjects/:subject/versions/:version'; public method = 'get'; public static fetch(data: { subject: string; version: number | string }) { return this._fetch<{ subject: string; id: number; version: number; schemaType: string; schema: string; }>({ path: data }); } } class GetSchemaBySubjectsAndVersion extends SchemaRegistryApi { public url = '/subjects/:subject/versions/:version/schema'; public method = 'get'; public static fetch(data: { subject: string; version: number | string }) { return this._fetch<unknown>({ path: data }); } } class PostSubjectsVersions extends SchemaRegistryApi { public url = '/subjects/:subject/versions'; public method = 'post'; public static fetch(data: { subject: string; schema: string | Record<string, any>; schemaType?: string; reference?: string; normalize?: boolean; }) { return this._fetch<{ id: number }>({ path: { subject: data.subject }, params: { normalize: !!data.normalize }, data: { schema: toStringData(data.schema), schemaType: data.schemaType, reference: data.reference, }, }); } } class PostSubjects extends SchemaRegistryApi { public url = '/subjects/:subject'; public method = 'post'; public static fetch(data: { subject: string; schema: string | Record<string, any>; schemaType?: string; reference?: string; normalize?: boolean; }) { return this._fetch<{ subject: string; id: number; version: number; schema: string; }>({ path: { subject: data.subject }, params: { normalize: !!data.normalize }, data: { schema: toStringData(data.schema), schemaType: data.schemaType, reference: data.reference, }, }); } } class PutConfig extends SchemaRegistryApi { public url = '/config/:subject'; public method = 'put'; public static fetch(data: { subject: string; compatibility: ICompatibilities }) { return this._fetch<{ compatibility: ICompatibilities; }>({ path: { subject: data.subject }, data: { compatibility: data.compatibility }, }); } } async function encode( subject: string, data: Record<string, any>, version: string | number = 'latest', ) { const errors: string[] = []; const response = await GetSubjectsByVersion.fetch({ subject, version }); const header = Buffer.alloc(5); const schema = Type.forSchema(JSON.parse(response.data.schema)); schema.isValid(data, { errorHook: (path: string[], value: unknown) => { errors.push(`${path.join('.')}: ${value} (${typeof value})`); }, }); if (errors.length) throw new SchemaRegistryAvroSchemaParseError(errors); header.writeInt32BE(response.data.id, 1); return Buffer.concat([header, schema.toBuffer(data)]); } async function decode(buffer: Buffer) { const id = buffer.readInt32BE(1); let data: Type | undefined = cache.get(id); if (!data) { const response = await GetSchemasById.fetch(id); data = Type.forSchema(JSON.parse(response.data.schema)); cache.set(id, data); } const schema = Type.forSchema(data); return schema.fromBuffer(buffer.slice(5)); } function toStringData(data: string | Record<string, any>) { return typeof data === 'string' ? data : JSON.stringify(data); } return { ping: <typeof Ping.fetch>Ping.fetch.bind(Ping), getSchemasById: <typeof GetSchemasById.fetch>( GetSchemasById.fetch.bind(GetSchemasById) ), getSchemasTypes: <typeof GetSchemasTypes.fetch>( GetSchemasTypes.fetch.bind(GetSchemasTypes) ), getSchemasVersionsById: <typeof GetSchemasVersionsById.fetch>( GetSchemasVersionsById.fetch.bind(GetSchemasVersionsById) ), getSubjects: <typeof GetSubjects.fetch>GetSubjects.fetch.bind(GetSubjects), getSubjectsVersions: <typeof GetSubjectsVersions.fetch>( GetSubjectsVersions.fetch.bind(GetSubjectsVersions) ), deleteSubjects: <typeof DeleteSubjects.fetch>( DeleteSubjects.fetch.bind(DeleteSubjects) ), getSubjectsByVersion: <typeof GetSubjectsByVersion.fetch>( GetSubjectsByVersion.fetch.bind(GetSubjectsByVersion) ), getSchemaBySubjectsAndVersion: <typeof GetSchemaBySubjectsAndVersion.fetch>( GetSchemaBySubjectsAndVersion.fetch.bind(GetSchemaBySubjectsAndVersion) ), postSubjects: <typeof PostSubjects.fetch>PostSubjects.fetch.bind(PostSubjects), postSubjectsVersions: <typeof PostSubjectsVersions.fetch>( PostSubjectsVersions.fetch.bind(PostSubjectsVersions) ), putConfig: <typeof PutConfig.fetch>PutConfig.fetch.bind(PutConfig), encode, decode, }; };