Git Product home page Git Product logo

googleapis.dart's Introduction

Package source Description Published Version
_discoveryapis_commons Library for use by client APIs generated from Discovery Documents. pub package
discoveryapis_generator Create API Client libraries based on the Discovery API Service. pub package
googleapis Auto-generated client libraries for accessing Google APIs described through the API discovery service. pub package
googleapis_beta Auto-generated client libraries for accessing Google APIs described through the API discovery service. pub package
googleapis_auth Obtain Access credentials for Google services using OAuth 2.0 pub package

Google API Client Libraries with Dart

Google provides a large set of APIs that your applications can use to interact with Google products such as Google Drive, Gmail, Cloud Datastore, and Cloud Storage. These APIs are accessible via REST-like interfaces. The Dart team provides the googleapis and googleapis_beta packages, which provide generated Dart libraries for these APIs. Using the APIs, which are available for both web apps and cloud apps, is more convenient and less error-prone than using the raw REST protocol.

To use any of these APIs, you need a Cloud Project. In addition, based on the API being used, you need either an API key or a Client ID. And finally, depending on what kind of application is being used, you might need a Service Account. All these items are available through Google Developers Console when you create a project. Below are a few scenarios:

  • APIs require a Client ID specific to the kind of application when it accesses data that is owned by a user on behalf of that user (with consent): for example a browser application or a console application.

  • A server application can access data owned by the application itself by using a Service Account. Example: a server application accessing data in Datastore or Google Cloud Storage.

  • APIs that can be used to get public data require only an API key (for quota and billing purposes).

To set up authentication and authorization for your app, you need to create a project, create the authentication credentials, and activate the API you want to use, all of which you do at Google Developers Console.

Support for Google APIs is in two packages—googleapis and googleapis_beta. The googleapis package contains the APIs for all the APIs that are available in a stable version. The googleapis_beta package contains the APIs that are currently in beta and possibly only available through a Limited Preview program.

A third package, googleapis_auth, provides a way to obtain OAuth 2.0 credentials and an authenticated HTTP client required to use these APIs.

The rest of this document describes the following:

Some of the APIs you can use

Here are just a few of the APIs your Dart programs can use.

Google Drive
Google Drive is a Cloud Storage service that allows you to store your documents, photos, videos, and more online. The Google Drive client library lets you access Google Drive services, such as reading and writing files.
Gmail
The Gmail API gives you flexible, RESTful access to the user's inbox, with a natural interface to threads, messages, labels, drafts, and history.
Cloud Datastore
Using Cloud Datastore client libraries you have access to a fully managed, schemaless database for storing non-relational data. Cloud Datastore provides high availability of reads and writes, strong consistency for reads and ancestor queries, and eventual consistency for all other queries.
Google Cloud Storage
Google Cloud Storage provides a fast, scalable, highly available object store that scales as your needs grow. You can access your data with an HTTP API, a web-based interface, or a commmand-line tool.

You can see the full list of APIs at googleapis and googleapis_beta.

OAuth 2.0

Applications sometimes require OAuth 2.0 for authentication and authorization. Whether an application needs OAuth 2.0 depends on the API being used and the kind of data being accessed. For example, an application needs OAuth 2.0 if it needs user consent. An application sometimes needs OAuth 2.0 depending on the following properties:

  • Using public API (no credentials needed)
  • Using API that can be accessed using an API Key (no concrete user)
  • Using API that provides access to user data (user consent)
  • Using API that provides access to application data (service account)

The OAuth 2.0 protocol provides different flows for different types of applications, including web server, installed, and client-side applications. For example, the following diagram illustrates the flow of communication for client-side applications:

Token flow in client-only (JavaScript) application

Using OAuth 2.0 to Access Google APIs gives a detailed overview of the OAuth 2.0 authorization scenarios that Google supports.

What do you need?

To write a program that interacts with a Google product, you need several tools and packages.

A Google account
If you don't already have a Google account, you can create one at Create your Google Account.
A project in Google Developers Console
Every application that uses the client libraries needs a project in Google Developers Console. A project is a collection of settings, credentials, and metadata about the application. Google Developers Console is where you manage aspects of your project, such as authenticating and authorizing you application, activating APIs, and managing team and billing information associated with your project. You must have a project to get OAuth2 service accounts and client IDs.
The googleapis_auth package
Access to Google APIs uses the HTTP protocol. The googleapis_auth package provides different means for creating an HTTP client that can handle the authorization. This HTTP client is then passed to the API objects and takes care of augmenting the communication with the required authorization information. The Dart googleapis_auth client library is available at pub.dev/packages/googleapis_auth. There you can find a detailed README file with code examples and explanatory text.
The googleapis or googleapis_beta package
These packages are publicly available at pub.dev/packages/googleapis and pub.dev/packages/googleapis_beta. Later, you'll see an example of how to use them in your Dart program.
Dart
Get Dart from the download page.

A web application example

Let's look at a web application example that uses the googleapis Google Drive API to retrieve documents from a user's Google Drive. The following screenshot shows the app after it has retrieved a list of spreadsheets from a user's Google Drive and displayed them on the page.

A list of spreadsheets retrieved from Google Drive using client library APIs

You can find the source code for this example, drive_search_web, and others, at googleapis_examples on GitHub.

The section Example explained describes the code in the drive_search_web example related to googleapis and googleapis_auth. But first let's look at how to run the example.

Running the example

To run this example, you need to create a project, activate an API, and create a Client ID in Google Developers Console. This section provides instructions about how to do these for this particular example. For complete information and detailed explanations, refer to Google Developers Console Help.

Create project

  • Go to Google Developers Console.

  • Click the Create Project button.

  • Provide a name for your project.

  • Click the Create button.

Activate the Drive API

  • On left of the project page, click APIs & auth, click APIs.

  • Turn on the authentication for Drive API. It might take a couple of minutes to propagate.

Create a client ID

  • On the left of the project page, under APIs & Auth, then click Credentials.

  • Click Create new Client ID.

  • In the popup window, click Web application, then fill in the form. Use http://localhost:8080 for Authorized JavaScript origins. Because this example is a client-side-only application, don't put a value in Authorized redirect URIs. This example runs on the local computer and uses port 8080. Ensure nothing else is using port 8080. If you later run this example from a different origin, you'll need a new Client ID.

  • Click Create Client ID.

