samedi 27 juin 2020

Use SuperGraph as a library in already existing project, doubts and questions

I'm trying to use SuperGraph as a library.

I think I can summarize the problems that a neophyte (GraphQL and Go) like me can have in these three points:

  1. How to integrate SuperGraph (especially for CRUD) into an existing Go project that does not already use GraphQL
  2. how to integrate SuperGraph (especially for CRUD) into an existing Go project that already uses GraphQL
  3. how to perform other actions (call other code/packages) before, during or after SuperGraph operations (the so-called "actions" of Hasura and other similar projects)

#1

For point number 1 I think I have found a good way with this code:

package main

import (
    "context"
    "database/sql"
    "encoding/json"
    "net/http"

    "github.com/go-chi/render"
    "github.com/dosco/super-graph/core"
    "github.com/go-chi/chi"
    _ "github.com/jackc/pgx/v4/stdlib"
)

type reqBody struct {
    Query string `json:"query"`
}

func sgHandler(sg *core.SuperGraph) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        // Check to ensure query was provided in the request body
        if r.Body == nil {
            http.Error(w, "Must provide graphQL query in request body", 400)
            return
        }

        var rBody reqBody
        // Decode the request body into rBody
        err := json.NewDecoder(r.Body).Decode(&rBody)
        if err != nil {
            http.Error(w, "Error parsing JSON request body", 400)
        }

        // Execute graphQL query
        ctx := context.WithValue(r.Context(), core.UserIDKey, 3) // whatever
        res, err := sg.GraphQL(ctx, rBody.Query, nil)
        // check err

        // render.JSON comes from the chi/render package and handles
        // marshalling to json, automatically escaping HTML and setting
        // the Content-Type as application/json.
        render.JSON(w, r, res.Data)
    }
}

func main() {
    dbConn, err := sql.Open("pgx", "DB_URL")
    // check err

    sg, err := core.NewSuperGraph(nil, dbConn)
    // check err

    router := chi.NewRouter()

    router.Group(func(r chi.Router) {
        router.Post("/graphql", sgHandler(sg))
    })

    server.Start(router)
}

// Some code from https://medium.com/@bradford_hamilton/building-an-api-with-graphql-and-go-9350df5c9356

it works (although now I have to fully understand how SuperGraph works).

  • Do you have any advice to give me?

  • Anything more solid for future scaling?

#2

For point number 2 (How to integrate SuperGraph (especially for CRUD) into an existing Go project that already uses GraphQL) I don't really know how to do, I have an idea that could solve: a chain of middlewares, but I still have to understand well; I'll try to explain myself with an example:

func main() {
  // initialization... see #1
    router.Group(func(r chi.Router) {
        router.Post("/graphql", superGraphOrSecondHandler())
    })
}

func superGraphOrSecondHandler() {

  // if SuperGraphHandler is

    err != nil && err == supergraph.ErrQueryNotFound // I'm just imagining

  // I can call the second graphQL handler with

    next()
}
  • Is this a good way of doing it in your opinion?

  • Is there a type of error that I can already use for this case (when I can't find the query in the allow list)? Or should I simply check the error string?

#3

For point number 3 (how to perform other actions (call other code/packages) before, during or after SuperGraph operations (the so-called "actions" of Hasura and other similar projects)) I don't really have good ideas. And this is the point that scares me most of all.

I read https://github.com/dosco/super-graph/issues/69. I think @howesteve had a good idea, although this example clarified my doubts.

I thought of something like this:

func httpHandler(w, r) {
  ...read in json
  ...validate json
  ...call core.GraphQL(context, query, validated_json)
  // my idea here: check if this just finished query is followed by an "action"/code to call
  query_name := core.Name() // https://pkg.go.dev/github.com/dosco/super-graph/core?tab=doc#Name
  query_operation := core.Operation() // https://pkg.go.dev/github.com/dosco/super-graph/core?tab=doc#Operation
  ...checkForActionsAndDo(query_name, query_operation)
  ...return output to user
}
  • Is this a good way of doing it in your opinion? What am I doing wrong?

Aucun commentaire:

Enregistrer un commentaire