pocketbase / dart-sdk

PocketBase Dart SDK
https://pub.dev/packages/pocketbase
MIT License
512 stars 51 forks source link

Weird format issue #7

Closed rodydavis closed 2 years ago

rodydavis commented 2 years ago

Going through the Dart client

isAbort: false, statusCode: 500, response: {}, originalError: FormatException: Unexpected character (at character 1)
flutter: <!DOCTYPE html>
flutter: ^
flutter: }

Fetching via HTTP

 200 {"page":1,"perPage":30,"totalItems":6098,"totalPages":204,"items":

I am omitting the data from the response in the snippet. But After logging in with the client and making sure the auth store is valid the client still returns a 500 error.

ganigeorgiev commented 2 years ago

That's strange. When do you get this error? Could you provide an example what request you are performing and whether there is any extra query/body parameters that you are sending with the call?

rodydavis commented 2 years ago

No extra headers or body parameters. I am creating the client, logging in a and getting a token, then calling getFullList.

I will see if I can create an example, but traveling at the moment.

I can use Http client and get the results manually but the pocket base client is throwing the error.

Im also testing on an iOS simulator and other network calls pass too.

ganigeorgiev commented 2 years ago

I'm not able to reproduce the issue (using dart v2.17.6).

The error is most likely generated by the dart-http client and not server-side. We expect always json for the getFullList() call, but for some reason the response body resulted in HTML. Maybe it was a temporary network failure or vpn/proxy restriction page?

rodydavis commented 2 years ago

Yep I can test. Calling it from a flutter app just using the http client works using the same url. And it returns json.

I will create an example if I can reproduce it

rodydavis commented 2 years ago

Here is an example and was able to reproduce:

import 'package:flutter/material.dart';
import 'package:pocketbase/pocketbase.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key});

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  final db = PocketBase('REMOTE_POCKET_BASE_URL');
  bool loaded = false;
  List<RecordModel> items = [];

  @override
  void initState() {
    super.initState();
    initDb();
  }

  void initDb() async {
    await db.admins.authViaEmail(
      'ADMIN_USERNAME',
      'ADMIN_PASSWORD',
    );
    final items = await db.records.getFullList('TABLE');
    if (mounted) {
      setState(() {
        loaded = true;
        this.items = items;
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('PocketBase'),
      ),
      body: !loaded
          ? const Center(child: CircularProgressIndicator())
          : ListView.builder(
              itemCount: items.length,
              itemBuilder: (context, index) {
                final item = items[index];
                return ListTile(
                  leading: Text('$index'),
                  title: Text(item.data['name']),
                );
              },
            ),
    );
  }
}

Notes about the install:

rodydavis commented 2 years ago

If you want to get DB access I can provide access via email.

I have a feeling it is something in the PocketBase HTTP client that is created. I looked through the code and didnt see anything that would cause it.

rodydavis commented 2 years ago

Just to show its working with the url, this code works for me:

import 'package:flutter/material.dart';
import 'package:pocketbase/pocketbase.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key});

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  final db = PocketBase('REMOTE_POCKET_BASE_URL');
  bool loaded = false;
  List<Map<String, dynamic>> items = [];

  @override
  void initState() {
    super.initState();
    initDb();
  }

  void initDb() async {
    await db.admins.authViaEmail(
      'ADMIN_USERNAME',
      'ADMIN_PASSWORD',
    );
    try {
      // Fetch data from SDK
      final items = await db.records.getFullList('TABLE');
      if (mounted) {
        setState(() {
          loaded = true;
          this.items = items.map((e) => e.toJson()).toList();
        });
      }
    } catch (e) {
      if (e is ClientException) {
        if (e.url != null) {
          debugPrint('URL: ${e.url}');
          // Fetch data from url
          final response = await http.get(e.url!);
          debugPrint('RESPONSE: ${response.body}');
          final result = ResultList.fromJson(
            jsonDecode(response.body),
            (item) => Json(item),
          );
          if (mounted) {
            setState(() {
              loaded = true;
              items = result.items.map((e) => e.toJson()).toList();
            });
          }
        }
      }
    }  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('PocketBase'),
      ),
      body: !loaded
          ? const Center(child: CircularProgressIndicator())
          : ListView.builder(
              itemCount: items.length,
              itemBuilder: (context, index) {
                final item = items[index];
                return ListTile(
                  leading: Text('$index'),
                  title: Text(item['name']),
                );
              },
            ),
    );
  }
}

class Json extends Jsonable {
  Json(this.data);
  final Map<String, dynamic> data;
  @override
  Map<String, dynamic> toJson() => data;
}
rodydavis commented 2 years ago

Fixed it and made a PR! https://github.com/pocketbase/dart-sdk/pull/8

TLDR: Body cannot be added on GET request

ganigeorgiev commented 2 years ago

Thank you! It should be fixed in v0.4.1.