Skip to content

Commit b383885

Browse files
authored
feat: library observability improvements (#14309)
* feat(auth): throw extended AuthError for service errors from user pool & id pool (#14230) * feat(core): expose metadata from base AmplifyError class * feat(auth): throw auth error with extended metadata from amplify error * fix: remain internal metadata as $metadata * feat(storage): emit response metadata in applicable error throw sites (#14237) * chore(api-rest): use non-aws-specific transfer handlers (#14259) * chore(api-rest): use non-aws-specific transfer handlers * feat(core): add amz-sdk-request and amz-sdk-invocation-id header to aws clients * feat(storage): add amz-sdk-request and amz-sdk-invocation-id header to s3 client * fix(core): add amz-sdk-request and amz-sdk-invocation-id header to aws clients * feat(storage): add x-id query to applicable s3 apis (#14251) * feat(storage): add x-id query to applicable s3 apis * chore: update size limit * test(core): add internal transfer handler unit test (#14296)
1 parent 980e3f8 commit b383885

File tree

79 files changed

+1247
-536
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

79 files changed

+1247
-536
lines changed
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
import { composeTransferHandler } from '@aws-amplify/core/internals/aws-client-utils/composers';
4+
import {
5+
fetchTransferHandler,
6+
retryMiddlewareFactory,
7+
signingMiddlewareFactory,
8+
userAgentMiddlewareFactory,
9+
} from '@aws-amplify/core/internals/aws-client-utils';
10+
11+
import { authenticatedHandler } from '../../../../src/apis/common/baseHandlers/authenticatedHandler';
12+
13+
jest.mock('@aws-amplify/core/internals/aws-client-utils/composers', () => ({
14+
composeTransferHandler: jest
15+
.fn()
16+
.mockReturnValue('composed_transfer_handler'),
17+
}));
18+
19+
describe('authenticated handler', () => {
20+
it('should be configured correctly', () => {
21+
expect(authenticatedHandler).toEqual('composed_transfer_handler');
22+
expect(composeTransferHandler).toHaveBeenCalledTimes(1);
23+
expect(composeTransferHandler).toHaveBeenCalledWith(fetchTransferHandler, [
24+
userAgentMiddlewareFactory,
25+
retryMiddlewareFactory,
26+
signingMiddlewareFactory,
27+
]);
28+
});
29+
});
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
import { composeTransferHandler } from '@aws-amplify/core/internals/aws-client-utils/composers';
4+
import {
5+
fetchTransferHandler,
6+
retryMiddlewareFactory,
7+
userAgentMiddlewareFactory,
8+
} from '@aws-amplify/core/internals/aws-client-utils';
9+
10+
import { unauthenticatedHandler } from '../../../../src/apis/common/baseHandlers/unauthenticatedHandler';
11+
12+
jest.mock('@aws-amplify/core/internals/aws-client-utils/composers', () => ({
13+
composeTransferHandler: jest
14+
.fn()
15+
.mockReturnValue('composed_transfer_handler'),
16+
}));
17+
18+
describe('unauthenticated handler', () => {
19+
it('should be configured correctly', () => {
20+
expect(unauthenticatedHandler).toEqual('composed_transfer_handler');
21+
expect(composeTransferHandler).toHaveBeenCalledTimes(1);
22+
expect(composeTransferHandler).toHaveBeenCalledWith(fetchTransferHandler, [
23+
userAgentMiddlewareFactory,
24+
retryMiddlewareFactory,
25+
]);
26+
});
27+
});

packages/api-rest/__tests__/apis/common/internalPost.test.ts

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,24 +3,24 @@
33

44
import { AmplifyClassV6 } from '@aws-amplify/core';
55
import { ApiError } from '@aws-amplify/core/internals/utils';
6-
import {
7-
authenticatedHandler,
8-
parseJsonError,
9-
unauthenticatedHandler,
10-
} from '@aws-amplify/core/internals/aws-client-utils';
6+
import { parseJsonError } from '@aws-amplify/core/internals/aws-client-utils';
117

128
import {
139
cancel,
1410
post,
1511
updateRequestToBeCancellable,
1612
} from '../../../src/apis/common/internalPost';
13+
import { authenticatedHandler } from '../../../src/apis/common/baseHandlers/authenticatedHandler';
14+
import { unauthenticatedHandler } from '../../../src/apis/common/baseHandlers/unauthenticatedHandler';
1715
import { RestApiError, isCancelError } from '../../../src/errors';
1816

1917
jest.mock('@aws-amplify/core/internals/aws-client-utils');
18+
jest.mock('../../../src/apis/common/baseHandlers/authenticatedHandler');
19+
jest.mock('../../../src/apis/common/baseHandlers/unauthenticatedHandler');
2020

21-
const mockAuthenticatedHandler = authenticatedHandler as jest.Mock;
22-
const mockUnauthenticatedHandler = unauthenticatedHandler as jest.Mock;
23-
const mockParseJsonError = parseJsonError as jest.Mock;
21+
const mockAuthenticatedHandler = jest.mocked(authenticatedHandler);
22+
const mockUnauthenticatedHandler = jest.mocked(unauthenticatedHandler);
23+
const mockParseJsonError = jest.mocked(parseJsonError);
2424
const mockFetchAuthSession = jest.fn();
2525
const mockAmplifyInstance = {
2626
Auth: {
@@ -320,11 +320,12 @@ describe('internal post', () => {
320320
},
321321
};
322322
mockParseJsonError.mockImplementationOnce(async response => {
323-
const errorResponsePayload = await response.body?.json();
323+
const errorResponsePayload = await response?.body?.json();
324324
const error = new Error(errorResponsePayload.message);
325325

326326
return Object.assign(error, {
327327
name: errorResponsePayload.name,
328+
$metadata: {},
328329
});
329330
});
330331
mockUnauthenticatedHandler.mockResolvedValueOnce(errorResponse);
@@ -365,11 +366,12 @@ describe('internal post', () => {
365366
},
366367
};
367368
mockParseJsonError.mockImplementationOnce(async response => {
368-
const errorResponsePayload = await response.body?.json();
369+
const errorResponsePayload = await response?.body?.json();
369370
const error = new Error(errorResponsePayload.message);
370371

371372
return Object.assign(error, {
372373
name: errorResponsePayload.name,
374+
$metadata: {},
373375
});
374376
});
375377
mockUnauthenticatedHandler.mockResolvedValueOnce(errorResponse);

packages/api-rest/__tests__/apis/common/publicApis.test.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,11 @@
22
// SPDX-License-Identifier: Apache-2.0
33

44
import { AmplifyClassV6 } from '@aws-amplify/core';
5-
import {
6-
authenticatedHandler,
7-
parseJsonError,
8-
unauthenticatedHandler,
9-
} from '@aws-amplify/core/internals/aws-client-utils';
5+
import { parseJsonError } from '@aws-amplify/core/internals/aws-client-utils';
106
import { ApiError } from '@aws-amplify/core/internals/utils';
117

8+
import { authenticatedHandler } from '../../../src/apis/common/baseHandlers/authenticatedHandler';
9+
import { unauthenticatedHandler } from '../../../src/apis/common/baseHandlers/unauthenticatedHandler';
1210
import {
1311
del,
1412
get,
@@ -26,6 +24,8 @@ import {
2624
import { RestApiResponse } from '../../../src/types';
2725

2826
jest.mock('@aws-amplify/core/internals/aws-client-utils');
27+
jest.mock('../../../src/apis/common/baseHandlers/authenticatedHandler');
28+
jest.mock('../../../src/apis/common/baseHandlers/unauthenticatedHandler');
2929

3030
const mockAuthenticatedHandler = authenticatedHandler as jest.Mock;
3131
const mockUnauthenticatedHandler = unauthenticatedHandler as jest.Mock;

packages/api-rest/package.json

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -91,13 +91,5 @@
9191
"@aws-amplify/react-native": "1.1.7",
9292
"@aws-sdk/types": "3.387.0",
9393
"typescript": "5.0.2"
94-
},
95-
"size-limit": [
96-
{
97-
"name": "API (rest client)",
98-
"path": "./dist/esm/index.mjs",
99-
"import": "{ Amplify, RestAPI }",
100-
"limit": "31.5 kB"
101-
}
102-
]
94+
}
10395
}

packages/core/src/clients/handlers/authenticated.ts renamed to packages/api-rest/src/apis/common/baseHandlers/authenticatedHandler.ts

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,21 @@
11
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
22
// SPDX-License-Identifier: Apache-2.0
3-
4-
import { RetryOptions, retryMiddlewareFactory } from '../middleware/retry';
53
import {
4+
HttpRequest,
5+
HttpResponse,
6+
RetryOptions,
67
SigningOptions,
7-
signingMiddlewareFactory,
8-
} from '../middleware/signing';
9-
import {
108
UserAgentOptions,
9+
fetchTransferHandler,
10+
retryMiddlewareFactory,
11+
signingMiddlewareFactory,
1112
userAgentMiddlewareFactory,
12-
} from '../middleware/userAgent';
13-
import { composeTransferHandler } from '../internal/composeTransferHandler';
14-
import { HttpRequest, HttpResponse } from '../types';
15-
16-
import { fetchTransferHandler } from './fetch';
13+
} from '@aws-amplify/core/internals/aws-client-utils';
14+
import { composeTransferHandler } from '@aws-amplify/core/internals/aws-client-utils/composers';
1715

16+
/**
17+
* @internal
18+
*/
1819
export const authenticatedHandler = composeTransferHandler<
1920
[UserAgentOptions, RetryOptions<HttpResponse>, SigningOptions],
2021
HttpRequest,

packages/core/src/clients/handlers/unauthenticated.ts renamed to packages/api-rest/src/apis/common/baseHandlers/unauthenticatedHandler.ts

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,19 @@
11
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
22
// SPDX-License-Identifier: Apache-2.0
3-
4-
import { RetryOptions, retryMiddlewareFactory } from '../middleware/retry';
53
import {
4+
HttpRequest,
5+
HttpResponse,
6+
RetryOptions,
67
UserAgentOptions,
8+
fetchTransferHandler,
9+
retryMiddlewareFactory,
710
userAgentMiddlewareFactory,
8-
} from '../middleware/userAgent';
9-
import { composeTransferHandler } from '../internal/composeTransferHandler';
10-
import { HttpRequest, HttpResponse } from '../types';
11-
12-
import { fetchTransferHandler } from './fetch';
11+
} from '@aws-amplify/core/internals/aws-client-utils';
12+
import { composeTransferHandler } from '@aws-amplify/core/internals/aws-client-utils/composers';
1313

14+
/**
15+
* @internal
16+
*/
1417
export const unauthenticatedHandler = composeTransferHandler<
1518
[UserAgentOptions, RetryOptions<HttpResponse>],
1619
HttpRequest,

packages/api-rest/src/apis/common/internalPost.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { createCancellableOperation } from '../../utils';
88
import { CanceledError } from '../../errors';
99
import { isIamAuthApplicableForGraphQL } from '../../utils/isIamAuthApplicable';
1010

11-
import { transferHandler } from './handler';
11+
import { transferHandler } from './transferHandler';
1212

1313
/**
1414
* This weak map provides functionality to cancel a request given the promise containing the `post` request.

packages/api-rest/src/apis/common/publicApis.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ import {
2727
} from '../../utils';
2828
import { isIamAuthApplicableForRest } from '../../utils/isIamAuthApplicable';
2929

30-
import { transferHandler } from './handler';
30+
import { transferHandler } from './transferHandler';
3131

3232
const publicHandler = (
3333
amplify: AmplifyClassV6,

packages/api-rest/src/apis/common/handler.ts renamed to packages/api-rest/src/apis/common/transferHandler.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,8 @@ import { AmplifyClassV6 } from '@aws-amplify/core';
44
import {
55
Headers,
66
HttpRequest,
7-
authenticatedHandler,
87
getRetryDecider,
98
jitteredBackoff,
10-
unauthenticatedHandler,
119
} from '@aws-amplify/core/internals/aws-client-utils';
1210
import {
1311
AWSCredentials,
@@ -22,6 +20,9 @@ import {
2220
import { resolveHeaders } from '../../utils/resolveHeaders';
2321
import { RestApiResponse, SigningServiceInfo } from '../../types';
2422

23+
import { authenticatedHandler } from './baseHandlers/authenticatedHandler';
24+
import { unauthenticatedHandler } from './baseHandlers/unauthenticatedHandler';
25+
2526
type HandlerOptions = Omit<HttpRequest, 'body' | 'headers'> & {
2627
body?: DocumentType | FormData;
2728
headers?: Headers;

packages/auth/__tests__/foundation/factories/serviceClients/cognitoIdentityProvider/shared/serde/createUserPoolDeserializer.test.ts

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import {
33
parseJsonBody,
44
parseJsonError,
55
} from '@aws-amplify/core/internals/aws-client-utils';
6+
import { ErrorParser } from '@aws-amplify/core/src/clients';
67

78
import { createUserPoolDeserializer } from '../../../../../../../src/foundation/factories/serviceClients/cognitoIdentityProvider/shared/serde/createUserPoolDeserializer';
89
import { AuthError } from '../../../../../../../src/errors/AuthError';
@@ -33,10 +34,19 @@ describe('buildUserPoolDeserializer created response deserializer', () => {
3334
});
3435

3536
it('throws AuthError for 4xx status code', async () => {
37+
expect.assertions(2);
3638
const expectedErrorName = 'TestError';
3739
const expectedErrorMessage = 'TestErrorMessage';
38-
const expectedError = new Error(expectedErrorMessage);
39-
expectedError.name = expectedErrorName;
40+
type ParsedError = Awaited<ReturnType<ErrorParser>>;
41+
const expectedError: ParsedError = Object.assign(
42+
new Error(expectedErrorMessage),
43+
{
44+
name: expectedErrorName,
45+
$metadata: {
46+
httpStatusCode: 400,
47+
},
48+
},
49+
);
4050

4151
mockParseJsonError.mockReturnValueOnce(expectedError as any);
4252
const response: HttpResponse = {
@@ -49,11 +59,17 @@ describe('buildUserPoolDeserializer created response deserializer', () => {
4959
headers: {},
5060
};
5161

52-
expect(deserializer(response as any)).rejects.toThrow(
53-
new AuthError({
62+
try {
63+
await deserializer(response as any);
64+
} catch (e) {
65+
expect(e).toBeInstanceOf(AuthError);
66+
expect(e).toMatchObject({
5467
name: expectedErrorName,
5568
message: expectedErrorMessage,
56-
}),
57-
);
69+
metadata: expect.objectContaining({
70+
httpStatusCode: 400,
71+
}),
72+
});
73+
}
5874
});
5975
});

0 commit comments

Comments
 (0)