Run the example

  • In the index.dart file, change to the client ID generated in the previous step. The client ID ends in apps.googeusercontent.com.

  • In the top directory of the application, run pub serve.

  • Visit http://localhost:8080 in a browser window. After a little while, you'll see a built version of the app.

  • Click Authorize and accept the authorization on the page that appears.

  • Select a document type from the drop-down menu and click List. The program displays the list of files from the Google Drive of the user who is currently logged in. (Later the user can revoke access if desired.) Refer to Security - Account Settings for details.

This example, drive_search_web, uses the Google Drive API and the OAuth 2.0 API to access the user's files on Google Drive. Let's look at the relevant parts of the example.

  • To use the googleapi packages, you need to declare dependencies in the pubspec.yaml file.
dependencies:
  googleapis_auth: '>=0.1.0 < 0.2.0'
  googleapis: '>=0.1.1 < 0.2.0'
  • In addition to declaring dependencies, you need to import the libraries from the packages into your Dart file. This example has only one Dart file, index.dart, which imports the libraries like this:
import 'package:googleapis_auth/auth_browser.dart' as auth;
import 'package:googleapis/drive/v2.dart' as drive;
  • At the top level, the program gets an identifier for the client with its ID created in Google Developers Console. In addition, the code defines the scope of the APIs it intends to use. The scope controls the set of APIs or parts of APIs that can access token permits. During the access-token request, your application sends one or more values in the scope parameter.
final identifier = new auth.ClientId(
     "<custom-app-id>.apps.googleusercontent.com",
     null);

final scopes = [drive.DriveApi.DriveScope];
  • The main() method authorizes the client with a call to authorizedClient(), passing the identifier and scopes in as parameters.
