Skip to content

Commit 1237afd

Browse files
authored
Breaking changes to functions_framework (#177)
See the changelog for all of the details tl;dr: enables future flexibility because we no longer require const constructors
1 parent 2db1109 commit 1237afd

16 files changed

+355
-374
lines changed

functions_framework/CHANGELOG.md

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,16 @@
11
# Changelog
22

3-
## 0.3.2-dev
3+
## 0.4.0-dev
4+
5+
- **BREAKING** `RequestContext`: removed deprecated `headers` and `headersAll`
6+
properties.
7+
- **BREAKING** `serve.dart`:
8+
- Changed the signature for `serve` function accept
9+
`FunctionTarget Function(String) nameToFunctionTarget` instead of
10+
`Set<FunctionTarget> targets`. This will allow more flexibility in future
11+
`FunctionTarget` implementations.
12+
- `FunctionTarget` no longer has a `const` constructor. The `name` parameter
13+
has also been removed.
414

515
- Allow the latest versions of `args`, `http`, `http_parser`, and `shelf`
616
packages.

functions_framework/lib/serve.dart

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,12 @@ export 'src/function_target.dart'
3535
/// If there are no configuration errors, this function will not return until
3636
/// the process has received signal [ProcessSignal.sigterm] or
3737
/// [ProcessSignal.sigint].
38-
Future<void> serve(List<String> args, Set<FunctionTarget> targets) async {
38+
Future<void> serve(
39+
List<String> args,
40+
FunctionTarget Function(String) nameToFunctionTarget,
41+
) async {
3942
try {
40-
await _serve(args, targets);
43+
await _serve(args, nameToFunctionTarget);
4144
} on BadConfigurationException catch (e) {
4245
stderr.writeln(red.wrap(e.message));
4346
if (e.details != null) {
@@ -47,21 +50,24 @@ Future<void> serve(List<String> args, Set<FunctionTarget> targets) async {
4750
}
4851
}
4952

50-
Future<void> _serve(List<String> args, Set<FunctionTarget> targets) async {
53+
Future<void> _serve(
54+
List<String> args,
55+
FunctionTarget Function(String) nameToFunctionTarget,
56+
) async {
5157
final configFromEnvironment = FunctionConfig.fromEnv();
5258

5359
final config = FunctionConfig.fromArgs(
5460
args,
5561
defaults: configFromEnvironment,
5662
);
5763

58-
final functionTarget = targets.singleWhere(
59-
(target) => target.name == config.target,
60-
orElse: () => throw BadConfigurationException(
64+
final functionTarget = nameToFunctionTarget(config.target);
65+
if (functionTarget == null) {
66+
throw BadConfigurationException(
6167
'There is no handler configured for '
6268
'$environmentKeyFunctionTarget `${config.target}`.',
63-
),
64-
);
69+
);
70+
}
6571

6672
if (functionTarget.type == FunctionType.cloudevent &&
6773
config.functionType == FunctionType.http) {

functions_framework/lib/src/function_target.dart

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -24,27 +24,21 @@ import 'typedefs.dart';
2424
export 'targets/json_targets.dart';
2525

2626
abstract class FunctionTarget {
27-
final String name;
28-
2927
FunctionType get type => FunctionType.http;
3028

31-
const FunctionTarget(this.name);
29+
FunctionTarget();
3230

33-
const factory FunctionTarget.http(String target, Handler function) =
34-
HttpFunctionTarget;
31+
factory FunctionTarget.http(Handler function) = HttpFunctionTarget;
3532

36-
const factory FunctionTarget.httpWithLogger(
37-
String target,
33+
factory FunctionTarget.httpWithLogger(
3834
HandlerWithLogger function,
3935
) = HttpWithLoggerFunctionTarget;
4036

41-
const factory FunctionTarget.cloudEvent(
42-
String target,
37+
factory FunctionTarget.cloudEvent(
4338
CloudEventHandler function,
4439
) = CloudEventFunctionTarget;
4540

46-
const factory FunctionTarget.cloudEventWithContext(
47-
String target,
41+
factory FunctionTarget.cloudEventWithContext(
4842
CloudEventWithContextHandler function,
4943
) = CloudEventWithContextFunctionTarget;
5044

functions_framework/lib/src/request_context.dart

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -29,25 +29,6 @@ class RequestContext {
2929

3030
final responseHeaders = <String, /* String | List<String> */ Object>{};
3131

32-
/// The HTTP headers with case-insensitive keys.
33-
///
34-
/// If a header occurs more than once in the query string, they are mapped to
35-
/// by concatenating them with a comma.
36-
///
37-
/// The returned map is unmodifiable.
38-
@Deprecated('Use request.headers instead')
39-
Map<String, String> get headers => request.headers;
40-
41-
/// The HTTP headers with multiple values with case-insensitive keys.
42-
///
43-
/// If a header occurs only once, its value is a singleton list.
44-
/// If a header occurs with no value, the empty string is used as the value
45-
/// for that occurrence.
46-
///
47-
/// The returned map and the lists it contains are unmodifiable.
48-
@Deprecated('Use request.headersAll instead')
49-
Map<String, List<String>> get headersAll => request.headersAll;
50-
5132
RequestContext._(this.request) : logger = loggerForRequest(request);
5233
}
5334

functions_framework/lib/src/targets/cloud_event_targets.dart

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -32,16 +32,14 @@ class CloudEventFunctionTarget extends FunctionTarget {
3232

3333
@override
3434
FutureOr<Response> handler(Request request) async {
35-
final event = _requiredBinaryHeader.every(request.headers.containsKey)
36-
? await _decodeBinary(request)
37-
: await _decodeStructured(request);
35+
final event = await _eventFromRequest(request);
3836

3937
await function(event);
4038

4139
return Response.ok('');
4240
}
4341

44-
const CloudEventFunctionTarget(String target, this.function) : super(target);
42+
CloudEventFunctionTarget(this.function);
4543
}
4644

4745
class CloudEventWithContextFunctionTarget extends FunctionTarget {
@@ -52,20 +50,22 @@ class CloudEventWithContextFunctionTarget extends FunctionTarget {
5250

5351
@override
5452
Future<Response> handler(Request request) async {
55-
final event = _requiredBinaryHeader.every(request.headers.containsKey)
56-
? await _decodeBinary(request)
57-
: await _decodeStructured(request);
53+
final event = await _eventFromRequest(request);
5854

5955
final context = contextForRequest(request);
6056
await function(event, context);
6157

6258
return Response.ok('', headers: context.responseHeaders);
6359
}
6460

65-
const CloudEventWithContextFunctionTarget(String target, this.function)
66-
: super(target);
61+
CloudEventWithContextFunctionTarget(this.function);
6762
}
6863

64+
Future<CloudEvent> _eventFromRequest(Request request) =>
65+
_requiredBinaryHeader.every(request.headers.containsKey)
66+
? _decodeBinary(request)
67+
: _decodeStructured(request);
68+
6969
Future<CloudEvent> _decodeStructured(Request request) async {
7070
final type = mediaTypeFromRequest(request);
7171

@@ -82,16 +82,20 @@ Future<CloudEvent> _decodeStructured(Request request) async {
8282
return _decodeValidCloudEvent(jsonObject, 'structured-mode message');
8383
}
8484

85-
Future<CloudEvent> _decodeBinary(Request request) async {
86-
final map = Map<String, dynamic>.fromEntries(request.headers.entries
87-
.where((element) => element.key.startsWith('ce-'))
88-
.map((e) => MapEntry(e.key.substring(3), e.value)));
85+
const _cloudEventPrefix = 'ce-';
86+
const _clientEventPrefixLength = _cloudEventPrefix.length;
8987

88+
Future<CloudEvent> _decodeBinary(Request request) async {
9089
final type = mediaTypeFromRequest(request);
91-
9290
mustBeJson(type);
93-
map['datacontenttype'] = type.toString();
94-
map['data'] = await decodeJson(request);
91+
92+
final map = <String, Object>{
93+
for (var e in request.headers.entries
94+
.where((element) => element.key.startsWith(_cloudEventPrefix)))
95+
e.key.substring(_clientEventPrefixLength): e.value,
96+
'datacontenttype': type.toString(),
97+
'data': await decodeJson(request),
98+
};
9599

96100
return _decodeValidCloudEvent(map, 'binary-mode message');
97101
}

functions_framework/lib/src/targets/http_targets.dart

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ class HttpFunctionTarget extends FunctionTarget {
2626
@override
2727
FutureOr<Response> handler(Request request) => _function(request);
2828

29-
const HttpFunctionTarget(String target, this._function) : super(target);
29+
HttpFunctionTarget(this._function);
3030
}
3131

3232
class HttpWithLoggerFunctionTarget extends FunctionTarget {
@@ -36,6 +36,5 @@ class HttpWithLoggerFunctionTarget extends FunctionTarget {
3636
FutureOr<Response> handler(Request request) =>
3737
_function(request, loggerForRequest(request));
3838

39-
const HttpWithLoggerFunctionTarget(String target, this._function)
40-
: super(target);
39+
HttpWithLoggerFunctionTarget(this._function);
4140
}

functions_framework/lib/src/targets/json_targets.dart

Lines changed: 17 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,7 @@ import '../typedefs.dart';
2525
abstract class _JsonFunctionTargetBase<RequestType> extends FunctionTarget {
2626
final RequestType Function(Object) _fromJson;
2727

28-
const _JsonFunctionTargetBase(
29-
String target,
30-
this._fromJson,
31-
) : super(target);
28+
_JsonFunctionTargetBase(this._fromJson);
3229

3330
Future<RequestType> _toRequestType(Request request) async {
3431
final type = mediaTypeFromRequest(request);
@@ -42,32 +39,28 @@ abstract class JsonFunctionTarget<RequestType, ResponseType>
4239
extends _JsonFunctionTargetBase<RequestType> {
4340
final JsonHandler<RequestType, ResponseType> _function;
4441

45-
const JsonFunctionTarget._(
46-
String target,
42+
JsonFunctionTarget._(
4743
this._function,
4844
RequestType Function(Object) fromJson,
49-
) : super(target, fromJson);
45+
) : super(fromJson);
5046

51-
const factory JsonFunctionTarget(
52-
String target,
47+
factory JsonFunctionTarget(
5348
JsonHandler<RequestType, ResponseType> function,
5449
RequestType Function(Object) fromJson,
5550
) = _JsonFunctionTarget<RequestType, ResponseType>;
5651

57-
const factory JsonFunctionTarget.voidResult(
58-
String target,
52+
factory JsonFunctionTarget.voidResult(
5953
JsonHandler<RequestType, ResponseType> function,
6054
RequestType Function(Object) fromJson,
6155
) = _VoidJsonFunctionTarget<RequestType, ResponseType>;
6256
}
6357

6458
class _JsonFunctionTarget<RequestType, ResponseType>
6559
extends JsonFunctionTarget<RequestType, ResponseType> {
66-
const _JsonFunctionTarget(
67-
String target,
60+
_JsonFunctionTarget(
6861
JsonHandler<RequestType, ResponseType> function,
6962
RequestType Function(Object) fromJson,
70-
) : super._(target, function, fromJson);
63+
) : super._(function, fromJson);
7164

7265
@override
7366
FutureOr<Response> handler(Request request) async {
@@ -84,11 +77,10 @@ class _JsonFunctionTarget<RequestType, ResponseType>
8477

8578
class _VoidJsonFunctionTarget<RequestType, ResponseType>
8679
extends JsonFunctionTarget<RequestType, ResponseType> {
87-
const _VoidJsonFunctionTarget(
88-
String target,
80+
_VoidJsonFunctionTarget(
8981
JsonHandler<RequestType, ResponseType> function,
9082
RequestType Function(Object) fromJson,
91-
) : super._(target, function, fromJson);
83+
) : super._(function, fromJson);
9284

9385
@override
9486
FutureOr<Response> handler(Request request) async {
@@ -102,32 +94,28 @@ abstract class JsonWithContextFunctionTarget<RequestType, ResponseType>
10294
extends _JsonFunctionTargetBase<RequestType> {
10395
final JsonWithContextHandler<RequestType, ResponseType> _function;
10496

105-
const JsonWithContextFunctionTarget._(
106-
String target,
97+
JsonWithContextFunctionTarget._(
10798
this._function,
10899
RequestType Function(Object) fromJson,
109-
) : super(target, fromJson);
100+
) : super(fromJson);
110101

111-
const factory JsonWithContextFunctionTarget(
112-
String target,
102+
factory JsonWithContextFunctionTarget(
113103
JsonWithContextHandler<RequestType, ResponseType> function,
114104
RequestType Function(Object) fromJson,
115105
) = _JsonWithContextFunctionTarget<RequestType, ResponseType>;
116106

117-
const factory JsonWithContextFunctionTarget.voidResult(
118-
String target,
107+
factory JsonWithContextFunctionTarget.voidResult(
119108
JsonWithContextHandler<RequestType, ResponseType> function,
120109
RequestType Function(Object) fromJson,
121110
) = _VoidJsonWithContextFunctionTarget<RequestType, ResponseType>;
122111
}
123112

124113
class _JsonWithContextFunctionTarget<RequestType, ResponseType>
125114
extends JsonWithContextFunctionTarget<RequestType, ResponseType> {
126-
const _JsonWithContextFunctionTarget(
127-
String target,
115+
_JsonWithContextFunctionTarget(
128116
JsonWithContextHandler<RequestType, ResponseType> function,
129117
RequestType Function(Object) fromJson,
130-
) : super._(target, function, fromJson);
118+
) : super._(function, fromJson);
131119

132120
@override
133121
FutureOr<Response> handler(Request request) async {
@@ -150,11 +138,10 @@ class _JsonWithContextFunctionTarget<RequestType, ResponseType>
150138

151139
class _VoidJsonWithContextFunctionTarget<RequestType, ResponseType>
152140
extends JsonWithContextFunctionTarget<RequestType, ResponseType> {
153-
const _VoidJsonWithContextFunctionTarget(
154-
String target,
141+
_VoidJsonWithContextFunctionTarget(
155142
JsonWithContextHandler<RequestType, ResponseType> function,
156143
RequestType Function(Object) fromJson,
157-
) : super._(target, function, fromJson);
144+
) : super._(function, fromJson);
158145

159146
@override
160147
FutureOr<Response> handler(Request request) async {

functions_framework/pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
name: functions_framework
2-
version: 0.3.2-dev
2+
version: 0.4.0-dev
33
description: >-
44
FaaS (Function as a service) framework for writing portable Dart functions
55
repository: https://github.com/GoogleCloudPlatform/functions-framework-dart

functions_framework_builder/CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
# Changelog
22

3-
## 0.3.2-dev
3+
## 0.4.0-dev
44

5+
- Support the latest `package:functions_framework` version.
56
- Allow the latest version `package:shelf`.
67

78
## 0.3.1

functions_framework_builder/lib/builder.dart

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -85,15 +85,9 @@ class _FunctionsFrameworkBuilder implements Builder {
8585
entries[targetName] = invokeExpression;
8686
}
8787

88-
final functions = <String>[];
89-
final factories = <String>[];
90-
for (var e in entries.values) {
91-
final factory = e.createFactory(functions.length);
92-
if (factory != null) {
93-
factories.add(factory);
94-
}
95-
functions.add(' ${e.createReference(functions.length)},');
96-
}
88+
final cases = [
89+
for (var e in entries.values) ' case ${e.name}:return ${e.expression};',
90+
];
9791

9892
var output = '''
9993
// GENERATED CODE - DO NOT MODIFY BY HAND
@@ -115,17 +109,23 @@ import 'package:functions_framework/serve.dart';
115109
import '${input.uri}' as $functionsLibraryPrefix;
116110
117111
Future<void> main(List<String> args) async {
118-
await serve(args, _functionTargets);
112+
await serve(args, _nameToFunctionTarget);
119113
}
120114
121-
const _functionTargets = <FunctionTarget>{
122-
${functions.join('\n')}
123-
};
124-
125-
${factories.join('\n')}
115+
FunctionTarget _nameToFunctionTarget(String name) {
116+
switch (name) {
117+
${cases.join('\n')}
118+
default:
119+
return null;
120+
}
121+
}
126122
''';
127123

128-
output = DartFormatter().format(output);
124+
try {
125+
output = DartFormatter().format(output);
126+
} on FormatterException catch (e, stack) {
127+
log.warning('Could not format output.', e, stack);
128+
}
129129

130130
await buildStep.writeAsString(
131131
AssetId(

0 commit comments

Comments
 (0)