diff --git a/src/api/index.spec.ts b/src/api/index.spec.ts new file mode 100644 index 0000000..1d36468 --- /dev/null +++ b/src/api/index.spec.ts @@ -0,0 +1,23 @@ +import API from '.' +import { mockClient, install, uninstall } from 'mappersmith/test' + +const client = API({ clientId: 'test-client', host: 'http://example.com' }) +const mock = mockClient(client) + .resource('Schema') + .method('find') + .with({ id: 'abc' }) + .response({}) + .assertObject() + +describe('API Client', () => { + beforeEach(() => install()) + + afterEach(() => uninstall()) + + it('should include a user agent header', async () => { + const response = await client.Schema.find({ id: 'abc' }) + + expect(mock.callsCount()).toBe(1) + expect(response.request().header('User-Agent')).not.toBeUndefined() + }) +}) diff --git a/src/api/index.ts b/src/api/index.ts index 87fd65e..b8c6d03 100644 --- a/src/api/index.ts +++ b/src/api/index.ts @@ -6,6 +6,7 @@ import BasicAuthMiddleware from 'mappersmith/middleware/basic-auth' import { DEFAULT_API_CLIENT_ID } from '../constants' import errorMiddleware from './middleware/errorMiddleware' import confluentEncoder from './middleware/confluentEncoderMiddleware' +import userAgentMiddleware from './middleware/userAgent' const DEFAULT_RETRY = { maxRetryTimeInSecs: 5, @@ -43,17 +44,19 @@ export type SchemaRegistryAPIClient = Client<{ export default ({ auth, - clientId, + clientId: userClientId, host, retry = {}, agent, }: SchemaRegistryAPIClientArgs): SchemaRegistryAPIClient => { + const clientId = userClientId || DEFAULT_API_CLIENT_ID // FIXME: ResourcesType typings is not exposed by mappersmith const manifest: Options = { - clientId: clientId || DEFAULT_API_CLIENT_ID, + clientId, ignoreGlobalMiddleware: true, host, middleware: [ + userAgentMiddleware, confluentEncoder, RetryMiddleware(Object.assign(DEFAULT_RETRY, retry)), errorMiddleware, diff --git a/src/api/middleware/userAgent.spec.ts b/src/api/middleware/userAgent.spec.ts new file mode 100644 index 0000000..9be2512 --- /dev/null +++ b/src/api/middleware/userAgent.spec.ts @@ -0,0 +1,53 @@ +import { Request } from 'mappersmith' + +import UserAgentMiddleware from './userAgent' + +const middlewareParams = (clientId?: string) => ({ + resourceName: 'resourceNameMock', + resourceMethod: 'resourceMethodMock', + context: { context: 'contextMock' }, + clientId, +}) + +describe('UserAgentMiddleware', () => { + let next, request + + beforeEach(() => { + request = ({ + enhance: jest.fn(), + } as unknown) as jest.Mocked + next = jest.fn().mockResolvedValue(request) + }) + + describe('When the user has provided a clientId', () => { + const params = middlewareParams('some-client-id') + + it('should add the client id as a user agent comment', async () => { + const middleware = UserAgentMiddleware(params) + + await middleware.prepareRequest(next, jest.fn()) + + expect(request.enhance).toHaveBeenCalledWith({ + headers: { + 'User-Agent': `@kafkajs/confluent-schema-registry (${params.clientId})`, + }, + }) + }) + }) + + describe('When the user has not provided a clientId', () => { + const params = middlewareParams() + + it('should not include a comment in the user agent', async () => { + const middleware = UserAgentMiddleware(params) + + await middleware.prepareRequest(next, jest.fn()) + + expect(request.enhance).toHaveBeenCalledWith({ + headers: { + 'User-Agent': `@kafkajs/confluent-schema-registry`, + }, + }) + }) + }) +}) diff --git a/src/api/middleware/userAgent.ts b/src/api/middleware/userAgent.ts new file mode 100644 index 0000000..92b519f --- /dev/null +++ b/src/api/middleware/userAgent.ts @@ -0,0 +1,19 @@ +import { Middleware } from 'mappersmith' +import { DEFAULT_API_CLIENT_ID } from '../../constants' + +const product = '@kafkajs/confluent-schema-registry' + +const userAgentMiddleware: Middleware = ({ clientId }) => { + const comment = clientId !== DEFAULT_API_CLIENT_ID ? clientId : undefined + const userAgent = comment ? `${product} (${comment})` : product + const headers = { + 'User-Agent': userAgent, + } + return { + prepareRequest: next => { + return next().then(req => req.enhance({ headers })) + }, + } +} + +export default userAgentMiddleware