GraphQL Custom Logic

We are working on a new batch of GraphQL features. One of those is the ability to extend the generated GraphQL API with custom logic.

There’s a first version built that we are moving through testing and into a beta release. It’ll be part of beta releases until the release of 20.07.0. We are really keen to get feedback and make this the most useful feature it can be.

Docs and examples will also land pretty soon. But seeing as there’s been lots of interest in this sort of feature I’m putting up this page as a way of recording interest, discussion, feature requests etc.

Custom Logic

Initially, custom logic is available by calling out to a http endpoint. First versions will support both REST endpoints and GraphQL.

Support is provided to define your own types, as well as the url of the endpoint and the body/graphql-query patterned from the arguments.

For example, you can define a custom query as follows:

type Query {
  myCustomQuery(arg1: MyInputType, arg2: String): [MyResult] @custom(
    http: {
      url:"http://my.api.com/endpoint/$arg2",
      method:POST,
      body:"{ data: $input }"},
      forwardHeaders: [ ... ] )
}

input MyInputType { ... }

type MyResult @remote { ... }

This works for queries, mutations and fields within types. You can also pass on headers from the incoming request to the backend (@remote means the data is in the remote service, not Dgraph).

This allows you knit together Dgraph data and external data.

As a simple example, you can take an external data service, like a GraphQL service that just lists movies, and start to build a GraphQL server that provides reviews linking local and remote data, etc.

type User {
  name: String! @id
  ...
}

type Movie @remote { ... }

type Review {
  id: ID!
  text: String @search(by: [term])
  rating: Int @search
  byUser: User
  ...
  ofMovie: String! 
  movie: Movie @custom(http: {
			url: "http://movie.server/graphql",
			graphql: "query { movie(id: $ofMovie) }"
		})
}

At query time, Dgraph takes a query like:

query {
  queryReview(filter: { text: { anyofterms: "brilliant" } }, order: { asc: rating }, first: 10) {
    text
    rating
    byUser { 
      username 
      ...
    }
    movie { ... }
}

and works out what part it can resolve locally (including some query planning to make sure it gets the Review’s ofMovie field so it can make the custom call) resolves that against Dgraph, and then uses the resolved data to resolve any further custom requirements (in this case finding the movie details) before building the response.

There’s a world of possibility here from knitting together existing GraphQL services to adding bespoke custom logic to your Dgraph GraphQL instance.

We’ll post more examples and links to documentation as it comes online. However, if you’ve got questions, feature requests, etc please feel to be involved in the conversation.

5 Likes

I have one question about this. The func anyofterms will be applied on the fly? (e.g: anyofterms
on REST result?) And any Dgraph’s func that is supported in Dgraph’s GraphQL will also work in any remote data?

Nice question.

The schema has Review as a type stored in Dgraph. For all the Dgraph types we’ll generate the usual query+mutation options.

For things from remote schemas we can’t do that, so in this example the Movie type won’t get any query or mutations generated for it. That needs custom query/mutation to get those things.

1 Like

Oh, now that I’ve come to notice (a little inattentive tonight). I had thought It was applying func on the remote. So I was surprised, cuz it is an extra layer of complexity. Thanks for clarifying!

BTW, nice work!

Thanks so much for the work guys! With regards to the (DataLoader-ish) N+1 problem, might we look into batching those remote @custom http calls in the future?

Too late - we already do that :slight_smile:

There’s a mode where, for example, if the external GraphQL api takes a list of ids as input and returns a list of results, we batch into a single request.

2 Likes

That’s way awesome man, @michaelcompton when might custom logic be released? My team and I are creating a prototype without access control right now and we could really use it.

Also, will Dgraph have field validators that also work with custom logic? E.g. the predicate price is permitted to only have a range of $x_min to $x_max that is fetched from a http call, or a predicate’s string value (e.g. username) must pass a regex check etc. That would be lovely.

Hi, sorry it took a few more days than expected to get the first versions of this out.
Draft docs are now here https://graphql.dgraph.io/docs/ and the feature is in master and will be in a 20.07 beta release soon.

I really like your ideas around validation. Others have asked if we can have directives that express constraints, or default values, but I totally agree that sometimes that would have to be expressed as custom code.

It’s not likely to be added right now - we’ll want to push custom logic around a bit more first to see in what directions is should go - but if you’d like to add your requirements as a git issue, it’s something we’ll consider as we think about those custom logic extensions.

2 Likes

Alright, issue added. Please let me know if there’s more I can do to help (apart from contributing code for now :sweat_smile:).