ocaml-graphql-server
                                
                                 ocaml-graphql-server copied to clipboard
                                
                                    ocaml-graphql-server copied to clipboard
                            
                            
                            
                        Deriving schema from types
It would be nice if we could derive a schema directly from a type, for example:
type user = {
  id   : int [@description "Unique user identifier"];
  name : string [@name "firstName"];
  role : role;
}
[@@deriving graphql_object]
would generate the following code:
Schema.(obj "user"
  ~fields:(fun _ -> [
    field "id"
      ~doc:"Unique user identifier"
      ~typ:(non_null int)
      ~args:Arg.[]
      ~resolve:(fun info p -> p.id)
    ;
    field "firstName"
      ~typ:(non_null string)
      ~args:Arg.[]
      ~resolve:(fun info p -> p.name)
    ;
    field "role"
      ~typ:(non_null role)
      ~args:Arg.[]
      ~resolve:(fun info p -> p.role)
  ])
)
thoughts?
What about using SDL to generate the types and resolvers (and use a few custom directives to control the generation)?
So the above could be written as:
"""
User role
"""
# Specify that a GraphQL type should specify an existing OCaml type:
enum Role @useExistingType(name: "Roles.t") {
  admin
  user
}
# Otherwise generate a new type definition (and resolvers) for our GraphQL type
type User {
  id: int!
  """
  Unique user identifier
  """
  firstName: String! @rename(lookupKey: "name") # Specify that the record field name should actually be `name` while the GraphQL field name is `firstName`
  role: role
}
Hey @bram209 😄 I've been toying in my mind with such an idea myself, and I think it could be great for simple GraphQL objects. It's not obvious to me how it can be adapted for more complex use cases though (e.g. fields with arguments).
@sgrove: I really like the idea of a PPX based on the SDL. I've been wondering whether it could generate a functor, where the user supplies the types and resolvers. As an example, the following SDL:
type User {
  id: int!
  friends(first: int): [User!]
}
type Query {
  me: User!
}
schema {
  query: Query
}
... would generate a functor with the following type:
functor (S : sig
  type ctx
  module User : sig
    type t
    val id : t -> int
    val friends : ctx Schema.resolve_info -> t -> first:int option -> t list option
  end
  module Query : sig
    type t
    val me : ctx Schema.resolve_info -> t -> User.t
  end
end) -> sig
  val schema : S.ctx Schema.schema
end
Been thinking about this for a while too. (Pardon the Reason syntax), but do you think something like this is viable w.r.t defining resolvers?
let name_resolver = (info, p) => p.name;
type role = 
| [@desc "A regular user"] User 
| [@desc "An admin user"] Admin
| Test;
[@deriving graphql_object]
type user = {
  id: [@desc "Unique user identifier"] int,
  name: [@name "firstName"][@resolver name_resolver] string,
  role,
  age: option(int),
  friends: list(user)
};
https://astexplorer.net/#/gist/842c826d3dbd3ce841f33ff1d7e8ba26/d8ce85315ec79cf0b3906121deb1a7178ea52a83
@sgrove I believe you have done some work on codegen from record type declarations? I'd be happy to go down this rabbit hole with some guidance!
W.r.t. the SDL approach, it looks like the sister project (targeting node.js) has a PR open for SDL parsing & printing! https://github.com/sikanhe/reason-graphql/pull/31
W.r.t. the SDL approach, it looks like the sister project (targeting node.js) has a PR open for SDL parsing & printing! sikanhe/reason-graphql#31
Yeah, unfortunately it's with a handrolled parser rather than using Menhir or similar 😕
Right :/
Good news though. The following seems to be: https://github.com/tahnik/graphqlx/blob/master/src/language/src/parser.mly
Might be missing things such as description. Maybe now is the time I'll finally get to try out Menhir 😄
W.r.t. the SDL approach, it looks like the sister project (targeting node.js) has a PR open for SDL parsing & printing! sikanhe/reason-graphql#31
Yeah, unfortunately it's with a handrolled parser rather than using Menhir or similar 😕
I don't know if that's the worst thing for a production project, given the error messages Menhir or similar tend to produce (not that a handrolled parser will give good error messages by default)...