Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Fetching data from Azure Cosmos DB in Flutter?

I wrote a function to fetch data using query from Azure Cosmos Database in Flutter/Dart, however it's giving error :

response.body: {"code":"BadRequest","message":"Message: {\"Errors\":[\"The input content is invalid because the required properties - 'æ©; ' - are missing\"]}\r\nActivityId: f75a0c6e-2c8d-4f13-a020-6e3c13fa5458, Request URI: /apps/f4533d11-81e3-4512-b639-0f0475c10611/services/401c9130-a85e-46a6-8311-c2dc8e5070d6/partitions/b5d2a58d-1304-414b-92c7-10e7fa95f679/replicas/131768862196689298p, RequestStats: , SDK: Microsoft.Azure.Documents.Common/2.0.0.0"}

I/flutter ( 5284): response.status: 400

Here is my piece of code

 final response = await http.post(
  endpointResource,
  // Query
  body: query,
  // Post new message
  headers: {
    HttpHeaders.AUTHORIZATION: authToken,
    HttpHeaders.CONTENT_TYPE: "application/query+json",
    //'content-type': 'application/json',
    'Accept': 'application/json',
    //c.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
    'x-ms-version': '2017-02-22',
    'x-ms-date': date,
    'x-ms-documentdb-isquery': 'true',
    'x-ms-query-enable-crosspartition': 'true',
    'x-ms-documentdb-query-enable-scan': 'true', 
  },
);

What should I do to get data back?

like image 944
goops17 Avatar asked Jul 02 '18 15:07

goops17


2 Answers

I managed to translate a code snippet from a working example in Javascript to Dart.

import 'dart:io';
import 'dart:convert';
import 'dart:async';
import 'dart:core';
import 'package:crypto/crypto.dart';
import 'package:hex/hex.dart';

class Cosmos{
  String documentDBMasterKey;

  Cosmos({this.documentDBMasterKey});

 Future queryCosmos({url, method, body}) async{
    String auth;
    String documentDBMasterKey = this.documentDBMasterKey;
    print("mastKey: $documentDBMasterKey");

    method = method.trim(); //GET, POST, PUT or DEL
    url = url.trim();
    String utcString = HttpDate.format(DateTime.now());

    print('RFC1123time: $utcString');
    print('request url = ' + url);

    String strippedurl =
        url.replaceAllMapped(RegExp(r'^https?://[^/]+/'), (match) {
      return '/';
    });

    print('stripped Url: $strippedurl');

    List strippedparts = strippedurl.split('/');
    int truestrippedcount = strippedparts.length - 1;
    print('$truestrippedcount');

  String resourceId;
  String resType;

    if (truestrippedcount % 2 != 0){
      print('odd');
      resType = strippedparts[truestrippedcount];
      print('$resType');

      if (truestrippedcount > 1){
        int  lastPart = strippedurl.lastIndexOf('/');
        resourceId = strippedurl.substring(1, lastPart);
        print('ResourceId: ' + resourceId); 
      }
    }
    else{
      print('even');
      resType = strippedparts[truestrippedcount -1];
      print('resType: $resType');
      strippedurl = strippedurl.substring(1);
      print('strippedurl $strippedurl');
      resourceId = strippedurl;
      print('ResourceId: ' + resourceId);
    }

  String verb = method.toLowerCase();
  String date = utcString.toLowerCase();

  Base64Codec base64 = const Base64Codec(); 
  var key = base64.decode(documentDBMasterKey); //Base64Bits --> BITS
  print('key = ${HEX.encode(key)}');
  print('masterKey = $documentDBMasterKey');

  String text = (verb ?? '').toLowerCase() + '\n' + 
                (resType ?? '').toLowerCase() + '\n' +
                (resourceId ?? '') + '\n' +
                (date ?? '').toLowerCase() + '\n' +
                '' + '\n';

  print('text: $text');

  var hmacSha256 = Hmac(sha256, key);
  List<int> utf8Text = utf8.encode(text);
  var hashSignature = hmacSha256.convert(utf8Text);
  String base64Bits = base64.encode(hashSignature.bytes);

//Format our authentication token and URI encode it.
var masterToken = "master";
var tokenVersion = "1.0";
auth = Uri.encodeComponent('type=' + masterToken + '&ver=' + tokenVersion + '&sig=' + base64Bits);
print('auth= $auth');

  Map<String, String> headers = {
    'Accept': 'application/json',
    'x-ms-version': '2016-07-11',
    'Authorization': auth,
    'x-ms-date': utcString,
    'x-ms-documentdb-isquery' : 'true',
    'Content-Type' : 'application/query+json',
    'x-ms-documentdb-query-enablecrosspartition' : 'true',
  };

  Future<String> readResponse(HttpClientResponse response) {
  final completer = Completer<String>();
  final contents = StringBuffer();
  response.transform(utf8.decoder).listen((data) {
    contents.write(data);
  }, onDone: () => completer.complete(contents.toString()));
  return completer.future;
}

  HttpClientRequest request;
  HttpClient httpClient = new HttpClient();
  if (method=='GET'){
    request = await httpClient.getUrl(Uri.parse(url));
  }
  else if(method=='POST'){
    request = await httpClient.postUrl(Uri.parse(url));
  }
  else if(method=='PUT'){
    request = await httpClient.putUrl(Uri.parse(url));
  }
  else if(method=='DEL'){
    request = await httpClient.deleteUrl(Uri.parse(url));
  }
    headers.forEach((key, value) {
      request.headers.set(key,value);
    });

    if(body != null) {
      request.add(utf8.encode(json.encode(body)));
    }

    HttpClientResponse aresponse = await request.close();
    httpClient.close();
  String aresponseString = await readResponse(aresponse);
  return jsonDecode(aresponseString); 
  }
}

