Skip to content

Commit

Permalink
chore: support multiple graphql or rest APIs (#4982)
Browse files Browse the repository at this point in the history
  • Loading branch information
Jordan-Nelson authored and Nika Hassani committed Jun 7, 2024
1 parent f6cc0a4 commit bbf6e72
Show file tree
Hide file tree
Showing 10 changed files with 274 additions and 23 deletions.
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

0 comments on commit bbf6e72

Please sign in to comment.