Skip to content

Commit

Permalink
fix(api-rest): omit no credentials error and make unauth request(#12736)
Browse files Browse the repository at this point in the history
  • Loading branch information
AllanZhengYP authored Jan 3, 2024
1 parent e295445 commit e2824b6
Show file tree
Hide file tree
Showing 6 changed files with 70 additions and 50 deletions.
19 changes: 19 additions & 0 deletions packages/api-rest/__tests__/apis/common/internalPost.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,25 @@ describe('internal post', () => {
expect(mockAuthenticatedHandler).not.toHaveBeenCalled();
});

it('should call unauthenticatedHandler if credential is not set', async () => {
mockFetchAuthSession.mockClear();
mockFetchAuthSession.mockRejectedValue(
new Error('Mock error as credentials not configured')
);
await post(mockAmplifyInstance, {
url: apiGatewayUrl,
});
expect(mockUnauthenticatedHandler).toHaveBeenCalledWith(
{
url: apiGatewayUrl,
method: 'POST',
headers: {},
},
expect.anything()
);
expect(mockAuthenticatedHandler).not.toHaveBeenCalled();
});

it('should abort request when cancel is called', async () => {
expect.assertions(4);
let underLyingHandlerReject;
Expand Down
54 changes: 30 additions & 24 deletions packages/api-rest/__tests__/apis/common/publicApis.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import { AmplifyClassV6 } from '@aws-amplify/core';
import {
authenticatedHandler,
unauthenticatedHandler,
parseJsonError,
} from '@aws-amplify/core/internals/aws-client-utils';

Expand All @@ -25,6 +26,7 @@ import {
jest.mock('@aws-amplify/core/internals/aws-client-utils');

const mockAuthenticatedHandler = authenticatedHandler as jest.Mock;
const mockUnauthenticatedHandler = unauthenticatedHandler as jest.Mock;
const mockFetchAuthSession = jest.fn();
let mockConfig = {
API: {
Expand Down Expand Up @@ -60,24 +62,27 @@ const credentials = {
sessionToken: 'sessionToken',
secretAccessKey: 'secretAccessKey',
};
const mockSuccessResponse = {
statusCode: 200,
headers: {
'response-header': 'response-header-value',
},
body: {
blob: jest.fn(),
json: jest.fn(),
text: jest.fn(),
},
};

describe('public APIs', () => {
beforeEach(() => {
jest.resetAllMocks();
mockFetchAuthSession.mockResolvedValue({
credentials,
});
mockAuthenticatedHandler.mockResolvedValue({
statusCode: 200,
headers: {
'response-header': 'response-header-value',
},
body: {
blob: jest.fn(),
json: jest.fn().mockResolvedValue({ foo: 'bar' }),
text: jest.fn(),
},
});
mockSuccessResponse.body.json.mockResolvedValue({ foo: 'bar' });
mockAuthenticatedHandler.mockResolvedValue(mockSuccessResponse);
mockUnauthenticatedHandler.mockResolvedValue(mockSuccessResponse);
mockGetConfig.mockReturnValue(mockConfig);
});
const APIs = [
Expand Down Expand Up @@ -266,20 +271,21 @@ describe('public APIs', () => {
}
});

it('should throw if credentials are not available', async () => {
expect.assertions(2);
it('should use unauthenticated request if credentials are not available', async () => {
expect.assertions(1);
mockFetchAuthSession.mockResolvedValueOnce({});
try {
await fn(mockAmplifyInstance, {
apiName: 'restApi1',
path: '/items',
}).response;
} catch (error) {
expect(error).toBeInstanceOf(RestApiError);
expect(error).toMatchObject(
validationErrorMap[RestApiValidationErrorCode.NoCredentials]
);
}
await fn(mockAmplifyInstance, {
apiName: 'restApi1',
path: '/items',
}).response;
expect(mockUnauthenticatedHandler).toHaveBeenCalledWith(
expect.objectContaining({
url: new URL(
'https://123.execute-api.us-west-2.amazonaws.com/development/items/123'
),
}),
expect.anything()
);
});

it('should throw when response is not ok', async () => {
Expand Down
25 changes: 21 additions & 4 deletions packages/api-rest/src/apis/common/handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,15 @@ import {
jitteredBackoff,
authenticatedHandler,
} from '@aws-amplify/core/internals/aws-client-utils';
import { DocumentType } from '@aws-amplify/core/internals/utils';
import {
AWSCredentials,
DocumentType,
} from '@aws-amplify/core/internals/utils';

import {
logger,
parseRestApiServiceError,
parseSigningInfo,
resolveCredentials,
} from '../../utils';
import { resolveHeaders } from '../../utils/resolveHeaders';
import { RestApiResponse } from '../../types';
Expand Down Expand Up @@ -67,13 +70,13 @@ export const transferHandler = async (

const isIamAuthApplicable = iamAuthApplicable(request, signingServiceInfo);
let response: RestApiResponse;
if (isIamAuthApplicable) {
const credentials = await resolveCredentials(amplify);
if (isIamAuthApplicable && credentials) {
const signingInfoFromUrl = parseSigningInfo(url);
const signingService =
signingServiceInfo?.service ?? signingInfoFromUrl.service;
const signingRegion =
signingServiceInfo?.region ?? signingInfoFromUrl.region;
const credentials = await resolveCredentials(amplify);
response = await authenticatedHandler(request, {
...baseOptions,
credentials,
Expand All @@ -97,3 +100,17 @@ const iamAuthApplicable = (
{ headers }: HttpRequest,
signingServiceInfo?: SigningServiceInfo
) => !headers.authorization && !headers['x-api-key'] && !!signingServiceInfo;

const resolveCredentials = async (
amplify: AmplifyClassV6
): Promise<AWSCredentials | null> => {
try {
const { credentials } = await amplify.Auth.fetchAuthSession();
if (credentials) {
return credentials;
}
} catch (e) {
logger.debug('No credentials available, the request will be unsigned.');
}
return null;
};
4 changes: 0 additions & 4 deletions packages/api-rest/src/errors/validation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,10 @@
import { AmplifyErrorMap } from '@aws-amplify/core/internals/utils';

export enum RestApiValidationErrorCode {
NoCredentials = 'NoCredentials',
InvalidApiName = 'InvalidApiName',
}

export const validationErrorMap: AmplifyErrorMap<RestApiValidationErrorCode> = {
[RestApiValidationErrorCode.NoCredentials]: {
message: 'Credentials should not be empty.',
},
[RestApiValidationErrorCode.InvalidApiName]: {
message: 'API name is invalid.',
recoverySuggestion:
Expand Down
1 change: 0 additions & 1 deletion packages/api-rest/src/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
// SPDX-License-Identifier: Apache-2.0

export { createCancellableOperation } from './createCancellableOperation';
export { resolveCredentials } from './resolveCredentials';
export { parseSigningInfo } from './parseSigningInfo';
export { parseRestApiServiceError } from './serviceError';
export { resolveApiUrl } from './resolveApiUrl';
Expand Down
17 changes: 0 additions & 17 deletions packages/api-rest/src/utils/resolveCredentials.ts

This file was deleted.

0 comments on commit e2824b6

Please sign in to comment.