Just instantiate the class with your Cosmos Master Key:

Cosmos cosmos = Cosmos( documentDBMasterKey:'{your_cosmos_db_master_key}');

Query Cosmos Db by calling queryCosmos method. Pass 'url', 'method' and an optional 'body' as parameters:

// GET Example
    () async {
       Map<String, dynamic> get_dbs = await cosmos.queryCosmos(
         url: 'https://{your_base_url}.documents.azure.com:443/dbs', method: 'GET');
       print(get_dbs);
    }

// POST Example (Query)
    () async {
    final Map<String, dynamic> body = {
      "query":
          "SELECT * FROM Faults f WHERE f.FaultId = @faultId",
      "parameters": [
        {"name": "@faultId", "value": 306000}
      ]
    };
    Map<String, dynamic> get_fault = await cosmos.queryCosmos(
        url:
            'https://{your_base_url}.documents.azure.com:443/dbs/{your_db}/colls/{your_collection}/docs',
        method: 'POST',
        body: body);
    print('Get fault $get_fault');
    }

Original code (JavaScript - Download to Postman and check pre-req script): https://github.com/MicrosoftCSA/documentdb-postman-collection

My code (dart): https://github.com/fvarela/cosmos_db_dart

like image 177
Francisco Varela Avatar answered Oct 04 '22 03:10

Francisco Varela


I've created a Dart library to fetch data from a CosmosDB. For example to fetch documents from a collection you can just call this function:

import 'package:cosmosdb/cosmosdb.dart';

void main() {
    final cosmosDB = CosmosDB(
      masterKey: '<YOUR_MASTER_KEY>',
      baseUrl: '<YOUR_BASE_URL>',
    );
    // get all documents from a collection
    final documents = cosmosDB.documents.list('<YOUR_DATABASE>', '<YOUR_COLLECTION>');
    print(documents);
}

GitHub: https://github.com/jonasfranz/cosmosdb

Package: https://pub.dev/packages/cosmosdb

like image 26
Jonas Franz Avatar answered Oct 04 '22 04:10

Jonas Franz