synapsecns/sanguine

View on GitHub
services/explorer/graphql/server/gin.go

Summary

Maintainability
A
1 hr
Test Coverage
package server

import (
    "github.com/99designs/gqlgen/graphql"
    "github.com/99designs/gqlgen/graphql/handler"
    "github.com/99designs/gqlgen/graphql/handler/extension"
    "github.com/99designs/gqlgen/graphql/handler/lru"
    "github.com/99designs/gqlgen/graphql/handler/transport"
    "github.com/gin-gonic/gin"
    "github.com/ravilushqa/otelgqlgen"
    "github.com/synapsecns/sanguine/core/mapmutex"
    "github.com/synapsecns/sanguine/core/metrics"
    etherClient "github.com/synapsecns/sanguine/ethergo/client"
    "github.com/synapsecns/sanguine/services/explorer/api/cache"
    serverConfig "github.com/synapsecns/sanguine/services/explorer/config/server"
    "github.com/synapsecns/sanguine/services/explorer/consumer/fetcher"
    "github.com/synapsecns/sanguine/services/explorer/contracts/swap"
    "github.com/synapsecns/sanguine/services/explorer/db"
    "github.com/synapsecns/sanguine/services/explorer/graphql/server/graph"
    "github.com/synapsecns/sanguine/services/explorer/graphql/server/graph/interceptor"
    resolvers "github.com/synapsecns/sanguine/services/explorer/graphql/server/graph/resolver"
    "github.com/synapsecns/sanguine/services/explorer/types"
    "time"
)

const (
    // GraphqlEndpoint is the base endpoint for graphql and the endpoint for post requests to the graphql service.
    GraphqlEndpoint string = "/graphql"
    // GraphiqlEndpoint is the endpoint for the graphql user interface.
    GraphiqlEndpoint string = "/graphiql"
)

// EnableGraphql enables the scribe graphql service.
func EnableGraphql(engine *gin.Engine, consumerDB db.ConsumerDB, fetcher fetcher.ScribeFetcher, apiCache cache.Service, clients map[uint32]etherClient.EVM, parsers *types.ServerParsers, refs *types.ServerRefs, swapFilters map[string]*swap.SwapFlashLoanFilterer, config serverConfig.Config, handler metrics.Handler) {
    server := createServer(
        resolvers.NewExecutableSchema(
            resolvers.Config{Resolvers: &graph.Resolver{
                DB:          consumerDB,
                Fetcher:     fetcher,
                Cache:       apiCache,
                CacheMutex:  mapmutex.NewStringMapMutex(),
                Clients:     clients,
                Parsers:     parsers,
                Refs:        refs,
                SwapFilters: swapFilters,
                Config:      config,
            }},
        ),
    )
    // TODO; investigate WithCreateSpanFromFields(predicate)
    server.Use(otelgqlgen.Middleware(otelgqlgen.WithTracerProvider(handler.GetTracerProvider())))
    server.Use(interceptor.SqlSanitizerMiddleware())

    engine.GET(GraphqlEndpoint, graphqlHandler(server))
    engine.POST(GraphqlEndpoint, graphqlHandler(server))
    engine.GET(GraphiqlEndpoint, graphiqlHandler())
}

// Create a server without introspection.
func createServer(es graphql.ExecutableSchema) *handler.Server {
    srv := handler.New(es)
    srv.AddTransport(transport.Websocket{
        KeepAlivePingInterval: 10 * time.Second,
    })
    srv.AddTransport(transport.Options{})
    srv.AddTransport(transport.GET{})
    srv.AddTransport(transport.POST{})
    srv.AddTransport(transport.MultipartForm{})
    srv.SetQueryCache(lru.New(1000))
    srv.Use(extension.Introspection{})
    srv.Use(extension.FixedComplexityLimit(300)) // Prevent ddos
    srv.Use(extension.AutomaticPersistedQuery{
        Cache: lru.New(100),
    })
    return srv
}