Giter Club home page Giter Club logo

Comments (10)

jimmyff avatar jimmyff commented on June 24, 2024

Just been digging through the source and I can't understand why JsonWithContextFunctionTarget<PubSub, void> isn't working for me. build_runner is correctly generating bin/server.dart, it's only when it's trying to deploy to cloud functions that it throws this error.

Wondering if I need to make my own FunctionTarget but I think there should be a simple way to get JsonWithContextFunctionTarget working?

from functions-framework-dart.

kevmoo avatar kevmoo commented on June 24, 2024

Does PubSub have a fromJson constructor and a toJson function?

from functions-framework-dart.

kevmoo avatar kevmoo commented on June 24, 2024

And/or have you tried typing your function FutureOr and marking it async?

from functions-framework-dart.

jimmyff avatar jimmyff commented on June 24, 2024

Hey @kevmoo thanks for the suggestions. Yeah pub sub class should be fine, this is it:

pub_sub_types.dart
import 'dart:convert';
import 'dart:typed_data';
import 'package:json_annotation/json_annotation.dart';

part 'pub_sub_types.g.dart';

@JsonSerializable()
class PubSub {
  final PubSubMessage message;
  final String subscription;
  PubSub(this.message, this.subscription);
  factory PubSub.fromJson(Map<String, dynamic> json) {
    try {
      return _$PubSubFromJson(json);
    } catch (e, s) {
      print('PubSub: Failed to parse json: $json');
      rethrow;
    }
  }
  Map<String, dynamic> toJson() => _$PubSubToJson(this);
}

@JsonSerializable()
class PubSubMessage {
  final String? data;
  final Map<String, String>? attributes;
  final String messageId;
  final DateTime publishTime;

  bool hasData() => data != null;
  Map<String, dynamic> jsonDecoded() => json.decode(dataDecoded());
  String dataDecoded() => utf8.decode(dataBytes());
  Uint8List dataBytes() =>
      data != null ? base64Decode(data!) : throw Exception('Data excected');

  PubSubMessage(this.data, this.messageId, this.publishTime, this.attributes);
  factory PubSubMessage.fromJson(Map<String, dynamic> json) {
    try {
      return _$PubSubMessageFromJson(json);
    } catch (e, s) {
      print('PubSubMessage: Failed to parse json: $json');
      rethrow;
    }
  }
  Map<String, dynamic> toJson() => _$PubSubMessageToJson(this);
}

// This was a test to see if returning this instead of void would help, it didn't
@JsonSerializable()
class PubSubResponse {
  final bool success;
  PubSubResponse(this.success);
  factory PubSubResponse.fromJson(Map<String, dynamic> json) {
    try {
      return _$PubSubResponseFromJson(json);
    } catch (e, s) {
      print('PubSubResponse: Failed to parse json: $json');
      rethrow;
    }
  }
  Map<String, dynamic> toJson() => _$PubSubResponseToJson(this);
}

I've tried every combination return types and async keyword but I get the not compatible shape error if I use any sort of Future / async. I tried creating a PubSubResponse class for ResponseType but that hasn't helped.

Should I look at registering my own function target? If so is there any advice where to start with that? I've had a quick scout around but I couldn't see where they're registered.

Thanks

from functions-framework-dart.

jimmyff avatar jimmyff commented on June 24, 2024

A little progress, it doesn't seem to be related to the Future/async. If I alter the package example to include the RequestContext parameter then it fails to deploy too:

@CloudFunction()
GreetingResponse function(GreetingRequest request, RequestContext context) {
  final name = request.name ?? 'World';
  final json = GreetingResponse(salutation: 'Hello', name: name);
  return json;
}

With the same error:

Not compatible with a supported function shape:
  HandlerWithLogger [FutureOr<Response> Function(Request, RequestLogger)] from package:functions_framework/functions_framework.dart
  Handler [FutureOr<Response> Function(Request)] from package:shelf/shelf.dart
  CloudEventWithContextHandler [FutureOr<void> Function(CloudEvent, RequestContext)] from package:functions_framework/functions_framework.dart
  CloudEventHandler [FutureOr<void> Function(CloudEvent)] from package:functions_framework/functions_framework.dart
  JsonHandler [FutureOr<ResponseType> Function(RequestType request, RequestContext context)] from package:functions_framework/functions_framework.dart
  JsonHandler [FutureOr<ResponseType> Function(RequestType request)] from package:functions_framework/functions_framework.dart

package:test_pubsub/functions.dart:55:18
   ╷
