Intégration d'un point d'entrée GraphQL et d'un connecteur pour
PostgreSQL - Possibilité de migrer le schéma de la base de données via drapeau - Génération du code GraphQL avec https://gqlgen.com/
This commit is contained in:
2
internal/.gitignore
vendored
Normal file
2
internal/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
/server.go
|
||||
/graph/generated
|
@ -13,9 +13,11 @@ import (
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
Log LogConfig `yaml:"log"`
|
||||
HTTP HTTPConfig `yaml:"http"`
|
||||
OIDC OIDCConfig `yaml:"oidc"`
|
||||
Debug bool `yaml:"debug" env:"DEBUG"`
|
||||
Log LogConfig `yaml:"log"`
|
||||
HTTP HTTPConfig `yaml:"http"`
|
||||
OIDC OIDCConfig `yaml:"oidc"`
|
||||
Database DatabaseConfig `yaml:"database"`
|
||||
}
|
||||
|
||||
// NewFromFile retrieves the configuration from the given file
|
||||
@ -57,6 +59,10 @@ type LogConfig struct {
|
||||
Format logger.Format `yaml:"format" env:"LOG_FORMAT"`
|
||||
}
|
||||
|
||||
type DatabaseConfig struct {
|
||||
DSN string `yaml:"dsn" env:"DATABASE_DSN"`
|
||||
}
|
||||
|
||||
func NewDumpDefault() *Config {
|
||||
config := NewDefault()
|
||||
return config
|
||||
@ -64,6 +70,7 @@ func NewDumpDefault() *Config {
|
||||
|
||||
func NewDefault() *Config {
|
||||
return &Config{
|
||||
Debug: false,
|
||||
Log: LogConfig{
|
||||
Level: logger.LevelInfo,
|
||||
Format: logger.FormatHuman,
|
||||
@ -82,6 +89,9 @@ func NewDefault() *Config {
|
||||
RedirectURL: "http://localhost:8081/oauth2/callback",
|
||||
PostLogoutRedirectURL: "http://localhost:8081",
|
||||
},
|
||||
Database: DatabaseConfig{
|
||||
DSN: "host=localhost database=daddy",
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
79
internal/database/migration.go
Normal file
79
internal/database/migration.go
Normal file
@ -0,0 +1,79 @@
|
||||
package database
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/jackc/pgx/v4"
|
||||
|
||||
"github.com/jackc/pgx/v4/pgxpool"
|
||||
"github.com/pkg/errors"
|
||||
"gitlab.com/wpetit/goweb/middleware/container"
|
||||
)
|
||||
|
||||
type MigrationFunc func(ctx context.Context, tx pgx.Tx) error
|
||||
|
||||
type Migration struct {
|
||||
version string
|
||||
up MigrationFunc
|
||||
down MigrationFunc
|
||||
}
|
||||
|
||||
func (m *Migration) Version() string {
|
||||
return m.version
|
||||
}
|
||||
|
||||
func (m *Migration) Up(ctx context.Context) error {
|
||||
pool, err := m.getDatabaseService(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = WithTx(ctx, pool, func(ctx context.Context, tx pgx.Tx) error {
|
||||
return m.up(ctx, tx)
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not apply up migration")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Migration) Down(ctx context.Context) error {
|
||||
pool, err := m.getDatabaseService(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = WithTx(ctx, pool, func(ctx context.Context, tx pgx.Tx) error {
|
||||
return m.down(ctx, tx)
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not apply down migration")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Migration) getDatabaseService(ctx context.Context) (*pgxpool.Pool, error) {
|
||||
ctn, err := container.From(ctx)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not retrieve service container")
|
||||
}
|
||||
|
||||
pool, err := From(ctn)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not retrieve database service")
|
||||
}
|
||||
|
||||
return pool, nil
|
||||
}
|
||||
|
||||
func NewMigration(version string, up, down MigrationFunc) *Migration {
|
||||
return &Migration{
|
||||
version: version,
|
||||
up: up,
|
||||
down: down,
|
||||
}
|
||||
}
|
24
internal/database/provider.go
Normal file
24
internal/database/provider.go
Normal file
@ -0,0 +1,24 @@
|
||||
package database
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/jackc/pgx/v4/pgxpool"
|
||||
"github.com/pkg/errors"
|
||||
"gitlab.com/wpetit/goweb/service"
|
||||
)
|
||||
|
||||
func ServiceProvider(dsn string) service.Provider {
|
||||
pool, err := pgxpool.Connect(context.Background(), dsn)
|
||||
if err != nil {
|
||||
err = errors.Wrap(err, "could not connect to database")
|
||||
}
|
||||
|
||||
return func(ctn *service.Container) (interface{}, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return pool, nil
|
||||
}
|
||||
}
|
34
internal/database/service.go
Normal file
34
internal/database/service.go
Normal file
@ -0,0 +1,34 @@
|
||||
package database
|
||||
|
||||
import (
|
||||
"github.com/jackc/pgx/v4/pgxpool"
|
||||
"github.com/pkg/errors"
|
||||
"gitlab.com/wpetit/goweb/service"
|
||||
)
|
||||
|
||||
const ServiceName service.Name = "database"
|
||||
|
||||
// From retrieves the database pool service in the given container
|
||||
func From(container *service.Container) (*pgxpool.Pool, error) {
|
||||
service, err := container.Service(ServiceName)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "error while retrieving '%s' service", ServiceName)
|
||||
}
|
||||
|
||||
srv, ok := service.(*pgxpool.Pool)
|
||||
if !ok {
|
||||
return nil, errors.Errorf("retrieved service is not a valid '%s' service", ServiceName)
|
||||
}
|
||||
|
||||
return srv, nil
|
||||
}
|
||||
|
||||
// Must retrieves the database pool service in the given container or panic otherwise
|
||||
func Must(container *service.Container) *pgxpool.Pool {
|
||||
srv, err := From(container)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return srv
|
||||
}
|
38
internal/database/tx.go
Normal file
38
internal/database/tx.go
Normal file
@ -0,0 +1,38 @@
|
||||
package database
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/jackc/pgx/v4"
|
||||
"github.com/jackc/pgx/v4/pgxpool"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func WithTx(ctx context.Context, pool *pgxpool.Pool, fn func(context.Context, pgx.Tx) error) error {
|
||||
tx, err := pool.BeginTx(ctx, pgx.TxOptions{})
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not begin transaction")
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if err := tx.Rollback(ctx); err != nil && !errors.Is(err, pgx.ErrTxClosed) {
|
||||
panic(errors.Wrap(err, "could not rollback transaction"))
|
||||
}
|
||||
}()
|
||||
|
||||
if err := fn(ctx, tx); err != nil {
|
||||
err := errors.Wrap(err, "could not apply down migration")
|
||||
|
||||
if rollbackErr := tx.Rollback(ctx); rollbackErr != nil {
|
||||
return errors.Wrap(err, rollbackErr.Error())
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
if err := tx.Commit(ctx); err != nil {
|
||||
return errors.Wrap(err, "could not commit transaction")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
94
internal/database/version_resolver.go
Normal file
94
internal/database/version_resolver.go
Normal file
@ -0,0 +1,94 @@
|
||||
package database
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/jackc/pgx/v4"
|
||||
"github.com/jackc/pgx/v4/pgxpool"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
type VersionResolver struct {
|
||||
pool *pgxpool.Pool
|
||||
}
|
||||
|
||||
func (r *VersionResolver) Current(ctx context.Context) (string, error) {
|
||||
var version string
|
||||
|
||||
err := WithTx(ctx, r.pool, func(ctx context.Context, tx pgx.Tx) error {
|
||||
err := tx.QueryRow(ctx, `SELECT version FROM database_schema WHERE is_current = true;`).
|
||||
Scan(&version)
|
||||
|
||||
if errors.Is(err, pgx.ErrNoRows) {
|
||||
return nil
|
||||
}
|
||||
|
||||
return err
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "could execute version resolver init transaction")
|
||||
}
|
||||
|
||||
return version, nil
|
||||
}
|
||||
|
||||
func (r *VersionResolver) Set(ctx context.Context, version string) error {
|
||||
err := WithTx(ctx, r.pool, func(ctx context.Context, tx pgx.Tx) error {
|
||||
if version != "" {
|
||||
_, err := tx.Exec(ctx, `
|
||||
INSERT INTO database_schema (version, is_current, migrated_at)
|
||||
VALUES
|
||||
(
|
||||
$1,
|
||||
true,
|
||||
now()
|
||||
)
|
||||
ON CONFLICT ON CONSTRAINT unique_version
|
||||
DO UPDATE SET migrated_at = now(), is_current = true;
|
||||
`, version)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
_, err := tx.Exec(ctx, `
|
||||
UPDATE database_schema SET is_current = false, migrated_at = null WHERE version <> $1;
|
||||
`, version)
|
||||
|
||||
return err
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not update schema version")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *VersionResolver) Init(ctx context.Context) error {
|
||||
err := WithTx(ctx, r.pool, func(ctx context.Context, tx pgx.Tx) error {
|
||||
_, err := tx.Exec(ctx, `
|
||||
CREATE TABLE IF NOT EXISTS database_schema(
|
||||
version TEXT NOT NULL,
|
||||
migrated_at TIME,
|
||||
is_current BOOLEAN,
|
||||
CONSTRAINT unique_version UNIQUE(version)
|
||||
);`)
|
||||
|
||||
return err
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could execute version resolver init transaction")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewVersionResolver(pool *pgxpool.Pool) *VersionResolver {
|
||||
return &VersionResolver{
|
||||
pool: pool,
|
||||
}
|
||||
}
|
56
internal/gqlgen.yml
Normal file
56
internal/gqlgen.yml
Normal file
@ -0,0 +1,56 @@
|
||||
# Where are all the schema files located? globs are supported eg src/**/*.graphqls
|
||||
schema:
|
||||
- graph/*.graphqls
|
||||
|
||||
# Where should the generated server code go?
|
||||
exec:
|
||||
filename: graph/generated/generated.go
|
||||
package: generated
|
||||
|
||||
# Uncomment to enable federation
|
||||
# federation:
|
||||
# filename: graph/generated/federation.go
|
||||
# package: generated
|
||||
|
||||
# Where should any generated models go?
|
||||
model:
|
||||
filename: graph/model/models_gen.go
|
||||
package: model
|
||||
|
||||
# Where should the resolver implementations go?
|
||||
resolver:
|
||||
layout: follow-schema
|
||||
dir: graph
|
||||
package: graph
|
||||
|
||||
# Optional: turn on use `gqlgen:"fieldName"` tags in your models
|
||||
# struct_tag: json
|
||||
|
||||
# Optional: turn on to use []Thing instead of []*Thing
|
||||
# omit_slice_element_pointers: false
|
||||
|
||||
# Optional: set to speed up generation time by not performing a final validation pass.
|
||||
# skip_validation: true
|
||||
|
||||
# gqlgen will search for any type names in the schema in these go packages
|
||||
# if they match it will use them, otherwise it will generate them.
|
||||
autobind:
|
||||
- "forge.cadoles.com/Cadoles/daddy/internal/graph/model"
|
||||
|
||||
# This section declares type mapping between the GraphQL and go type systems
|
||||
#
|
||||
# The first line in each type will be used as defaults for resolver arguments and
|
||||
# modelgen, the others will be allowed when binding to fields. Configure them to
|
||||
# your liking
|
||||
models:
|
||||
ID:
|
||||
model:
|
||||
- github.com/99designs/gqlgen/graphql.ID
|
||||
- github.com/99designs/gqlgen/graphql.Int
|
||||
- github.com/99designs/gqlgen/graphql.Int64
|
||||
- github.com/99designs/gqlgen/graphql.Int32
|
||||
Int:
|
||||
model:
|
||||
- github.com/99designs/gqlgen/graphql.Int
|
||||
- github.com/99designs/gqlgen/graphql.Int64
|
||||
- github.com/99designs/gqlgen/graphql.Int32
|
8
internal/graph/model/models_gen.go
Normal file
8
internal/graph/model/models_gen.go
Normal file
@ -0,0 +1,8 @@
|
||||
// Code generated by github.com/99designs/gqlgen, DO NOT EDIT.
|
||||
|
||||
package model
|
||||
|
||||
type User struct {
|
||||
Name *string `json:"name"`
|
||||
Email string `json:"email"`
|
||||
}
|
7
internal/graph/resolver.go
Normal file
7
internal/graph/resolver.go
Normal file
@ -0,0 +1,7 @@
|
||||
package graph
|
||||
|
||||
// This file will not be regenerated automatically.
|
||||
//
|
||||
// It serves as dependency injection for your app, add any dependencies you require here.
|
||||
|
||||
type Resolver struct{}
|
12
internal/graph/schema.graphqls
Normal file
12
internal/graph/schema.graphqls
Normal file
@ -0,0 +1,12 @@
|
||||
# GraphQL schema example
|
||||
#
|
||||
# https://gqlgen.com/getting-started/
|
||||
|
||||
type User {
|
||||
name: String
|
||||
email: String!
|
||||
}
|
||||
|
||||
type Query {
|
||||
userProfile: User
|
||||
}
|
21
internal/graph/schema.resolvers.go
Normal file
21
internal/graph/schema.resolvers.go
Normal file
@ -0,0 +1,21 @@
|
||||
package graph
|
||||
|
||||
// This file will be automatically regenerated based on the schema, any resolver implementations
|
||||
// will be copied through when generating and any unknown code will be moved to the end.
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"forge.cadoles.com/Cadoles/daddy/internal/graph/generated"
|
||||
"forge.cadoles.com/Cadoles/daddy/internal/graph/model"
|
||||
)
|
||||
|
||||
func (r *queryResolver) UserProfile(ctx context.Context) (*model.User, error) {
|
||||
panic(fmt.Errorf("not implemented"))
|
||||
}
|
||||
|
||||
// Query returns generated.QueryResolver implementation.
|
||||
func (r *Resolver) Query() generated.QueryResolver { return &queryResolver{r} }
|
||||
|
||||
type queryResolver struct{ *Resolver }
|
146
internal/migration/manager.go
Normal file
146
internal/migration/manager.go
Normal file
@ -0,0 +1,146 @@
|
||||
package migration
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrNoAvailableMigration = errors.New("no available migration")
|
||||
ErrMigrationNotFound = errors.New("migration not found")
|
||||
)
|
||||
|
||||
type Manager struct {
|
||||
migrations []Migration
|
||||
resolver VersionResolver
|
||||
}
|
||||
|
||||
func (m *Manager) Up(ctx context.Context) error {
|
||||
currentVersion, err := m.resolver.Current(ctx)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not retrieve current version")
|
||||
}
|
||||
|
||||
migrate := func(up Migration) error {
|
||||
if err := up.Up(ctx); err != nil {
|
||||
return errors.Wrapf(err, "could not apply '%s' up migration", up.Version())
|
||||
}
|
||||
|
||||
if err := m.resolver.Set(ctx, up.Version()); err != nil {
|
||||
return errors.Wrapf(err, "could not update schema version to '%s'", up.Version())
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
if currentVersion == "" {
|
||||
up := m.migrations[0]
|
||||
|
||||
return migrate(up)
|
||||
}
|
||||
|
||||
for i, mi := range m.migrations {
|
||||
if mi.Version() != currentVersion && currentVersion != "" {
|
||||
continue
|
||||
}
|
||||
|
||||
// Already at latest, do nothing
|
||||
if i >= len(m.migrations)-1 {
|
||||
return nil
|
||||
}
|
||||
|
||||
up := m.migrations[i+1]
|
||||
|
||||
return migrate(up)
|
||||
}
|
||||
|
||||
return errors.WithStack(ErrMigrationNotFound)
|
||||
}
|
||||
|
||||
func (m *Manager) Down(ctx context.Context) error {
|
||||
currentVersion, err := m.resolver.Current(ctx)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not retrieve current version")
|
||||
}
|
||||
|
||||
for i, mi := range m.migrations {
|
||||
if mi.Version() != currentVersion {
|
||||
continue
|
||||
}
|
||||
|
||||
if err := mi.Down(ctx); err != nil {
|
||||
return errors.Wrapf(err, "could not apply '%s' down migration", mi.Version())
|
||||
}
|
||||
|
||||
var version string
|
||||
|
||||
// Already at oldest, do nothing
|
||||
if i != 0 {
|
||||
down := m.migrations[i-1]
|
||||
version = down.Version()
|
||||
}
|
||||
|
||||
if err := m.resolver.Set(ctx, version); err != nil {
|
||||
return errors.Wrapf(err, "could not update schema version to '%s'", version)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
return errors.WithStack(ErrMigrationNotFound)
|
||||
}
|
||||
|
||||
func (m *Manager) Latest(ctx context.Context) error {
|
||||
for {
|
||||
isLatest, err := m.IsLatest(ctx)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not retrieve schema state")
|
||||
}
|
||||
|
||||
if isLatest {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := m.Up(ctx); err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (m *Manager) Register(migrations ...Migration) {
|
||||
m.migrations = migrations
|
||||
}
|
||||
|
||||
func (m *Manager) CurrentVersion(ctx context.Context) (string, error) {
|
||||
return m.resolver.Current(ctx)
|
||||
}
|
||||
|
||||
func (m *Manager) LatestVersion() (string, error) {
|
||||
if len(m.migrations) == 0 {
|
||||
return "", errors.WithStack(ErrNoAvailableMigration)
|
||||
}
|
||||
|
||||
return m.migrations[len(m.migrations)-1].Version(), nil
|
||||
}
|
||||
|
||||
func (m *Manager) IsLatest(ctx context.Context) (bool, error) {
|
||||
currentVersion, err := m.resolver.Current(ctx)
|
||||
if err != nil {
|
||||
return false, errors.Wrap(err, "could not retrieve current version")
|
||||
}
|
||||
|
||||
latestVersion, err := m.LatestVersion()
|
||||
if err != nil {
|
||||
return false, errors.Wrap(err, "could not retrieve latest version")
|
||||
}
|
||||
|
||||
return currentVersion == latestVersion, nil
|
||||
}
|
||||
|
||||
func NewManager(resolver VersionResolver) *Manager {
|
||||
return &Manager{
|
||||
resolver: resolver,
|
||||
migrations: make([]Migration, 0),
|
||||
}
|
||||
}
|
9
internal/migration/migration.go
Normal file
9
internal/migration/migration.go
Normal file
@ -0,0 +1,9 @@
|
||||
package migration
|
||||
|
||||
import "context"
|
||||
|
||||
type Migration interface {
|
||||
Version() string
|
||||
Up(context.Context) error
|
||||
Down(context.Context) error
|
||||
}
|
13
internal/migration/provider.go
Normal file
13
internal/migration/provider.go
Normal file
@ -0,0 +1,13 @@
|
||||
package migration
|
||||
|
||||
import (
|
||||
"gitlab.com/wpetit/goweb/service"
|
||||
)
|
||||
|
||||
func ServiceProvider(resolver VersionResolver) service.Provider {
|
||||
manager := NewManager(resolver)
|
||||
|
||||
return func(ctn *service.Container) (interface{}, error) {
|
||||
return manager, nil
|
||||
}
|
||||
}
|
33
internal/migration/service.go
Normal file
33
internal/migration/service.go
Normal file
@ -0,0 +1,33 @@
|
||||
package migration
|
||||
|
||||
import (
|
||||
"github.com/pkg/errors"
|
||||
"gitlab.com/wpetit/goweb/service"
|
||||
)
|
||||
|
||||
const ServiceName service.Name = "migration"
|
||||
|
||||
// From retrieves the migration service in the given container.
|
||||
func From(container *service.Container) (*Manager, error) {
|
||||
service, err := container.Service(ServiceName)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "error while retrieving '%s' service", ServiceName)
|
||||
}
|
||||
|
||||
srv, ok := service.(*Manager)
|
||||
if !ok {
|
||||
return nil, errors.Errorf("retrieved service is not a valid '%s' service", ServiceName)
|
||||
}
|
||||
|
||||
return srv, nil
|
||||
}
|
||||
|
||||
// Must retrieves the migration service in the given container or panic otherwise.
|
||||
func Must(container *service.Container) *Manager {
|
||||
srv, err := From(container)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return srv
|
||||
}
|
8
internal/migration/version_resolver.go
Normal file
8
internal/migration/version_resolver.go
Normal file
@ -0,0 +1,8 @@
|
||||
package migration
|
||||
|
||||
import "context"
|
||||
|
||||
type VersionResolver interface {
|
||||
Current(context.Context) (string, error)
|
||||
Set(context.Context, string) error
|
||||
}
|
@ -2,7 +2,11 @@ package route
|
||||
|
||||
import (
|
||||
"forge.cadoles.com/Cadoles/daddy/internal/config"
|
||||
"forge.cadoles.com/Cadoles/daddy/internal/graph"
|
||||
"forge.cadoles.com/Cadoles/daddy/internal/graph/generated"
|
||||
oidc "forge.cadoles.com/wpetit/goweb-oidc"
|
||||
"github.com/99designs/gqlgen/graphql/handler"
|
||||
"github.com/99designs/gqlgen/graphql/playground"
|
||||
|
||||
"github.com/go-chi/chi"
|
||||
"gitlab.com/wpetit/goweb/static"
|
||||
@ -18,6 +22,17 @@ func Mount(r *chi.Mux, config *config.Config) error {
|
||||
r.Route("/api", func(r chi.Router) {
|
||||
r.Use(oidc.Middleware)
|
||||
|
||||
gql := handler.NewDefaultServer(
|
||||
generated.NewExecutableSchema(generated.Config{
|
||||
Resolvers: &graph.Resolver{},
|
||||
}),
|
||||
)
|
||||
|
||||
if config.Debug {
|
||||
r.Get("/v1/graphql", playground.Handler("GraphQL playground", "/api/v1/graphql"))
|
||||
}
|
||||
|
||||
r.Post("/v1/graphql", gql.ServeHTTP)
|
||||
})
|
||||
|
||||
notFoundHandler := r.NotFoundHandler()
|
||||
|
Reference in New Issue
Block a user