tendant / graphql-clj

A Clojure library that provides GraphQL implementation.
Eclipse Public License 1.0
285 stars 22 forks source link

Is it possible to define a custom scalar ? #51

Open mariogarcia opened 7 years ago

mariogarcia commented 7 years ago

Hi:

First of all, great work \o/

My question is about scalar types. Sometimes is annoying to be dealing with data conversion in my application logic and I'm wondering if it's possible to register a new scalar converter somehow.

Thanks

tendant commented 7 years ago

I am also considering to add Coercion support for all types, including Scalar, Object types and possibly Input Object.

We might be able to use the same way we define the resolver. Or enhance the resolver function with data coercion support.

mariogarcia commented 7 years ago

Well after taking a look to the graphql-java project and this one I think the strategy I'd like the most is to keep things separated:

All of them could be combined at the beginning to get the executor context (resolver), something like:

Type/Field function resolver DSL:

(def routes
  "GraphQL routing definition"
  [[:QueryRoot
    [auth/check-logged-in] ;; all queries under QueryRoot require to be logged in
    [:user users/find-by-email]
    [:course courses/by-id]
   ;; Relationships
   [:Course
    [:members courses/members]]])

One of the ideas of having a DSL is to be able to build a pipeline. That would help you applying things like authorization, or monitoring certain types...etc. (I'm actually implementing a basic version of the one above). Of course a pipeline requires that functions in the pipeline should return a type (not a graphql type I'm talking about defrecord deftype...) to let the pipeline know

Then Scalar converters. Coertion is ok, but I rather have the chance to be explicit in the conversion (from/to string). Anyway I'd like to know what you had in mind about coercion, maybe I got it wrong.

(def scalars
  "GraphQL scalars conversions"
  [[:UUID
    [converter/to-uuid converter/from-uuid]]
   [:Timestamp
    [converter/to-timestamp converter/from-timestamp]]])

Finally you can end up with something like this:

(def mappings (graphql/create-mappings routes))
(def schema (graphql/load-schema "graphql/schema.gql"))
(def resolve (graphql/create-resolver schema mappings scalars))

And use the resolve function in any known web framework or toolkit.

(defn execute-graphql
  "GraphQL endpoint"
  [ctx]
  (let [mp (:data ctx)
        qy (get-in mp ["query"])
        vs (get-in mp ["variables"])
        rs (graphql/resolve nil qy vs)]
    (-> (json/encode rs)
        (http/ok {:content-type http-util/json-type}))))

Sorry if my answer was too long. Thanks