55 │ GreetingResponse function(GreetingRequest request, RequestContext context) {
   │                  ^^^^^^^^
   ╵
[INFO] Running build completed, took 15.9s

My function & the package example both work without RequestContext with Future return type and async keyword. They also work with a FutureOr<void> return type.

Why it builds on my local environment yet fails on docker & cloud run remains a mystery for now. All I can think was a dependency version discrepancy but I've pretty much locked all the dependency versions down to mirror cloud run and local.

from functions-framework-dart.

kevmoo avatar kevmoo commented on June 24, 2024

have you tried printing out the pubspec.lock file in CI? Comparing the versions of Dart?

The only example I can think of is if the analyzer version has changed...

from functions-framework-dart.

kevmoo avatar kevmoo commented on June 24, 2024
diff --git a/examples/json/lib/functions.dart b/examples/json/lib/functions.dart
index 4213df4..802a158 100644
--- a/examples/json/lib/functions.dart
+++ b/examples/json/lib/functions.dart
@@ -12,6 +12,8 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.

+import 'dart:async';
+
 import 'package:functions_framework/functions_framework.dart';
 import 'package:json_annotation/json_annotation.dart';

@@ -59,7 +61,7 @@ class GreetingResponse {
 }

 @CloudFunction()
-GreetingResponse function(GreetingRequest request) {
+Future<GreetingResponse> function(GreetingRequest request) async {
   final name = request.name ?? 'World';
   final json = GreetingResponse(salutation: 'Hello', name: name);
   return json;

I tried changing up the example in the repro to make it work...and it's fine.

I might could change this to support FutureOr but that doesn't seem to be blocking you

from functions-framework-dart.

jimmyff avatar jimmyff commented on June 24, 2024

Hey @kevmoo the issue only occurs when adding a RequestContext context parameter.

I've since modified my code not to require the context so this issue is not blocking me. I left the issue open because as far as I can tell, you should be able to use RequestContext context (Expected it to get picked up by the FunctionTarget: JsonHandler [FutureOr<ResponseType> Function(RequestType request, RequestContext context)]). The example code demonstrates the issue too with the additional RequestContext parameter.

Happy for this issue to be closed or left open.

from functions-framework-dart.

kevmoo avatar kevmoo commented on June 24, 2024

Yep. Let's call it an enhancement!

from functions-framework-dart.

kevmoo avatar kevmoo commented on June 24, 2024

I tried modifying the integration test file and it works perfectly.

I'm going to close this out.

If you can modify the integartion_test/lib/src/json_handlers.dart to reproduce the error, let me know.

diff --git a/integration_test/bin/server.dart b/integration_test/bin/server.dart
index 6b155d0..ad074d1 100644
--- a/integration_test/bin/server.dart
+++ b/integration_test/bin/server.dart
@@ -61,6 +61,29 @@ FunctionTarget? _nameToFunctionTarget(String name) => switch (name) {
             );
           },
         ),
+      'pubSubHandlerWithReplyAndContext' =>
+        JsonWithContextFunctionTarget.voidResult(
+          function_library.pubSubHandlerWithReplyAndContext,
+          (json) {
+            if (json is Map<String, dynamic>) {
+              try {
+                return function_library.PubSub.fromJson(json);
+              } catch (e, stack) {
+                throw BadRequestException(
+                  400,
+                  'There was an error parsing the provided JSON data.',
+                  innerError: e,
+                  innerStack: stack,
+                );
+              }
+            }
+            throw BadRequestException(
+              400,
+              'The provided JSON is not the expected type '
+              '`Map<String, dynamic>`.',
+            );
+          },
+        ),
       'jsonHandler' => JsonWithContextFunctionTarget(
           function_library.jsonHandler,
           (json) {
diff --git a/integration_test/lib/src/json_handlers.dart b/integration_test/lib/src/json_handlers.dart
index 7e7e9db..016d5d6 100644
--- a/integration_test/lib/src/json_handlers.dart
+++ b/integration_test/lib/src/json_handlers.dart
@@ -24,6 +24,17 @@ void pubSubHandler(PubSub pubSub, RequestContext context) {
   context.responseHeaders['multi'] = ['item1', 'item2'];
 }

+@CloudFunction()
+Future<void> pubSubHandlerWithReplyAndContext(
+  PubSub pubSub,
+  RequestContext context,
+) async {
+  print('subscription: ${pubSub.subscription}');
+  context.logger.info('subscription: ${pubSub.subscription}');
+  context.responseHeaders['subscription'] = pubSub.subscription;
+  context.responseHeaders['multi'] = ['item1', 'item2'];
+}
+
 @CloudFunction()
 FutureOr<bool> jsonHandler(
   Map<String, dynamic> request,

from functions-framework-dart.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.