Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: support multiple graphql or rest APIs #4982

Merged
merged 1 commit into from
Jun 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions packages/amplify_core/lib/src/config/amplify_config.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

import 'package:amplify_core/amplify_core.dart';
import 'package:json_annotation/json_annotation.dart';
import 'package:meta/meta.dart';

part 'amplify_config.g.dart';

Expand Down Expand Up @@ -74,12 +75,14 @@ class AmplifyConfig with AWSEquatable<AmplifyConfig>, AWSSerializable {
);
}

@internal
AmplifyOutputs toAmplifyOutputs() {
final appSync = auth?.awsPlugin?.appSync;
return AmplifyOutputs(
version: '1',
auth: auth?.toAuthOutputs(),
data: api?.toDataOutputs(appSync: appSync),
restApi: api?.toRestApiOutputs(),
analytics: analytics?.toAnalyticsOutputs(),
notifications: notifications?.toNotificationsOutputs(),
storage: storage?.toStorageOutputs(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ import 'package:amplify_core/src/config/amplify_outputs/analytics/analytics_outp
import 'package:amplify_core/src/config/amplify_outputs/auth/auth_outputs.dart';
import 'package:amplify_core/src/config/amplify_outputs/data/data_outputs.dart';
import 'package:amplify_core/src/config/amplify_outputs/notifications/notifications_outputs.dart';
import 'package:amplify_core/src/config/amplify_outputs/rest_api/rest_api_outputs.dart';
import 'package:amplify_core/src/config/amplify_outputs/storage/storage_outputs.dart';
import 'package:json_annotation/json_annotation.dart';
import 'package:meta/meta.dart';

part 'amplify_outputs.g.dart';
Expand All @@ -26,6 +28,7 @@ class AmplifyOutputs
this.analytics,
this.auth,
this.data,
this.restApi,
this.notifications,
this.storage,
this.custom,
Expand All @@ -47,7 +50,12 @@ class AmplifyOutputs
final AuthOutputs? auth;

/// {@macro amplify_core.amplify_outputs.data_outputs}
final DataOutputs? data;
@JsonKey(fromJson: _dataFromJson, toJson: _dataToJson)
final Map<String, DataOutputs>? data;

/// {@macro amplify_core.amplify_outputs.rest_api_outputs}
@internal
final Map<String, RestApiOutputs>? restApi;

/// {@macro amplify_core.amplify_outputs.notifications_outputs}
final NotificationsOutputs? notifications;
Expand All @@ -61,8 +69,17 @@ class AmplifyOutputs
final Map<String, dynamic>? custom;

@override
List<Object?> get props =>
[schema, version, analytics, auth, data, notifications, storage, custom];
List<Object?> get props => [
schema,
version,
analytics,
auth,
data,
restApi,
notifications,
storage,
custom,
];

@override
String get runtimeTypeName => 'AmplifyOutputs';
Expand All @@ -72,3 +89,36 @@ class AmplifyOutputs
return _$AmplifyOutputsToJson(this);
}
}

/// The name of the API plugin when a Gen 2 config is used.
///
/// "data" is consistent with the name Gen 2 uses when generating a Gen 1 config.
/// reference: https://github.com/aws-amplify/amplify-backend/blob/4dd9d5a35c378895d1360c15a3b7ad1f09cc7653/packages/client-config/src/client-config-writer/client_config_to_mobile_legacy_converter.ts#L93
const _dataPluginName = 'data';

/// Converts a single data json object to a map of [DataOutputs].
///
/// This manual mapping is required since the Amplify Outputs schema only supports
/// a single data object, but Amplify Flutter supports more than 1.
Map<String, DataOutputs>? _dataFromJson(Map<String, Object?>? object) {
if (object == null) return null;
return {
_dataPluginName: DataOutputs.fromJson(object),
};
}

/// Converts a map of [DataOutputs] to a single data json object.
///
/// This manual mapping is required since the Amplify Outputs schema only supports
/// a single data object, but Amplify Flutter supports more than 1.
Object? _dataToJson(Map<String, DataOutputs>? outputs) {
if (outputs == null) return null;
if (outputs.length > 1) {
throw ConfigurationError(
'Found ${outputs.length} endpoints.'
' Amplify Outputs does not support multiple GraphQL endpoints.',
);
}
final data = outputs[_dataPluginName];
return data?.toJson();
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

import 'package:amplify_core/amplify_core.dart';

part 'rest_api_outputs.g.dart';

/// {@template amplify_core.amplify_outputs.rest_api_outputs}
/// An internal representation of Rest API.
///
/// This class should not be exposed publicly since the Gen 2 schema does not
/// support Rest API. This class exists to support Gen 1 configs that use Rest API.
/// {@endtemplate}
@zAmplifyOutputsSerializable
class RestApiOutputs
with AWSEquatable<RestApiOutputs>, AWSSerializable, AWSDebuggable {
/// {@macro amplify_core.amplify_outputs.rest_api_outputs}
const RestApiOutputs({
required this.awsRegion,
required this.url,
this.apiKey,
required this.authorizationType,
});

factory RestApiOutputs.fromJson(Map<String, Object?> json) =>
_$RestApiOutputsFromJson(json);

/// The AWS region of Amazon AWS Gateway resources.
final String awsRegion;

/// The AWS Gateway endpoint URL.
final String url;

/// The AppSync API Key.
final String? apiKey;

/// The authorization type.
final APIAuthorizationType authorizationType;

@override
List<Object?> get props => [
awsRegion,
url,
apiKey,
authorizationType,
];

@override
String get runtimeTypeName => 'RestApiOutputs';

@override
Object? toJson() {
return _$RestApiOutputsToJson(this);
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import 'package:amplify_core/amplify_core.dart';
import 'package:amplify_core/src/config/amplify_outputs/analytics/amazon_pinpoint_outputs.dart';
import 'package:amplify_core/src/config/amplify_outputs/analytics/analytics_outputs.dart';
import 'package:meta/meta.dart';

export 'pinpoint_config.dart' hide PinpointPluginConfigFactory;

Expand Down Expand Up @@ -33,6 +34,7 @@ class AnalyticsConfig extends AmplifyPluginConfigMap {
@override
Map<String, Object?> toJson() => _$AnalyticsConfigToJson(this);

@internal
AnalyticsOutputs? toAnalyticsOutputs() {
final plugin = awsPlugin?.pinpointAnalytics;
if (plugin == null) {
Expand Down
69 changes: 53 additions & 16 deletions packages/amplify_core/lib/src/config/api/api_config.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

import 'package:amplify_core/amplify_core.dart';
import 'package:amplify_core/src/config/amplify_outputs/data/data_outputs.dart';
import 'package:amplify_core/src/config/amplify_outputs/rest_api/rest_api_outputs.dart';
import 'package:meta/meta.dart';

export 'aws_api_config.dart' hide AWSApiPluginConfigFactory;

Expand Down Expand Up @@ -32,24 +34,59 @@ class ApiConfig extends AmplifyPluginConfigMap {
@override
Map<String, Object?> toJson() => _$ApiConfigToJson(this);

DataOutputs? toDataOutputs({AWSConfigMap<CognitoAppSyncConfig>? appSync}) {
final plugin = appSync?.default$;
@internal
Map<String, DataOutputs>? toDataOutputs({
AWSConfigMap<CognitoAppSyncConfig>? appSync,
}) {
final plugins = _getPlugins(EndpointType.graphQL);
if (plugins == null) {
return null;
}
return plugins.map((key, plugin) {
final defaultAuthorizationType = plugin.authorizationType;
final awsRegion = plugin.region;
final url = plugin.endpoint;
final allModes = (appSync?.all.values ?? []);
final authorizationTypes = allModes
.where((plugin) => plugin.apiUrl == url && plugin.region == awsRegion)
.map((config) => config.authMode)
.where((mode) => mode != defaultAuthorizationType)
.toList();
final data = DataOutputs(
awsRegion: awsRegion,
url: url,
defaultAuthorizationType: defaultAuthorizationType,
apiKey: plugin.apiKey,
authorizationTypes: authorizationTypes,
);
return MapEntry(key, data);
});
}

@internal
Map<String, RestApiOutputs>? toRestApiOutputs() {
final plugins = _getPlugins(EndpointType.rest);
if (plugins == null) {
return null;
}
return plugins.map((key, plugin) {
final rest = RestApiOutputs(
awsRegion: plugin.region,
url: plugin.endpoint,
authorizationType: plugin.authorizationType,
apiKey: plugin.apiKey,
);
return MapEntry(key, rest);
});
}

Map<String, AWSApiConfig>? _getPlugins(EndpointType endpointType) {
final plugin = awsPlugin;
if (plugin == null) {
return null;
}
final region = plugin.region;
final url = plugin.apiUrl;
final apiKey = plugin.apiKey;
final defaultAuthorizationType = plugin.authMode;
final modes = appSync?.all.values.map((config) => config.authMode) ?? [];
final authorizationTypes =
modes.where((mode) => mode != defaultAuthorizationType).toList();
return DataOutputs(
awsRegion: region,
url: url,
defaultAuthorizationType: defaultAuthorizationType,
apiKey: apiKey,
authorizationTypes: authorizationTypes,
);
final entries =
plugin.all.entries.where((p) => p.value.endpointType == endpointType);
return Map<String, AWSApiConfig>.fromEntries(entries);
}
}
2 changes: 2 additions & 0 deletions packages/amplify_core/lib/src/config/auth/auth_config.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import 'package:amplify_core/src/config/amplify_outputs/auth/auth_outputs.dart';
import 'package:amplify_core/src/config/amplify_outputs/auth/oauth_outputs.dart';
import 'package:amplify_core/src/config/amplify_outputs/auth/oauth_response_type.dart';
import 'package:amplify_core/src/config/amplify_outputs/auth/password_policy.dart';
import 'package:meta/meta.dart';

export 'cognito_config.dart' hide CognitoPluginConfigFactory;

Expand Down Expand Up @@ -79,6 +80,7 @@ class AuthConfig extends AmplifyPluginConfigMap {
@override
AuthConfig copy() => AuthConfig(plugins: Map.of(plugins));

@internal
AuthOutputs? toAuthOutputs() {
final plugin = awsPlugin?.auth?.default$;
final userPool = awsPlugin?.cognitoUserPool?.default$;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

import 'package:amplify_core/amplify_core.dart';
import 'package:amplify_core/src/config/amplify_outputs/storage/storage_outputs.dart';
import 'package:meta/meta.dart';

export 's3_config.dart' hide S3PluginConfigFactory;

Expand Down Expand Up @@ -32,6 +33,7 @@ class StorageConfig extends AmplifyPluginConfigMap {
@override
Map<String, Object?> toJson() => _$StorageConfigToJson(this);

@internal
StorageOutputs? toStorageOutputs() {
final plugin = awsPlugin;
if (plugin == null) {
Expand Down
Loading
Loading