Class: Agoo::GraphQL

Inherits:
Object
  • Object
show all
Defined in:
ext/agoo/rgraphql.c

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.



902
903
904
905
906
907
908
909
# File 'ext/agoo/rgraphql.c', line 902

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.



933
934
935
936
937
938
939
940
941
# File 'ext/agoo/rgraphql.c', line 933

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.



717
718
719
720
721
722
723
724
725
726
727
728
729
# File 'ext/agoo/rgraphql.c', line 717

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.



738
739
740
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
# File 'ext/agoo/rgraphql.c', line 738

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.



830
831
832
833
834
835
836
837
838
839
840
841
842
# File 'ext/agoo/rgraphql.c', line 830

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



635
636
637
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
# File 'ext/agoo/rgraphql.c', line 635

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, 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: dump_sdl()

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 #dump_sdl method returns the schema as an SDL string.

  • options [Hash] server 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.



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

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;
}