gql_eval_get_hook(agooReq req) {
    struct _agooErr	err = AGOO_ERR_INIT;
    const char		*gq; // graphql query
    const char		*op_name = NULL;
    const char		*var_json = NULL;
    int			qlen;
    int			oplen;
    int			vlen;
    int			indent = 0;
    gqlDoc		doc;
    gqlValue		result;
    gqlVar		vars = NULL;
    gqlOpKind		default_kind = GQL_QUERY;

    if (NULL != (gq = agoo_req_query_value(req, indent_str, sizeof(indent_str) - 1, &qlen))) {
	indent = (int)strtol(gq, NULL, 10);
    }
    if (NULL == (gq = agoo_req_query_value(req, query_str, sizeof(query_str) - 1, &qlen))) {
	if (NULL == (gq = agoo_req_query_value(req, subscription_str, sizeof(subscription_str) - 1, &qlen))) {
	    err_resp(req->res, &err, 500);
	    return;
	}
	default_kind = GQL_SUBSCRIPTION;
    }
    op_name = agoo_req_query_value(req, operation_name_str, sizeof(operation_name_str) - 1, &oplen);
    var_json = agoo_req_query_value(req, variables_str, sizeof(variables_str) - 1, &vlen);

    if (NULL != var_json) {
	if (NULL == (vars = parse_query_vars(&err, var_json, vlen)) && AGOO_ERR_OK != err.code) {
	    err_resp(req->res, &err, 400);
	    return;
	}
    }
    // Only call after extracting the variables as it terminates the string with a \0.
    qlen = agoo_req_query_decode((char*)gq, qlen);
    if (NULL == (doc = sdl_parse_doc(&err, gq, qlen, vars, default_kind))) {
	err_resp(req->res, &err, 500);
	return;
    }
    set_doc_op(doc, op_name, oplen);
    doc->req = req;

    if (NULL == gql_doc_eval_func) {
	result = gql_doc_eval(&err, doc);
    } else {
	result = gql_doc_eval_func(&err, doc);
    }
    if (NULL == result) {
	gql_doc_destroy(doc);
	err_resp(req->res, &err, 500);
	return;
    }
    if (GQL_SUBSCRIPTION == doc->op->kind) {
	int		status = 200;
	gqlValue	sv;
	const char	*subject;
	gqlSub		sub;

	switch (req->res->con_kind) {
	case AGOO_CON_WS:
	    status = 101;
	    break;
	case AGOO_CON_SSE:
	    break;
	default:
	    gql_doc_destroy(doc);
	    agoo_err_set(&err, AGOO_ERR_NETWORK, "An upgrade to Websockets or SSE is required for a GraphQL subscription.");
	    err_resp(req->res, &err, 426);
	    return;
	}
	if (NULL == (sv = gql_object_get(result, "subject"))) {
	    struct _agooErr	e;

	    agoo_err_set(&e, AGOO_ERR_TYPE, "subscription did not return a subject");
	    err_resp(req->res, &e, 400);
	    gql_doc_destroy(doc);
	    return;
	}
	subject = gql_string_get(sv);

	if (AGOO_CON_WS == req->res->con_kind) {
	    status = 101;
	}
	doc->op->kind = GQL_QUERY; // need so eval does the right thing
	if (NULL == (sub = gql_sub_create(&err, req->res->con, subject, doc))) {
	    err_resp(req->res, &err, 400);
	    return;
	}
	agoo_server_add_gsub(sub);

	value_resp(req, NULL, status, indent);

	return;
    }
    gql_doc_destroy(doc);
    value_resp(req, result, 200, indent);
}
gql_eval_get_hook(agooReq req) {
    struct _agooErr	err = AGOO_ERR_INIT;
    const char		*gq;  
    const char		*op_name = NULL;
    const char		*var_json = NULL;
    int			qlen;
    int			oplen;
    int			vlen;
    int			indent = 0;
    gqlDoc		doc;
    gqlValue		result;
    gqlVar		vars = NULL;
    gqlOpKind		default_kind = GQL_QUERY;

    if (NULL != (gq = agoo_req_query_value(req, indent_str, sizeof(indent_str) - 1, &qlen))) {
	indent = (int)strtol(gq, NULL, 10);
    }
    if (NULL == (gq = agoo_req_query_value(req, query_str, sizeof(query_str) - 1, &qlen))) {
	if (NULL == (gq = agoo_req_query_value(req, subscription_str, sizeof(subscription_str) - 1, &qlen))) {
	    err_resp(req->res, &err, 500);
	    return;
	}
	default_kind = GQL_SUBSCRIPTION;
    }
    op_name = agoo_req_query_value(req, operation_name_str, sizeof(operation_name_str) - 1, &oplen);
    var_json = agoo_req_query_value(req, variables_str, sizeof(variables_str) - 1, &vlen);

    if (NULL != var_json) {
	if (NULL == (vars = parse_query_vars(&err, var_json, vlen)) && AGOO_ERR_OK != err.code) {
	    err_resp(req->res, &err, 400);
	    return;
	}
    }
     
    qlen = agoo_req_query_decode((char*)gq, qlen);
    if (NULL == (doc = sdl_parse_doc(&err, gq, qlen, vars, default_kind))) {
	err_resp(req->res, &err, 500);
	return;
    }
    set_doc_op(doc, op_name, oplen);
    doc->req = req;

    if (NULL == gql_doc_eval_func) {
	result = gql_doc_eval(&err, doc);
    } else {
	result = gql_doc_eval_func(&err, doc);
    }
    if (NULL == result) {
	gql_doc_destroy(doc);
	err_resp(req->res, &err, 500);
	return;
    }
    if (GQL_SUBSCRIPTION == doc->op->kind) {
	int		status = 200;
	gqlValue	sv;
	const char	*subject;
	gqlSub		sub;

	switch (req->res->con_kind) {
	case AGOO_CON_WS:
	    status = 101;
	    break;
	case AGOO_CON_SSE:
	    break;
	default:
	    gql_doc_destroy(doc);
	    agoo_err_set(&err, AGOO_ERR_NETWORK, "An upgrade to Websockets or SSE is required for a GraphQL subscription.");
	    err_resp(req->res, &err, 426);
	    return;
	}
	if (NULL == (sv = gql_object_get(result, "subject"))) {
	    struct _agooErr	e;

	    agoo_err_set(&e, AGOO_ERR_TYPE, "subscription did not return a subject");
	    err_resp(req->res, &e, 400);
	    gql_doc_destroy(doc);
	    return;
	}
	subject = gql_string_get(sv);

	if (AGOO_CON_WS == req->res->con_kind) {
	    status = 101;
	}
	doc->op->kind = GQL_QUERY;  
	if (NULL == (sub = gql_sub_create(&err, req->res->con, subject, doc))) {
	    err_resp(req->res, &err, 400);
	    return;
	}
	agoo_server_add_gsub(sub);

	value_resp(req, NULL, status, indent);

	return;
    }
    gql_doc_destroy(doc);
    value_resp(req, result, 200, indent);
}