angel-dart / angel

[ARCHIVED] A polished, production-ready backend framework in Dart for the VM, AOT, and Flutter.
https://angel-dart.dev/
MIT License
1.06k stars 67 forks source link

Resolver not called on deeper query levels #198

Closed thosakwe closed 3 years ago

thosakwe commented 4 years ago

This issue was originally created by @marianc here, before being automatically moved: https://github.com/angel-dart-archive/graphql/issues/42


Use case: I am trying to write a database application. The GraphQL models contains two categories of fields: 'Properties' (table fields) and 'Navigation properties' (related records). All 'Properties' are retrieved from database in one request (cheap operation) but the 'Navigation properties' should be retrieved from the database only if specified in the query (on demand) as this may be expensive on resources. I have difficulties in retrieving 'Navigation properties'.

Please find below the code that exemplifies the problem:

pubspec.yaml

name: server
description: Server.
version: 0.0.1

environment:
  sdk: '>=2.7.0 <3.0.0'

dependencies:
  angel_framework: ^2.1.1
  angel_graphql:
    git:
      url: https://github.com/angel-dart/graphql.git
      path: angel_graphql
      ref: master

bin/server.dart

import 'package:angel_framework/angel_framework.dart';
import 'package:angel_framework/http.dart';
import 'package:angel_graphql/angel_graphql.dart';
import 'package:graphql_server/graphql_server.dart';
import 'package:graphql_schema/graphql_schema.dart';

main() async {

  var filmGraphQLType = objectType('Film', isInterface: false, interfaces: [], fields: [
    // Properties
    field('id', graphQLString),
    field('title', graphQLString),
    field('released', graphQLInt),

    // Navigation properties
    field('actors', listOf(graphQLString.nonNullable()).nonNullable(), resolve: (obj, args) async {
      // Retrieve actors from database based on id Film
      // var idFilm = obj['id'];
      return <String>[
        'Actor 1',
        'Actor 2',
        'Actor 3'
      ];
    }),
  ]);

  var typeRootQuery = objectType(
    'RootQuery',
    description: 'RootQuery',
    fields: [
      field(
        'films',
        listOf(filmGraphQLType.nonNullable()).nonNullable(),
        resolve: (root, args) async {
          return [
            {
              'id': 'id1',
              'title': 'Film 1',
              'released': 1999,
            },
            {
              'id': 'id2',
              'title': 'Film 2',
              'released': 1999,
            },
            {
              'id': 'id3',
              'title': 'Film 3',
              'released': 1999,
            },
          ];
        },
      ),
    ],
  );

  var schema = graphQLSchema(
    queryType: typeRootQuery,
  );

  var app = Angel();
  var http = AngelHttp(app);

  app.get('/', (req, res) => res.writeln('Hello Angel!'));

  app.all('/graphql', graphQLHttp(GraphQL(schema)));
  app.get('/graphiql', graphiQL());

  await http.startServer('127.0.0.1', 3000);

  print('Program started ...');
}

When I use the following query (http://localhost:3000/graphiql):

{
  films {
    id
    title
    released
    actors
  }
}

... an error is raised, indicating that that there was no attempt to retrieve 'actors' field using its resolver.

{
  "errors": [
    {
      "message": "Null value provided for non-nullable field \"actors\"."
    }
  ]
}

I am not sure if this is a bug or the intended behavior. If this is the intended behavior what is the recommended solution for this kind of problem ?

Thank you for your help.

thosakwe commented 4 years ago

@thosakwe commented:

Thanks for reporting. The master branch is currently in beta (2.0.0-beta), so I expect there to be some bugs. I'll keep you updated...