Class: Agoo::GraphQL

Inherits:
Object
  • Object
show all
Defined in:
lib/agoo/graphql.rb,
lib/agoo/graphql/arg.rb,
lib/agoo/graphql/type.rb,
lib/agoo/graphql/field.rb,
ext/agoo/rgraphql.c

Defined Under Namespace

Classes: Arg, Field, Type

Class Method Summary collapse

Class Method Details

.build_headers=(func) ⇒ Object

call-seq: build_headers=(func)

Provide a function to call that builds headers for GraphQL responses. The function should expect a single request and should return a Hash of the headers to add. Content-Type and Content-Length should not be set.



978
979
980
981
982
983
984
985
# File 'ext/agoo/rgraphql.c', line 978

static VALUE
graphql_build_headers(VALUE self, VALUE func) {
    gql_build_headers = build_headers;
    build_headers_func = func;
    rb_gc_register_address(&build_headers_func);

    return Qnil;
}

.headers(map) ⇒ Object

call-seq: headers(header_hash)

Provide a Hash to be used as the headers for GraphQL responses. Content-Type and Content-Length should not be set.



1009
1010
1011
1012
1013
1014
1015
1016
1017
# File 'ext/agoo/rgraphql.c', line 1009

static VALUE
graphql_headers(VALUE self, VALUE map) {
    agooText	t = agoo_text_allocate(1024);

    rb_hash_foreach(map, headers_cb, (VALUE)&t);
    gql_headers = t;

    return Qnil;
}

.load(sdl) ⇒ Object

call-seq: load(sdl)

Load an SDL string. This should only be called in a block provided to a call to #schema.



720
721
722
723
724
725
726
727
728
729
730
731
732
# File 'ext/agoo/rgraphql.c', line 720

static VALUE
graphql_load(VALUE self, VALUE sdl) {
    struct _agooErr	err = AGOO_ERR_INIT;

    if (NULL == gql_root) {
	rb_raise(rb_eStandardError, "GraphQL root not set. Use Agoo::GraphQL.schema.");
    }
    rb_check_type(sdl, T_STRING);
    if (AGOO_ERR_OK != sdl_parse(&err, StringValuePtr(sdl), (int)RSTRING_LEN(sdl))) {
	rb_raise(rb_eStandardError, "%s", err.msg);
    }
    return Qnil;
}

.load_file(path) ⇒ Object

call-seq: load_file(sdl_file)

Load an SDL file. This should only be called in a block provided to a call to #schema.



741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
# File 'ext/agoo/rgraphql.c', line 741

static VALUE
graphql_load_file(VALUE self, VALUE path) {
    struct _agooErr	err = AGOO_ERR_INIT;
    FILE		*f;
    long		len;
    char		*sdl;

    if (NULL == gql_root) {
	rb_raise(rb_eStandardError, "GraphQL root not set. Use Agoo::GraphQL.schema.");
    }
    rb_check_type(path, T_STRING);
    if (NULL == (f = fopen(StringValuePtr(path), "r"))) {
	rb_raise(rb_eIOError, "%s", strerror(errno));
    }
    if (0 != fseek(f, 0, SEEK_END)) {
	rb_raise(rb_eIOError, "%s", strerror(errno));
    }
    if (0 > (len = ftell(f))) {
	rb_raise(rb_eIOError, "%s", strerror(errno));
    }
    sdl = ALLOC_N(char, len + 1);
    if (0 != fseek(f, 0, SEEK_SET)) {
	rb_raise(rb_eIOError, "%s", strerror(errno));
    }
    if (len != (long)fread(sdl, 1, len, f)) {
	rb_raise(rb_eIOError, "%s", strerror(errno));
    } else {
	sdl[len] = '\0';
    }
    fclose(f);
    if (AGOO_ERR_OK != sdl_parse(&err, sdl, (int)len)) {
	xfree(sdl);
	rb_raise(rb_eStandardError, "%s", err.msg);
    }
    xfree(sdl);

    return Qnil;
}

.publish(subject, event) ⇒ Object

call-seq: publish(subject, event)

Publish an event on the given subject. A subject must be a String while the event must be one of the objects represented by the the GraphQL schema. Generally the subjects are selected to identify which objects are being published and should match the value returned by the subscription methods.



906
907
908
909
910
911
912
913
914
915
916
917
918
# File 'ext/agoo/rgraphql.c', line 906

static VALUE
graphql_publish(VALUE self, VALUE subject, VALUE event) {
    const char		*subj;
    struct _agooErr	err = AGOO_ERR_INIT;

    rb_check_type(subject, T_STRING);
    subj = StringValuePtr(subject);

    if (AGOO_ERR_OK != agoo_server_gpublish(&err, subj, (gqlRef)event)) {
	rb_raise(rb_eStandardError, "%s", err.msg);
    }
    return Qnil;
}

.schema(root) ⇒ Object

call-seq: schema(root) { }

Start the GraphQL/Ruby integration by assigning a root Ruby object to the GraphQL environment. Within the block passed to the function SDL strings or files can be loaded. On exiting the block validation of the loaded schema is performed.

Note that the _@ruby_ directive is added to the schema type as well as the Query, Mutation, and Subscription types based on the root class. Any _@ruby_ directives on the object types in the SDL will also associate a GraphQL and Ruby class. The association will be used to validate the Ruby class as a way to verify the class implements the methods described by the GraphQL type. The association is also use for resolving



