call<I> method

Future<O> call<I>({
  1. required I input,
  2. Map<String, String>? headers,
})

Invokes the remote flow.

Implementation

Future<O> call<I>({required I input, Map<String, String>? headers}) async {
  final uri = Uri.parse(_url);
  final requestHeaders = {
    'Content-Type': 'application/json',
    ...?_defaultHeaders,
    ...?headers,
  };
  final requestBody = jsonEncode({'data': input});

  http.Response response;
  try {
    response = await _httpClient.post(
      uri,
      headers: requestHeaders,
      body: requestBody,
    );
  } catch (e, s) {
    throw GenkitException(
      'HTTP request failed: ${e.toString()}',
      underlyingException: e,
      stackTrace: s,
    );
  }

  if (response.statusCode != 200) {
    throw GenkitException(
      'Server returned error: ${response.statusCode}',
      statusCode: response.statusCode,
      details: response.body,
    );
  }

  dynamic decodedBody;
  try {
    decodedBody = jsonDecode(response.body);
  } on FormatException catch (e, s) {
    throw GenkitException(
      'Failed to decode JSON response: ${e.toString()}',
      underlyingException: e,
      details: response.body,
      stackTrace: s,
    );
  }

  if (decodedBody is Map<String, dynamic>) {
    if (decodedBody.containsKey('error')) {
      final errorData = decodedBody['error'];
      final message =
          (errorData is Map<String, dynamic> &&
              errorData.containsKey('message'))
          ? errorData['message'] as String
          : errorData.toString();
      throw GenkitException(message, details: jsonEncode(errorData));
    }
    if (decodedBody.containsKey('result')) {
      return _fromResponse(decodedBody['result']);
    }
  }

  // Fallback for non-standard successful responses.
  return _fromResponse(decodedBody);
}