authorizedClient(loginButton, identifier, scopes).then((client) {
  ...
}

Let's take a look at authorizedClient().

Future authorizedClient(ButtonElement loginButton, auth.ClientId id, scopes) {
  return auth.createImplicitBrowserFlow(id, scopes)
      .then((auth.BrowserOAuth2Flow flow) {
        return flow.clientViaUserConsent(forceUserConsent: false).catchError((_) {
          loginButton.text = '';
          return loginButton.onClick.first.then((_) {
            return flow.clientViaUserConsent(forceUserConsent: true);
          });
        }, test: (error) => error is auth.UserConsentException);
  });
}

First the code initializes the browser flow as illustrated in the OAuth 2.0 diagram above. Then the program attempts to proceed without user consent using flow.clientViaUserConsent() with false as a parameter value. If the user previously gave consent, this will succeed. Otherwise, the program sets up the authorization button in the UI. When the user presses the button, the program brings up a popup window where the user can provide consent. To ask the user for consent, the code call flow.clientViaUserConsent() again using true for the parameter value.

  • In the main() function, the code gets access to the Drive API by creating a new DriveApi object and passing in the HTTP client.
var api = new drive.DriveApi(client);
  • The code uses the API provided by the DriveApi object to search the user's documents:
Future<List<drive.File>> searchTextDocuments(drive.DriveApi api,
                                             int max,
                                             String query) {
  var docs = [];
  Future next(String token) {
    // The API call returns only a subset of the results. It is possible
    // to query through the whole result set via "paging".
    return api.files.list(q: query, pageToken: token, maxResults: max)
        .then((results) {
      docs.addAll(results.items);
      // If we would like to have more documents, we iterate.
      if (docs.length < max && results.nextPageToken != null) {
        return next(results.nextPageToken);
      }
      return docs;
    });
  }
  return next(null);
}

Using a service account for a Cloud API

For APIs such as Cloud Datastore and Cloud Storage you need a Google service account, which is an account that represents your application instead of an individual end user. You can create one when creating a new Client ID: just click Service account instead of Web application.

The example cloudstorage_upload_download_service_account needs a service account because it uses the Google Cloud Storage API.

Let's take a quick look at the relevant code.

The following code creates account credentials from the service account specified in the details of the given JSON string. After you create the service account, you can download the JSON from the Cloud Console. Then enter the appropriate information to replace the placeholders.

final accountCredentials = new auth.ServiceAccountCredentials.fromJson(r'''
{
  "private_key_id": "<please fill in>",
  "private_key": "<please fill in>",
  "client_email": "<please fill in>@developer.gserviceaccount.com",
  "client_id": "<please fill in>.apps.googleusercontent.com",
  "type": "service_account"
}
''');

The program selects the scopes it will use and gets the StorageAPI, just like the previous example retrieved the Drive API.

final scopes = [storage.StorageApi.DevstorageFullControlScope];
...
var api = new storage.StorageApi(client);

Using the credentials and scopes parameters, a call to clientViaServiceAccount gets an authenticated client that can use the Storage APIs.

auth.clientViaServiceAccount(accountCredentials, scopes).then((client) {
  ...
  var regexp = new RegExp(r'^gs://([^/]+)/(.+)$');
  switch (args.first) {
    case 'upload':
  ...
}

Note that the code shown above creates accountCredentials, which identifies this application. The code specified by then() processes the command-line arguments and uploads or downloads a file as indicated.

The following line of code uses the Storage API to upload a media file to Google Cloud Storage.

return api.objects.insert(null, bucket, name: object, uploadMedia: media);

Resource links

Here's a convenient list of the resources you might need:

Contribute

The following notes for those who are contributing to this package. If you are only using this package, you can skip this section.

If you are only making changes to googleapis_auth, then you only need to run tests for that package and can skip the remainder of this section. Specifically, before submitting a pull request:

$ pushd googleapis_auth
$ pub get
$ pub run test
$ dart format . --fix
$ popd

Otherwise...

  • Clone this package and run pub upgrade from the generator directory.

    $ cd generator
    $ rm -rf .dart_tool
    $ pub upgrade
  • Download and generate the APIs using the config.yaml configuration (avoid doing this on corp network, use cloudshell instead).

    $ dart generator/bin/generate.dart run_config download

Note: You may need to reset some of the downloaded discovery documents, such as drive, or prediction.

  • Generate the APIs.

    $ dart generator/bin/generate.dart run_config generate
  • Create a diff with the previous APIs to determine whether a minor or a major update to the version number is required.

  • Update the appropriate CHANGELOG.md file under resources/.

  • Update config.yaml with a new version number and generate again.

    $ dart generator/bin/generate.dart run_config generate
  • Run the tests.

    $ pushd generated/googleapis
    $ pub get
    $ pub run test
    $ cd ../googleapis_beta
    $ pub get
    $ pub run test
    $ popd
  • Commit the downloaded discovery documents and generated packages.

Overrides

If you ever need to ignore a specific API method or make a manual change to anything inside discovery/, you should add the relevant diff to the overrides/ directory.

  • Make changes to the overrides/<desired-api>.json file.
  • Run git diff overrides/<desired-api>.json > overrides/<name>.diff to create a diff file.

Note: The name of the diff file is not important, but if possible, it is advised to associate the name with the relevant GitHub issue. For example, if your manual change is related to issue #123, then the diff file should be named i123.diff.

What next?

  • Read the README and the code for the packages on pub.dev: googleapis_auth.

  • Check out additional APIs that are currently in beta and possibly only available through a Limited Preview program: googleapis_beta.

  • Play with some examples.

  • Read the reference documentation. These APIs are common to many languages including Python, Java, and others. You can refer to the general reference documentation at the developers' products page. Find the product you're interested in on that page and follow the link. Be sure to look the API reference docs for Dart as some of the Dart APIs have quirks.

googleapis.dart's People

Contributors

abdulmalikdev avatar bryanoltman avatar codadillo avatar davidmorgan avatar dependabot[bot] avatar devoncarew avatar franklinyow avatar frgmt avatar grant avatar he-lu avatar jakobr-google avatar jonasfj avatar kevmoo avatar kirill-21 avatar lesnitsky avatar melbournedeveloper avatar mkustermann avatar natebosch avatar nickmeinhold avatar sfshaza2 avatar sgjesse avatar slightfoot avatar srawlins avatar subfuzion avatar torbenkeller avatar wibling avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

googleapis.dart's Issues

Translate API not working correctly

For some reason, the Translate API is not generated correctly, I think.

In translate/v2.dart#L590 it just checks for the existance of the "translations" key, while the Map actually has a toplevel "data" key.

Map object fed into the fromJson method:

{data: {translations: [{translatedText: Hello, detectedSourceLanguage: de}]}}

FirestoreApi.projects.databases.documents.runQuery throws Exception when query returns list

Running the following code

  responses = await (new FirestoreApi(http_client))
      .projects
      .databases
      .documents
      .runQuery(
        //This should really be a RunQueryRequest, but you get the idea
        "{structuredQuery: {from: [{collectionId: messages}], limit: 10, orderBy: [{direction: DESCENDING, field: {fieldPath: createdAt}}]}}",
        "projects/REDACTED/databases/(default)/documents/channels/-KyrWc1BnJF2OlXLhRVV",
        $fields: "document(fields,name)",
      );

Throws an exception:

type 'List' is not a subtype of type 'Map' of '_json@710331970' where
  List is from dart:core
  Map is from dart:core

The reason is that RunQueryResponse.fromJson expects a single document (core.Map), while the query above returns a collection (core.List).

I think I am using the query API correctly. Are the API specs incorrect in this case?

[cloud_speech] Streaming response support

The cloud speech API supports streaming recognition via gRPC, but the dart cloud-speech package doesn't support streaming recognition, is there any planned support for this?

[Dart2] Drive V3 File.fromJson type 'List<dynamic>' is not a subtype of type 'List<String>'

Hello,

i'm having the following error when calling:
files.list

E/flutter ( 2708): type 'List<dynamic>' is not a subtype of type 'List<String>' where
E/flutter ( 2708):   List is from dart:core
E/flutter ( 2708):   List is from dart:core
E/flutter ( 2708):   String is from dart:core
E/flutter ( 2708):
E/flutter ( 2708): #0      new File.fromJson (package:googleapis/drive/v3.dart:4274:22)
E/flutter ( 2708): #1      new FileList.fromJson.<anonymous closure> (package:googleapis/drive/v3.dart:4546:37)
E/flutter ( 2708): #2      MappedListIterable.elementAt (dart:_internal/iterable.dart:414:29)
E/flutter ( 2708): #3      ListIterable.toList (dart:_internal/iterable.dart:219:19)
E/flutter ( 2708): #4      new FileList.fromJson (package:googleapis/drive/v3.dart:4547:12)
E/flutter ( 2708): #5      FilesResourceApi.list.<anonymous closure> (package:googleapis/drive/v3.dart:1321:41)
E/flutter ( 2708): #6      _RootZone.runUnary (dart:async/zone.dart:1381:54)
E/flutter ( 2708): #7      _FutureListener.handleValue (dart:async/future_impl.dart:129:18)

Error running googleapi on flutter

I run the example in flutter and i get an error:

import 'package:googleapis/storage/v1.dart';
import 'package:googleapis_auth/auth_io.dart';

final _credentials = new ServiceAccountCredentials.fromJson(r'''
{
  "private_key_id": ...,
  "private_key": ...,
  "client_email": ...,
  "client_id": ...,
  "type": "service_account"
}
''');

const _SCOPES = const [StorageApi.DevstorageReadOnlyScope];

void main() {
  clientViaServiceAccount(_credentials, _SCOPES).then((http_client) {
    var storage = new StorageApi(http_client);
    storage.buckets.list('dart-on-cloud').then((buckets) {
      print("Received ${buckets.items.length} bucket names:");
      for (var file in buckets.items) {
        print(file.name);
      }
    });
  });
}

E/flutter ( 752): [ERROR:topaz/lib/tonic/logging/dart_error.cc(16)] Unhandled exception:
E/flutter ( 752): type '_InternalLinkedHashMap' is not a subtype of type 'Map<String, List>' where
E/flutter ( 752): _InternalLinkedHashMap is from dart:collection
E/flutter ( 752): Map is from dart:core
E/flutter ( 752): String is from dart:core
E/flutter ( 752): List is from dart:core
E/flutter ( 752): String is from dart:core

This is my pubspec.yaml:

name: consumos_app
description: A new Flutter application.

dependencies:
  flutter:
    sdk: flutter
  cupertino_icons: ^0.1.0
  path_provider: ^0.3.1
  json_annotation: ^0.2.2
  shared_preferences: "^0.3.3"
  intl: "^0.15.2"
  googleapis: "^0.50.0"
  googleapis_auth: "^0.2.5"

dev_dependencies:
  flutter_test:
    sdk: flutter
  build_runner: ^0.7.6
  json_serializable: ^0.3.2

flutter:
  uses-material-design: true

Google Drive v3 API: Add in documentation that $fields expects `files/starred` format, not `starred` format

See https://stackoverflow.com/questions/47148937/how-to-set-the-fields-parameter-in-the-google-drive-googleapis-v3-in-dart/47149162#47149162 for more context.

Essentially, the web Try this API form at https://developers.google.com/drive/v3/reference/files/list is different enough from the Dart implementation that first-time users may get very confused.

Web version for list():

  • Press the Try It button, press Show standard parameters, and note the fields param.
  • fields can be set by just typing in a comma separated string of fields, such as starred,createdTime,webContentLink.

Dart v3 version for list():

  • fields isn't recognized as a query param; only by digging into the code do you find that it should be $fields
  • We also have to pass in the resource type when setting the $fields, i.e. files/starred,files/createdTime,files/webContentLink. This isn't mentioned in the documentation. When you only pass in starred,createdTime,webContentLink, the 400 error that returns is confusing - it says DetailedApiRequestError(status: 400, message: Invalid field selection starred), yet the web documentation lists starred as a field. Appending files/ also seems redundant since we're calling the Files resource's list(), not a generic list() call.

Update: It turns out that I had been testing using Files.get() on the web API explorer, where you don't have to specify the resource (fields=starred), but in the Files.list() web API explorer, you do (fields=files/starred). This is inconsistent and confusing.

How to use custom search api

I want to use custom search api for my flutter app for android but there are no samples or tutorials for using this please add some samples or tutorials for this

Dart2 compile-time error

<fuchsia>/third_party/dart-pkg/pub/googleapis/lib/admin/directory_v1.dart:11103:19: Error: A value of type '(dart.core::String, dynamic) → dart.core::Null' can't be assigned to a variable of type '(dynamic, dynamic) → void'.
Try changing the type of the left hand side, or casting the right hand side to '(dynamic, dynamic) → void'.
    _json.forEach((core.String key, value) {

The generator does not handle double values very well when they happen to be integers (in checked mode)

Please note I'm demonstrating with the Datastore API, but this applies to all API that has double fields.

Steps to reproduce a problem

  1. Set up a project that uses the Cloud Datastore

  2. Add an entity to the datastore
    a. Kind: Foo
    b. Key identifier: set it to Custom name, set the name to bar
    c. Add a property

    • name: field
    • type: Floating point number
    • value: 0

    d. Click Create

  3. Set up a Dart project that fetches that entity

  4. Run that project in checked mode

Expected behavior

The checks pass. Whenever there's a double field, it should work in checked mode even if the value happens to be an integer.

Actual behavior

It fails in checked mode, because for example JSON.decode("0") is int and JSON.decode("0") is! double are both true.

In this example in the Value class in the Datastore, there's a line:

    if (_json.containsKey("doubleValue")) {
      doubleValue = _json["doubleValue"];
    }

If that doubleValue field happens to contain an integer, like {"doubleValue":7}, it will be an int and it will fail in checked mode, the assignment should look something like doubleValue = _json["doubleValue"]?.toDouble()

These sources seems to be generated by a more advanced version of https://github.com/google/apis-client-generator/ and that project seems to be pretty much abandoned, so I'm filing here, because this one seems more active (and also, because it's obvious this project uses a modified or more advanced version of that generator).

The fix looks like something like this on https://github.com/google/apis-client-generator/blob/master/src/googleapis/codegen/languages/dart/0.2/templates/_model_content.tmpl replacing the fromJson constructor generator:

  /** Create new {{ model.className }} from JSON data. */
  {{ model.className }}.fromJson(core.Map json) {
{% for property in model.properties %}
    if (json.containsKey({% literal property.wireName %})) {
{% if property.data_type.arrayOf %}
      {{ property.codeName }} = [];
      json[{% literal property.wireName %}].forEach((item) {
        {% if property.data_type.baseType.builtIn %}
        {{ property.codeName }}.add(item);
        {% else %}
        {% if property.data_type.baseType.code_type == 'core.double' %}
        {{ property.codeName }}.add(new {{ property.data_type.baseType.className }}.fromJson(item?.toDouble()));
        {% else %}
        {{ property.codeName }}.add(new {{ property.data_type.baseType.className }}.fromJson(item));
        {% endif %}
        {% endif %}
      });
{% else %}
      {% if property.data_type.builtIn %}
        {% if property.data_type.code_type == 'core.double' %}
      {{ property.codeName }} = json[{% literal property.wireName %}]?.toDouble();
        {% else %}
      {{ property.codeName }} = json[{% literal property.wireName %}];
        {% endif %}
      {% else %}
      {{ property.codeName }} = new {{ property.data_type.className }}.fromJson(json[{% literal property.wireName %}]);
      {% endif %}
{% endif %}
    }
{% endfor %}
  }

Checked mode: type 'int' is not a subtype of type 'double' of 'value'

I try to use the Sheet API v4. In checked mode I got this error with googleapis v0.28.0:

type 'int' is not a subtype of type 'double' of 'value' where
  int is from dart:core
  double is from dart:core

package:googleapis/sheets/v4.dart 2396:15  Color.blue=
package:googleapis/sheets/v4.dart 2409:7   Color.Color.fromJson
package:googleapis/sheets/v4.dart 2053:29  CellFormat.CellFormat.fromJson
package:googleapis/sheets/v4.dart 5889:27  SpreadsheetProperties.SpreadsheetProperties.fromJson
package:googleapis/sheets/v4.dart 5813:24  Spreadsheet.Spreadsheet.fromJson
package:googleapis/sheets/v4.dart 218:41   SpreadsheetsResourceApi.get.<fn>

with this program

main() async {
  var accountCredentials =
      new ServiceAccountCredentials.fromJson({
    "type": "service_account",
    "project_id": "xxx",
    "private_key_id": "xxx",
    //...
  });
  var client = await clientViaServiceAccount(
      accountCredentials, ['https://www.googleapis.com/auth/spreadsheets']);

  var sheetApi = new SheetsApi(client);
  await sheetApi.spreadsheets.get('xxx');

  client.close();
}

Thanks

[Feature Request] add play-services-wearable

I would like to create a flutter app that is capable of syncing to wearos.
My android app currently utilizes com.google.android.gms:play-services-wearable.

Please add play-services-wearable to the dart libraries.

discoveryapi_commons: Help for working with video file for uploading in Stream

I am working with Youtube API. For Uploading a video we need to convert a file into Inputstream .But iam getting error --| ApiRequestError(message: Invalid response for resumable upload attempt (status was: 500))|--
Kindly help me out to resolve this.
My code is as follows

File postFile = new File(filePath);
Stream<List<int>> inputStream = new File(filePath).openRead();
inputStream
    .transform(utf8.decoder)
    .listen((String line) {       
  print('|---$line: ${line.length} bytes ---|');
},
    onDone: () { print('File is now closed.'); },
    onError: (e) { print('InputStream Error :${e.toString()}'); });

Media uploadMedia = new Media(inputStream,postFile.lengthSync());

Thanks in Advance

Google Drive V3: Media are corrupted when downloaded with 'get'

Hello,
When i download a media with the get(fileId) method i have a problem,
They are all corrupted when i try to read the file i downloaded previously.
I first get the media from google drive,
And them i write the media with writeAsByte on the local system with this code :

 drive.Media data = await MainProvider().downloadPlan(event.id);
        plansDir.create();
        final file = new File('${plansDir.path}/${event.filename}');
        data.stream.listen((data) async { // <-- here i write the file and when i read it he is corrupted
          await file.writeAsBytes(
            data,
            mode: FileMode.write,
          );

I use an authenthicate OAuth 2.0 client.
It is a big issue beacause i can't download any Media from google drive.
When i list files on google drive it work perfectly so my client is well authenticate.

This is the function that download the Meida from google drive :

drive.Media data = await MainProvider.driveApi.files
        .get(id, downloadOptions: drive.DownloadOptions.FullMedia);

    return data;

Thank you,
Michel M

I'm using:
Flutter : 1.5.4-hotfix.2
googleapis: ^0.53.0

Dart googleapis 0.35.0 - Google Drive API v3 - fields request parameter

Google Drive API v3 documentation:

Full resources are no longer returned by default. Use the fields query parameter to request specific fields to be returned. If left unspecified only a subset of commonly used fields are returned.

Either there is a fields request (query) parameter in the googleapis Dart library (which I can't find) or the library is useless for Google Drive API v3. Or maybe a workaround?

Stack Overflow: http://stackoverflow.com/q/42600136/1407962

Flutter / googleapis / Gmail API send email returns 400 Bad Request

I'm facing issue using the googleapis package for Flutter/Dart. That's the code that I have...

import 'dart:convert';

import 'package:googleapis/gmail/v1.dart' as gMail;
import "package:googleapis_auth/auth_io.dart";
import 'package:flutter/services.dart' show rootBundle;

class Example {
  ServiceAccountCredentials credentials;

  Future<gMail.GmailApi> getGMailApi() async {
    return gMail.GmailApi(await getGoogleClient());
  }

  Future<AuthClient> getGoogleClient() async {
    return await clientViaServiceAccount(await getCredentials(), [
      'https://www.googleapis.com/auth/drive',
      'https://mail.google.com/',
    ]);
  }

  Future<ServiceAccountCredentials> getCredentials() async {
    if (credentials == null) {
      credentials = ServiceAccountCredentials.fromJson(
          json.decode(await rootBundle.loadString('GSuiteServiceAccountInfo.json')));
    }

    return credentials;
  }

  String getBase64Email({String source}) {
    List<int> bytes = utf8.encode(source);
    String base64String = base64UrlEncode(bytes);

    return base64StringFormatted;
  }

  sendEmail({
      String from: 'me',
      String to: '[email protected]',
      String subject: 'Some subject',
      String contentType: 'text/html',
      String charset: 'utf-8',
      String contentTransferEncoding: 'base64',
      String emailContent: '<table></table>',
  }) async {
    (await getGMailApi()).users.messages.send(
       gMail.Message.fromJson({
         'raw': getBase64Email(
            source: 'From: $from\r\n'
                    'To: $to\r\n'
                    'Subject: $subject\r\n'
                    'Content-Type: $contentType; charset=$charset\r\n'
                    'Content-Transfer-Encoding: $contentTransferEncoding\r\n\r\n'
                    '$emailContent'), // emailContent is HTML table.
       }),
       from);
  }
}

When I call sendEmail function I get DetailedApiRequestError(status: 400, message: Bad Request). But when I try to send the base64UrlEncoded string through the playground it works, the email is sent.

Here is my flutter doctor -v:

[√] Flutter (Channel stable, v1.2.1, on Microsoft Windows [Version 10.0.17763.316], locale en-US)
    • Flutter version 1.2.1 at C:\src\flutter-0.7.3\flutter
    • Framework revision 8661d8aecd (3 weeks ago), 2019-02-14 19:19:53 -0800
    • Engine revision 3757390fa4
    • Dart version 2.1.2 (build 2.1.2-dev.0.0 0a7dcf17eb)

[√] Android toolchain - develop for Android devices (Android SDK version 28.0.3)
    • Android SDK at C:\Users\bbozhidarov\AppData\Local\Android\Sdk
    • Android NDK location not configured (optional; useful for native profiling support)
    • Platform android-28, build-tools 28.0.3
    • ANDROID_HOME = C:\Users\bbozhidarov\AppData\Local\Android\Sdk
    • Java binary at: C:\Program Files\Android\Android Studio\jre\bin\java
    • Java version OpenJDK Runtime Environment (build 1.8.0_152-release-1248-b01)
    • All Android licenses accepted.

[√] Android Studio (version 3.3)
    • Android Studio at C:\Program Files\Android\Android Studio
    • Flutter plugin version 33.3.1
    • Dart plugin version 182.5215
    • Java version OpenJDK Runtime Environment (build 1.8.0_152-release-1248-b01)

[!] IntelliJ IDEA Community Edition (version 2018.1)
    • IntelliJ at C:\Program Files\JetBrains\IntelliJ IDEA Community Edition 2018.1.6
    X Flutter plugin not installed; this adds Flutter specific functionality.
    X Dart plugin not installed; this adds Dart specific functionality.
    • For information about installing plugins, see
      https://flutter.io/intellij-setup/#installing-the-plugins

[!] VS Code, 64-bit edition (version 1.30.2)
    • VS Code at C:\Program Files\Microsoft VS Code
    X Flutter extension not installed; install from
      https://marketplace.visualstudio.com/items?itemName=Dart-Code.flutter

[√] Connected device (1 available)
    • Android SDK built for x86 • emulator-5554 • android-x86 • Android 8.1.0 (API 27) (emulator)

! Doctor found issues in 2 categories.

And this is my pubspec.yaml:

name: App Mobile
description: App Mobile

version: 1.0.0+1

environment:
  sdk: ">=2.0.0-dev.68.0 <3.0.0"

dependencies:
  flutter:
    sdk: flutter
  intl: 0.15.7
  cupertino_icons: 0.1.2
  http: 0.11.3+17
  shared_preferences: ^0.4.2
  google_api_availability: 1.0.4
  geolocator: 2.1.0
  file_picker: 0.1.6
  url_launcher: 4.0.3
  flutter_calendar_carousel: 1.3.10
  date_util: 0.1.4
  permission_handler: 2.1.0
  simple_permissions: 0.1.9
  logging: 0.11.3+2
  googleapis: 0.52.0+1
  uuid: 2.0.0
  googleapis_auth: 0.2.7

dev_dependencies:
  flutter_test:
    sdk: flutter

flutter:
  uses-material-design: true
  assets:
    - assets/email_templates/dynamic_form_email_template.html
    - assets/email_templates/dynamic_form_email_data_row_template.html
    - GSuiteServiceAccountInfo.json

I exclude the possibility of an issue with the credentials. The same credentials/account/client is working well with DriveApi. Any help will be much appreciated. Thanks.

CircularProgressIndicator ui stuck on IOS but works fine in andriod

Future<DriveApi> getDrive(String sth) async {
  final client = await clientViaServiceAccount(credentials, const [DriveApi.DriveScope]);
  final drive = DriveApi(client);
  return drive;
}

when I call the clientViaServiceAccount, CircularProgressIndicator stuck there but only happens on IOS
device, and the problem is only on physics device, when i test on the simulator device on my mac, no problem. please help

404 When using clientViaServiceAccount

Hi,
I followed the steps but I still having error.
I got DetailedApiRequestError(status: 404, message: Not Found) when tried to use auth.clientViaServiceAccount(credentials, scopes);
If I use auth.clientViaUserConsent(id, scopes, prompt); (need a browser) works 100% fine

print(client.credentials.accessToken.data); // token OK on both methods
print(client.credentials.idToken); // null on both methods
print(client.credentials.refreshToken); // null when ServiceAccount //OK when UserConsent

Calendar API Dart2/strong mode error: type '_InternalLinkedHashMap' is not a subtype of type 'Map<String, List<String>>'

I was so close to finally integrate calendar API in my project and then:

type '_InternalLinkedHashMap' is not a subtype of type 'Map<String, List<String>>' where
_InternalLinkedHashMap is from dart:collection
Map is from dart:core
String is from dart:core
List is from dart:core
String is from dart:core
#0      ApiRequester.request (package:_discoveryapis_commons/src/clients.dart:66:47)
#1      CalendarsResourceApi.insert (package:googleapis/calendar/v3.dart:1157:32)
#2      CalendarServer.createSecondaryCalendar (package:memspace/src/services/calendar_server.dart:35:26)
#3      _createCalendar (package:memspace/src/middleware/auth.dart:154:33)
<asynchronous suspension>
...

DetailedApiRequestError.toString() should print more information

I've often found the DetailedApiRequestError.jsonResponse to contain critically important information about errors...

Maybe we could just dump that as part of the error messages using toString(), if we pretty print it with indentation it probably doesn't matter so much if it's a huge blob.


I'm not entirely sure if any APIs would include sensitive information in error messages that you wouldn't want to risk leaking into logs. But I suspect that's not the case, although it can never be excluded as users could be doing anything..

Programmatically using a specified gmail id for Google signin

Hi,
I have a requirement that I need to run background processing that has to connect to Google Drive and Google Sheets for a set of gmail IDs. I didn't find any place where I could force a Google Signin using a specific gmail ID. In my native Android app, I could do this easily using the snippet below but this does not seem possible in Flutter using this package. Do you have any recommendations? Silent sign in also uses the last logged in gmail id. My requirement is to sign in for a set of gmail ids registered in my app.

    // Initialize credentials and service object.
    GoogleAccountCredential credential = GoogleAccountCredential.usingOAuth2(
            this, Arrays.asList(Const.SCOPES))
            .setBackOff(new ExponentialBackOff());

    credential.setSelectedAccount(new Account(gmailid,"com.test.myapp"));

Google SignIn + Google APIs integration

How to create an HTTP Client starting from an GoogleSignInAccount.authHeaders?
None of the below options seems to be fit for this scenario:

  1. clientViaApiKey(apiKey)
  2. clientViaMetadataServer()
  3. clientViaServiceAccount(clientCredentials, scopes)
  4. clientViaUserConsent(clientId, scopes, userPrompt)
  5. clientViaUserConsentManual(clientId, scopes, userPrompt)

Any Dart-specific documentation?

I want to use the Gmail API to make an email listener in Dart, but there doesn't seem to be any documentation at all for the Dart-specific API.

Can you please provide some documentation? If there already is some, can you provide a link to where the documentation may be?

Uploading files through DriveApi.files.create() on web

Is it possible to upload files from the WEB through googleapis DriveApi instance?
How to convert File() (dart instance) to media file which create method need?

I tried to read the file with FileReader() as readAsArrayBuffer or readAsDataUrl but in first case I'm receiving Uint8List, in second String (base64).

Part of my code:

final reader = new FileReader();
    reader.readAsDataUrl(file);
    reader.onLoad.listen((e) async{

      drive.File fileMetadata = drive.File.fromJson({
        "mimeType": file.type,
        "name": file.name,
        "parents": [folderId]
      });

      drive.Media fileMedia = drive.Media(reader.result, file.size, contentType: file.type);

      drive.DriveApi.files.create(fileMetadata, uploadMedia: fileMedia)

Issue here is that Media() want first parameter to be async.Stream<core.List<core.int>>;
Can someone give me a solution of creating a file from web with that google package?

pub dependencies: googleapis: ^0.52.0+1

Unable to call FirestoreApi.listen()

Calling FirestoreApi.listen() always returns 400 Bad Request.

Unfortunately the documentation doesn't help much here, nor does the error message. From my investigation it seems I'm supplying all of the required parameters, though that's hard to say from just looking at the docs.

The following code shows the issue I'm having. This is on a database with open security rules:

import 'package:googleapis/firestore/v1.dart';
import 'package:http/http.dart' as http;

final projectId = "PROJECT_ID";
final databaseId = "(default)";
final database = "projects/$projectId/databases/$databaseId";
final documentPath = "$database/documents/test_collection/test_document";

final firestore = FirestoreApi(http.Client());

Future main() async {
  // Works fine
  await getDocument();

  // Fails with 400 Bad Request
  await listen();
}

Future getDocument() async {
  var document = await firestore.projects.databases.documents.get(documentPath);
  print(document.fields["test_field"].stringValue);
}

Future listen() async {
  var documentsTarget = DocumentsTarget()
    ..documents = [documentPath];

  var target = Target()
    ..documents = documentsTarget;

  var listenRequest = ListenRequest()
    ..addTarget = target;

  var response = await firestore.projects.databases.documents
      .listen(listenRequest, database);
}

The outgoing json payload (collected using listenRequest.toJson()):

{
  addTarget: {
    documents: {
      documents: [
        projects/PROJECT_ID/databases/(default)/documents/test_collection/test_document
      ]
    }
  }
}

Here's the HTTP response:

<-- 400 Bad Request https://firestore.googleapis.com/v1/projects/PROJECT_ID/databases/(default)/documents:listen?alt=json
[
  {
    "error": {
      "code": 400,
      "message": "Invalid value (Object), ",
      "status": "INVALID_ARGUMENT",
      "details": [
        {
          "@type": "type.googleapis.com/google.rpc.BadRequest",
          "fieldViolations": [
            {
              "description": "Invalid value (Object), "
            }
          ]
        }
      ]
    }
  }
]

CalendarApi: EventExtendedProperties.fromJson still not Dart2 clean

With 0.50.1:

type '_InternalLinkedHashMap<String, dynamic>' is not a subtype of type 'Map<String, String>' where
  _InternalLinkedHashMap is from dart:collection
  String is from dart:core
  Map is from dart:core
  String is from dart:core
  String is from dart:core

#0      new EventExtendedProperties.fromJson (package:googleapis/calendar/v3.dart:4162:22)
#1      new Event.fromJson (package:googleapis/calendar/v3.dart:4635:15)
#2      new Events.fromJson.<anonymous closure> (package:googleapis/calendar/v3.dart:5163:38)
#3      MappedListIterable.elementAt (dart:_internal/iterable.dart:414:29)
#4      ListIterable.toList (dart:_internal/iterable.dart:219:19)
#5      new Events.fromJson (package:googleapis/calendar/v3.dart:5164:12)
#6      EventsResourceApi.list.<anonymous closure> (package:googleapis/calendar/v3.dart:1996:41)
#7      _RootZone.runUnary (dart:async/zone.dart:1381:54)
#8      _FutureListener.handleValue (dart:async/future_impl.dart:129:18)
#9      <…>

timeMin and timMax parameters cause a Bad Request

Issue:
Requests with timeMin or timeMax parameters fail with DetailedApiRequestError(status: 400, message: Bad Request).

Cause:
Because dart DateTime does not handle time zones, the function toIso8601String() does not append a z to the end of the string.

Related Example:
In the the Api explorer, entering a string generated by toIso8601String() will fail
FAILS: 2017-02-03T08:25:15.99878

adding z will work
SUCCESS: 2017-02-03T08:25:15.99878z

Code:
googleapis/calendar/v3.dart
Line 1744:

  _queryParams["timeMin"] = [(timeMin).toIso8601String()];

From the documentation

  • [timeMin] - Lower bound (inclusive) for an event's end time to filter by.
  • Optional. The default is not to filter by end time. Must be an RFC3339
  • timestamp with mandatory time zone offset, e.g., 2011-06-03T10:00:00-07:00,
  • 2011-06-03T10:00:00Z. Milliseconds may be provided but will be ignored.

Solution:

  1. Have the function append z to the string.
  2. Make the parameter a string instead of a datetime.
  3. Let the servers handle requests without z appended.

How to call DetectIntents (Dialogflow V2) from Flutter(Dart).

Please help me to write request/response from flutter to dialalog.my below code giving error. 404.
Please help me to run these code or any modification need please help me on this.

[+1949 ms] E/flutter (10462): [ERROR:topaz/lib/tonic/logging/dart_error.cc(16)] Unhandled exception:
[ ] E/flutter (10462): DetailedApiRequestError(status: 404, message: No error details. HTTP status was: 404.)

final scopes = ['https://www.googleapis.com/auth/cloud-platform'];
final authenticatedHttpClient = await clientViaServiceAccount(accountCredentials, scopes);
final df = new DialogflowApi(authenticatedHttpClient);
final session ='https://dialogflow.googleapis.com/v2/projects/chatbot-d5783/agent';
//final session = 'https://dialogflow.googleapis.com/v2/projects/chatbot-d5783/agent/sessions/' + sessionid + ':detectIntent';
print(session);
// Build the request
final inputText = new GoogleCloudDialogflowV2beta1TextInput()
..text = 'Hi'
..languageCode = 'en';
final queryInput = new GoogleCloudDialogflowV2beta1QueryInput()
..text = inputText;
final request = new GoogleCloudDialogflowV2beta1DetectIntentRequest()
..queryInput = queryInput;
// Perform the RPC to dialogflow.
final response = await df.projects.agent.sessions.detectIntent(request, session);
// Use the response.
print(response.queryResult.fulfillmentText);
await authenticatedHttpClient.close();

BR//
Mukut

Uncaught Error: Class 'int' has no instance getter 'length'.

Modifying googleapis_examples/drive_upload_download_console, I'm attempting to convert already stored .docx, .xlsx, etc files to their corresponding Google Drive counterpart.

The following code

import 'dart:async';
import 'dart:io';

import 'package:http/http.dart' show Client;
import 'package:googleapis/common/common.dart' show Media, DownloadOptions;
import 'package:googleapis/drive/v2.dart' as drive;
import 'package:path/path.dart' as path;

Future convertFile(drive.DriveApi api, 
                    Client client, 
                    String objectId) {
  var completer = new Completer();
  api.files.get(objectId).then((drive.File file) {
    var fileName = path.basenameWithoutExtension(file.title);
    var parents = file.parents;

    client.readBytes(file.downloadUrl).then((bytes) {
      var driveFile = new drive.File()
      ..title = fileName
      ..mimeType = 'application/vnd.google-apps.document'
      ..parents = parents;
      api.files.insert(driveFile)
      .then((driveFile){
        var byteList = bytes.toList();
        var stream = new Stream.fromIterable(byteList);
        var media = new Media(stream, byteList.length);
        api.files.update(new drive.File(), driveFile.id, uploadMedia: media)
        .then((drive.File f){
          stream.close().whenComplete((){
            api.files.delete(objectId)
            .then((_){
              completer.complete(true);
              print("Converted ${f.id}");
            });
          });
        });
      });
    });
  });
  return completer.future;
}

results in the following error.

Unhandled exception:
Uncaught Error: Class 'int' has no instance getter 'length'.

NoSuchMethodError: method not found: 'length'
Receiver: 80
Arguments: []
Stack Trace:
#0      Object.noSuchMethod (dart:core-patch/object_patch.dart:45)
#1      Base64Encoder.bind.onData (package:googleapis/src/common_internal.dart:325:42)
#2      _RootZone.runUnaryGuarded (dart:async/zone.dart:1093)
#3      _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:341)
#4      _IterablePendingEvents.handleNext (dart:async/stream_impl.dart:549)
#5      _PendingEvents.schedule.<anonymous closure> (dart:async/stream_impl.dart:671)
#6      _asyncRunCallbackLoop (dart:async/schedule_microtask.dart:41)
#7      _asyncRunCallback (dart:async/schedule_microtask.dart:48)
#8      _runPendingImmediateCallback (dart:isolate-patch/isolate_patch.dart:84)
#9      _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:131)

#0      _rootHandleUncaughtError.<anonymous closure> (dart:async/zone.dart:886)
#1      _asyncRunCallbackLoop (dart:async/schedule_microtask.dart:41)
#2      _asyncRunCallback (dart:async/schedule_microtask.dart:48)
#3      _runPendingImmediateCallback (dart:isolate-patch/isolate_patch.dart:84)
#4      _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:131)

Am I possibly creating the stream and consequently the media instance incorrectly?

Runtime error in Dart2: '_InternalLinkedHashMap<dynamic, dynamic>' is not a subtype of type 'Map<String, List<String>>'

After migrating to Dart2, there are "invalid cast" errors being thrown when using the Dart Google API clients to call the server.

It stems from trying to implicitly downcast a generic Map to a Map<String, List<String>> on line 66 in clients.dart:

type '_InternalLinkedHashMap<dynamic, dynamic>' is not a subtype of type 'Map<String, List<String>>' where
  _InternalLinkedHashMap is from dart:collection
  Map is from dart:core
  String is from dart:core
  List is from dart:core
  String is from dart:core

#0      ApiRequester.request (package:_discoveryapis_commons/src/clients.dart:66)
#1      PeopleConnectionsResourceApi.list (package:googleapis/people/v1.dart:982)

DriveApi.files.export - DetailedApiRequestError(status: 403, message: Export requires alt=media to download the exported content.)

I tried fetching a spreadsheet from Google Docs, I got a result back indicating the following error:

E/flutter ( 9786): [ERROR:flutter/lib/ui/ui_dart_state.cc(148)] Unhandled Exception: DetailedApiRequestError(status: 403, message: Export requires alt=media to download the exported content.)
E/flutter ( 9786): #0 _validateResponse (package:_discoveryapis_commons/src/clients.dart:875:9)
E/flutter ( 9786):
E/flutter ( 9786): #1 ApiRequester.request (package:_discoveryapis_commons/src/clients.dart:69:22)
E/flutter ( 9786):

Code below:
clientViaServiceAccount(_credentials, _SCOPES).then((httpClient) {
var driveApi = CustomDriveApi(httpClient);
final spreadSheetId = '';
final mimeType = 'application/pdf';
driveApi.files
.exportWithAlt(spreadSheetId, mimeType, alt: 'media')
.then((document) => print(document));
});

Was playing around with the mimeTypes -(csv/text, applciation/pdf)
image

Batch operations

I am trying to implement batch requests to Google Drive API to speed up analysis of folders structure. As I see it there is no way to perform batch requests using this library is that right?

Every request is performed right away (for examle https://pub.dartlang.org/documentation/googleapis/0.50.1/googleapis.drive.v3/FilesResourceApi/list.html) so there is no way to collect multiple "prepared" requests, join them together and send as one request to https://www.googleapis-com/batch, right?

Please update _validateResponse clients.dart code a bit

We happen to use the clients.dart code (commons.ApiRequester.request)to work with many other API's (Slack, Office 365, our own, ...) and it's very convenient but recently after switching to Dart2 we've discovered that not all of those API's send an integer error code so this line now fails in _validateResponse:

final code = error['code'] as int;

Would you be able to update the code to remove 'as int'?

Office 365 for example sends a String error code.

Thank you.

Failed assertion when doing clientViaUserConsent

When doing a clientViaUserConsent I get the following assertion error:

When running without assertions, the code seems to work.

Unhandled exception:
'package:googleapis_auth/src/auth_http_utils.dart': Failed assertion: line 81 pos 12: 'credentials.refreshToken != null': is not true.
#0      _AssertionError._doThrowNew (dart:core-patch/dart:core/errors_patch.dart:37)
#1      _AssertionError._throwNew (dart:core-patch/dart:core/errors_patch.dart:33)
#2      new AutoRefreshingClient (package:googleapis_auth/src/auth_http_utils.dart:81:12)
#3      clientViaUserConsent.<anonymous closure> (package:googleapis_auth/auth_io.dart:53:32)
#4      _RootZone.runUnary (dart:async/zone.dart:1381)
#5      _FutureListener.handleValue (dart:async/future_impl.dart:129)
#6      _Future._propagateToListeners.handleValueCallback (dart:async/future_impl.dart:633)
#7      _Future._propagateToListeners (dart:async/future_impl.dart:662)
#8      _Future._complete (dart:async/future_impl.dart:467)
#9      _SyncCompleter.complete (dart:async/future_impl.dart:51)
#10     _completeOnAsyncReturn (dart:async-patch/dart:async/async_patch.dart:255)
#11     AuthorizationCodeGrantServerFlow.run (package:googleapis_auth/src/oauth2_flows/auth_code.dart:223:9)
#12     _RootZone.runUnary (dart:async/zone.dart:1381)
#13     _FutureListener.handleValue (dart:async/future_impl.dart:129)
#14     _Future._propagateToListeners.handleValueCallback (dart:async/future_impl.dart:633)
#15     _Future._propagateToListeners (dart:async/future_impl.dart:662)
#16     _Future._addListener.<anonymous closure> (dart:async/future_impl.dart:342)
#17     _microtaskLoop (dart:async/schedule_microtask.dart:41)
#18     _startMicrotaskLoop (dart:async/schedule_microtask.dart:50)
#19     _Timer._runTimers (dart:isolate-patch/dart:isolate/timer_impl.dart:376)
#20     _Timer._handleMessage (dart:isolate-patch/dart:isolate/timer_impl.dart:401)
#21     _RawReceivePortImpl._handleMessage (dart:isolate-patch/dart:isolate/isolate_patch.dart:163)
main() {
  clientViaUserConsent(new ClientId(_CLIENT_ID, _CLIENT_SECRET), _SCOPES, (String str) {
    print("asking for consent: $str");
  }).then((client) {
  });

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.