638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
# File 'ext/agoo/rgraphql.c', line 638

static VALUE
graphql_schema(VALUE self, VALUE root) {
    struct _agooErr	err = AGOO_ERR_INIT;
    gqlDir		dir;
    gqlDirUse		use;
    gqlType		schema_type;
    bool		fresh = false;
    gqlType		string_nn;

    if (!rb_block_given_p()) {
	rb_raise(rb_eStandardError, "A block is required.");
    }
    if (AGOO_ERR_OK != gql_init(&err)) {
	printf("*-*-* %s\n", err.msg);
	exit(1);
    }
    if (NULL == (dir = gql_directive_create(&err, "ruby", "Associates a Ruby class with a GraphQL type.", 0))) {
	printf("*-*-* %s\n", err.msg);
	exit(2);
    }
    if (NULL == (string_nn = gql_assure_nonnull(&err, &gql_string_type)) ||
	NULL == gql_dir_arg(&err, dir, "class", string_nn, NULL, 0, NULL)) {
	printf("*-*-* %s\n", err.msg);
	exit(3);
    }
    if (AGOO_ERR_OK != gql_directive_on(&err, dir, "SCHEMA", 6) ||
	AGOO_ERR_OK != gql_directive_on(&err, dir, "OBJECT", 6)) {
	printf("*-*-* %s\n", err.msg);
	exit(4);
    }
    gql_root = (gqlRef)root;
    vroot = root;
    rb_gc_register_address(&vroot);

    gql_doc_eval_func = eval_wrap;
    gql_resolve_func = resolve;
    gql_type_func = ref_type;
    gql_root_op = root_op;

    if (NULL == (use = gql_dir_use_create(&err, "ruby"))) {
	printf("*-*-* %s\n", err.msg);
	exit(5);
    }
    if (AGOO_ERR_OK != gql_dir_use_arg(&err, use, "class", gql_string_create(&err, rb_obj_classname(root), 0))) {
	printf("*-*-* %s\n", err.msg);
	exit(6);
    }
    rb_rescue2(rescue_yield, Qnil, rescue_yield_error, (VALUE)&err, rb_eException, (VALUE)0);
    if (AGOO_ERR_OK != err.code) {
	printf("*-*-* %s\n", err.msg);
	exit(7);
    }
    if (NULL == (schema_type = gql_type_get("schema"))) {
	if (NULL == (schema_type = gql_schema_create(&err, "The GraphQL root Object.", 0))) {
	    printf("*-*-* %s\n", err.msg);
	    exit(8);
	}
	fresh = true;
    }

    if (AGOO_ERR_OK != gql_type_directive_use(&err, schema_type, use) ||
	AGOO_ERR_OK != make_ruby_use(&err, root, "query", "Query", fresh, schema_type, "Root level query.") ||
	AGOO_ERR_OK != make_ruby_use(&err, root, "mutation", "Mutation", fresh, schema_type, "Root level mutation.") ||
	AGOO_ERR_OK != make_ruby_use(&err, root, "subscription", "Subscription", fresh, schema_type, "Root level subscription.")) {
	printf("*-*-* %s\n", err.msg);
	exit(9);
    }
    if (AGOO_ERR_OK != gql_validate(&err) ||
	AGOO_ERR_OK != build_type_class_map(&err)) {
	printf("*-*-* %s\n", err.msg);
	exit(10);
    }
    return Qnil;
}

.sdl_dump(options) ⇒ Object

call-seq: sdl_dump()

The preferred method of inspecting a GraphQL schema is to use introspection queries but for debugging and for reviewing the schema a dump of the schema as SDL can be helpful. The #sdl_dump method returns the schema as an SDL string.

  • options [Hash] options

    • :with_description [true|false] if true the description strings are included. If false they are not included.

    • :all [true|false] if true all types and directives are included in the dump. If false only the user created types are include.



796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
# File 'ext/agoo/rgraphql.c', line 796

static VALUE
graphql_sdl_dump(VALUE self, VALUE options) {
    agooText		t = agoo_text_allocate(4096);
    volatile VALUE	dump;
    VALUE		v;
    bool		with_desc = true;
    bool		all = false;

    Check_Type(options, T_HASH);

    v = rb_hash_aref(options, ID2SYM(rb_intern("with_descriptions")));
    if (Qnil != v) {
	with_desc = (Qtrue == v);
    }
    v = rb_hash_aref(options, ID2SYM(rb_intern("all")));
    if (Qnil != v) {
	all = (Qtrue == v);
    }
    if (NULL == (t = gql_schema_sdl(t, with_desc, all))) {
	rb_raise(rb_eNoMemError, "Failed to allocate memory for a schema dump.");
    }
    dump = rb_str_new(t->text, t->len);
    agoo_text_release(t);

    return dump;
}

.sdl_typesObject

call-seq: sdl_types()

Returns an array of all SDL types as Ruby objects.



887
888
889
890
891
892
893
894
# File 'ext/agoo/rgraphql.c', line 887

static VALUE
graphql_sdl_types(VALUE self) {
    VALUE	rtypes = rb_ary_new();

    gql_type_iterate(type_cb, (void*)rtypes);

    return rtypes;
}