Golang dgraph client connection error


Report a Dgraph Client Bug

What Dgraph client (and version) are you using?

(put “x” in the box to select)

  • Dgo
  • PyDgraph
  • Dgraph4J
  • Dgraph-js
  • Dgraph-js-http
  • Dgraph.NET

Version: github.com/dgraph-io/dgo/v210

What version of Dgraph are you using? Slash

Have you tried reproducing the issue with the latest release? yes

What is the hardware spec (RAM, OS)? laptop

Steps to reproduce the issue (command/config used to run Dgraph).

I am trying to make a REST API that talks to a Slash endpoint via the Golang client, it looks like its connecting but is complaining about ‘content-type’ and nothing I have tried or found in other issues seems to make a difference. I’ve tried using both a JWT that is used for Authorizating calls (using Slash @auth) as well as an API key.

func (dg *Dgraph) Connect() error {
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()

	pool, err := x509.SystemCertPool()
	if err != nil {
		log.Printf("error getting system certificate store - %s", err)
		return err
	}

	// conn, err := dgo.DialCloud(dg.url, dg.token)
	conn, err := grpc.Dial(dg.url, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{RootCAs: pool, ServerName: strings.Split(dg.url, ":")[0]})), grpc.WithPerRPCCredentials(&authorizationCredentials{dg.token}))
	if err != nil {
		log.Printf("error connecting to Dgraph cloud - %s", err)
		return err
	}

	defer conn.Close()
	dgraphClient := dgo.NewDgraphClient(api.NewDgraphClient(conn))
	dg.client = dgraphClient

	// err = dgraphClient.Login(context.Background(), "user", "passwd")
	// if err != nil {
	// 	log.Printf("error logging in: %s", err)
	// 	return err
	// }

	md := metadata.New(map[string]string{"accept": "application/dql", "content-type": "application/dql"})
	ctx = metadata.NewOutgoingContext(ctx, md)

	txn := dg.client.NewTxn()
	q := `query MyQuery($order: OrderOrder = {}) {
		queryOrder(order: $order) {
			id
			name
			price
			state
			purchased
		}
	}`

	res, err := txn.QueryWithVars(ctx, q, map[string]string{})
	if err != nil {
		log.Printf("error in query - %s", err)
		return err
	}

	defer txn.Discard(ctx)

	log.Printf("ORDERS: %s", string(res.Json))

	return nil
}

Expected behaviour and actual result.

Here is the result when I try to connect…

2021/06/18 12:43:16 error in query - rpc error: code = Unauthenticated desc = Unauthorized: HTTP status code 401; transport: missing content-type field
2021/06/18 12:43:16 rpc error: code = Unauthenticated desc = Unauthorized: HTTP status code 401; transport: missing content-type field
exit status 1
make: *** [Makefile:22: grpc] Error 1

The dgo client currently only supports DQL queries, not GraphQL queries. If you’re looking to make GraphQL queries from Go you can make the HTTP calls to do so or use a GraphQL library. Because Dgraph supports the native GraphQL spec, it works well with GraphQL tools that also support the spec.

1 Like

I keep getting the same error even when trying DQL, do you have an example of a query that returns all records of a certain type “Order” in my example?

p.s. as you may have figured out I’m new to Dgraph

In DQL you can run a query like this:

{
  q(func: type(Order)) {
    uid
    name
    price
    state
    increased
  }
}

Thanks, I couldn’t find a simple example like that in the docs!

Now I have this code:

package dgraph

import (
	"context"
	"crypto/tls"
	"crypto/x509"
	"fmt"
	"log"
	"strings"
	"time"

	dgo "github.com/dgraph-io/dgo/v210"
	"github.com/dgraph-io/dgo/v210/protos/api"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials"
	"google.golang.org/grpc/metadata"
)

type authorizationCredentials struct {
	token string
}

func (a *authorizationCredentials) GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error) {
	return map[string]string{"Authorization": fmt.Sprintf("Bearer %s", a.token)}, nil
}

func (a *authorizationCredentials) RequireTransportSecurity() bool {
	return true
}

func (dg *Dgraph) Connect() error {
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()

	pool, err := x509.SystemCertPool()
	if err != nil {
		log.Printf("error getting system certificate store - %s", err)
		return err
	}

	// conn, err := dgo.DialCloud(dg.url, dg.token)
	conn, err := grpc.Dial(dg.url, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{RootCAs: pool, ServerName: strings.Split(dg.url, ":")[0]})), grpc.WithPerRPCCredentials(&authorizationCredentials{dg.token}))
	if err != nil {
		log.Printf("error connecting to Dgraph cloud - %s", err)
		return err
	}

	defer conn.Close()
	dgraphClient := dgo.NewDgraphClient(api.NewDgraphClient(conn))
	dg.client = dgraphClient

	// err = dgraphClient.Login(context.Background(), "user", "passwd")
	// if err != nil {
	// 	log.Printf("error logging in: %s", err)
	// 	return err
	// }

	md := metadata.New(map[string]string{"accept": "application/dql", "content-type": "application/dql"})
	ctx = metadata.NewOutgoingContext(ctx, md)

	txn := dg.client.NewTxn()
	q := `{
		q(func: type(Order)) {
			uid
			name
			purchased
			description
			state
		}
	}`

	res, err := txn.Query(ctx, q)
	if err != nil {
		log.Printf("error in query - %s", err)
		return err
	}

	defer txn.Discard(ctx)

	log.Printf("ORDERS: %s", string(res.Json))

	return nil
}

which still gives this error:

2021/06/18 18:48:32 error in query - rpc error: code = Unauthenticated desc = Unauthorized: HTTP status code 401; transport: missing content-type field
2021/06/18 18:48:32 rpc error: code = Unauthenticated desc = Unauthorized: HTTP status code 401; transport: missing content-type field
exit status 1
make: *** [Makefile:22: grpc] Error 1

The “dg.token” I am trying to use is both an API key from Slash and also a valid JWT that Slash is configured to authorize using the # Authorization feature of Slash.

I see you commented out the dgo.DialCloud endpoint. Did that not work for you?

You could try setting Authorization to just the key (not prefixed with "Bearer ") or use the Dg-Auth instead of Authorization.

I will try DialCloud again - it did not work same issue I believe.

Same issue either way, is there some difference in the way Slash authenticates?

I am using the # Authorization comment to verify the JWT in Slash.

Ok, looks like its working now with DialCloud and generating a new API key!