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.



1000
1001
1002
1003
1004
1005
1006
1007
# File 'ext/agoo/rgraphql.c', line 1000

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.



1031
1032
1033
1034
1035
1036
1037
1038
1039
# File 'ext/agoo/rgraphql.c', line 1031

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.



742
743
744
745
746
747
748
749
750
751
752
753
754
# File 'ext/agoo/rgraphql.c', line 742

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.



763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
# File 'ext/agoo/rgraphql.c', line 763

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.



928
929
930
931
932
933
934
935
936
937
938
939
940
# File 'ext/agoo/rgraphql.c', line 928

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



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
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
# File 'ext/agoo/rgraphql.c', line 660

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.



818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
# File 'ext/agoo/rgraphql.c', line 818

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.



909
910
911
912
913
914
915
916
# File 'ext/agoo/rgraphql.c', line 909

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

    gql_type_iterate(type_cb, (void*)rtypes);

    return rtypes;
}