Golang GraphQL 总是将一个变量返回为 null。

huangapple go评论85阅读模式
英文:

Golang GraphQL always returns one variable as null

问题

GraphQL查询字段postlist返回的所有数据都不包括created_at字段,它始终为null。我检查了GetPostBySlugGetPostList函数中的变量,它们从Postgres中获取了数据。我犯了什么错误?

根据您提供的代码,问题可能出在以下几个地方:

  1. model.go文件中的Post结构体定义中,CreatedAt字段的db标签应为db:"created_at",而不是db:"created_at"。请将所有的db:"..."替换为db:"..."

  2. repository.go文件中的GetPostBySlugGetPostList函数中,将post.CreatedAt的格式化字符串"02.01.2006"更改为"2006-01-02",以匹配数据库中created_at字段的日期格式。

请尝试进行这些更改,并重新运行您的代码,看看问题是否得到解决。

英文:

GraphQL query field post and list return all data except created_at. It always null. I check GetPostBySlug and GetPostList variables and it contain data from Postgres. Where is my mistake?

model.go

package post

type Post struct {
	Slug      string `db:"slug"`
	Title     string `db:"title"`
	Content   string `db:"content"`
	Author    string `db:"author"`
	Category  string `db:"category"`
	CreatedAt string `db:"created_at"`
	Published bool   `db:"published"`
}

resolver.go

package post

import (
	"context"

	"github.com/graphql-go/graphql"
)

var postType = graphql.NewObject(
	graphql.ObjectConfig{
		Name: "Post",
		Fields: graphql.Fields{
			"slug": &graphql.Field{
				Type: graphql.String,
			},
			"title": &graphql.Field{
				Type: graphql.String,
			},
			"content": &graphql.Field{
				Type: graphql.String,
			},
			"category": &graphql.Field{
				Type: graphql.String,
			},
			"author": &graphql.Field{
				Type: graphql.String,
			},
			"created_at": &graphql.Field{
				Type: graphql.String,
			},
			"published": &graphql.Field{
				Type: graphql.Boolean,
			},
		},
	},
)

var queryType = graphql.NewObject(
	graphql.ObjectConfig{
		Name: "Query",
		Fields: graphql.Fields{
			"post": &graphql.Field{
				Type:        postType,
				Description: "Get post by slug",
				Args: graphql.FieldConfigArgument{
					"slug": &graphql.ArgumentConfig{
						Type: graphql.String,
					},
				},
				Resolve: func(p graphql.ResolveParams) (interface{}, error) {
					var result interface{}

					slug, _ := p.Args["slug"].(string)
					result = GetPostBySlug(context.Background(), slug)

					return result, nil
				},
			},
			"list": &graphql.Field{
				Type:        graphql.NewList(postType),
				Description: "Get post list",
				Args: graphql.FieldConfigArgument{
					"limit": &graphql.ArgumentConfig{
						Type: graphql.Int,
					},
				},
				Resolve: func(params graphql.ResolveParams) (interface{}, error) {
					var result interface{}

					limit, _ := params.Args["limit"].(int)
					result = GetPostList(context.Background(), limit)

					return result, nil
				},
			},
		},
	})

var mutationType = graphql.NewObject(graphql.ObjectConfig{
	Name: "Mutation",
	Fields: graphql.Fields{
		"create": &graphql.Field{
			Type:        postType,
			Description: "Create new post",
			Args: graphql.FieldConfigArgument{
				"slug": &graphql.ArgumentConfig{
					Type: graphql.NewNonNull(graphql.String),
				},
				"title": &graphql.ArgumentConfig{
					Type: graphql.NewNonNull(graphql.String),
				},
				"content": &graphql.ArgumentConfig{
					Type: graphql.NewNonNull(graphql.String),
				},
				"category": &graphql.ArgumentConfig{
					Type: graphql.NewNonNull(graphql.String),
				},
				"author": &graphql.ArgumentConfig{
					Type: graphql.NewNonNull(graphql.String),
				},
				"published": &graphql.ArgumentConfig{
					Type: graphql.NewNonNull(graphql.Boolean),
				},
			},
			Resolve: func(params graphql.ResolveParams) (interface{}, error) {
				post := Post{
					Slug:      params.Args["slug"].(string),
					Title:     params.Args["title"].(string),
					Content:   params.Args["content"].(string),
					Category:  params.Args["category"].(string),
					Author:    params.Args["author"].(string),
					Published: params.Args["published"].(bool),
				}
				if err := InsertPost(context.Background(), post); err != nil {
					return nil, err
				}
				return nil, nil
			},
		},
		"update": &graphql.Field{
			Type:        postType,
			Description: "Update post",
			Args: graphql.FieldConfigArgument{
				"slug": &graphql.ArgumentConfig{
					Type: graphql.NewNonNull(graphql.String),
				},
				"title": &graphql.ArgumentConfig{
					Type: graphql.NewNonNull(graphql.String),
				},
				"content": &graphql.ArgumentConfig{
					Type: graphql.NewNonNull(graphql.String),
				},
				"category": &graphql.ArgumentConfig{
					Type: graphql.NewNonNull(graphql.String),
				},
				"author": &graphql.ArgumentConfig{
					Type: graphql.NewNonNull(graphql.String),
				},
				"published": &graphql.ArgumentConfig{
					Type: graphql.NewNonNull(graphql.Boolean),
				},
			},
			Resolve: func(params graphql.ResolveParams) (interface{}, error) {
				post := Post{}

				if slug, slugOk := params.Args["slug"].(string); slugOk {
					post.Slug = slug
				}
				if title, titleOk := params.Args["title"].(string); titleOk {
					post.Title = title
				}
				if content, contentOk := params.Args["content"].(string); contentOk {
					post.Content = content
				}

				if category, categoryOk := params.Args["category"].(string); categoryOk {
					post.Category = category
				}

				if published, publishedOk := params.Args["published"].(bool); publishedOk {
					post.Published = published
				}

				if old_slug, old_slugOk := params.Args["old-slug"].(string); old_slugOk {
					if err := UpdatePost(context.Background(), post, old_slug); err != nil {
						return nil, err
					}
				}

				return nil, nil
			},
		},
		"delete": &graphql.Field{
			Type:        postType,
			Description: "Delete post by slug",
			Args: graphql.FieldConfigArgument{
				"slug": &graphql.ArgumentConfig{
					Type: graphql.NewNonNull(graphql.String),
				},
			},
			Resolve: func(params graphql.ResolveParams) (interface{}, error) {
				slug, _ := params.Args["slug"].(string)
				if err := DeletePost(context.Background(), slug); err != nil {
					return nil, err
				}
				return nil, nil
			},
		},
	},
})

var Schema, _ = graphql.NewSchema(
	graphql.SchemaConfig{
		Query:    queryType,
		Mutation: mutationType,
	},
)

repository.go

package post

import (
	"context"
	"errors"
	"fmt"
	"log"
	"os"
	"time"

	"github.com/jackc/pgx/v4"
	"github.com/joho/godotenv"
)

var (
	db      *pgx.Conn
	Info    *log.Logger
	Warning *log.Logger
	Error   *log.Logger
)

func init() {
	err := godotenv.Load("environment/.env")
	if err != nil {
		Error.Fatalf("Can't read \".env\" file: %s\n", err.Error())
	}

	Info = log.New(os.Stdout, "INFO: ", log.Ldate|log.Ltime|log.Lshortfile)
	Warning = log.New(os.Stdout, "WARNING: ", log.Ldate|log.Ltime|log.Lshortfile)
	Error = log.New(os.Stderr, "ERROR: ", log.Ldate|log.Ltime|log.Lshortfile)

	db, err = pgx.Connect(
		context.Background(),
		fmt.Sprintf(
			"postgres://%s:%s@%s:%s/%s",
			os.Getenv("POSTGRES_USER"),
			os.Getenv("POSTGRES_PASSWORD"),
			os.Getenv("POSTGRES_HOST"),
			os.Getenv("POSTGRES_PORT"),
			os.Getenv("POSTGRES_DB"),
		),
	)
	if err != nil {
		Error.Fatalf("Can't connect to database: %s\n", err.Error())
	}
}

func GetPostBySlug(ctx context.Context, slug string) (result interface{}) {
	row, err := db.Query(ctx, "SELECT slug, title, content, author, category, created_at, published FROM posts WHERE slug=$1 LIMIT 1", slug)
	if err != nil {
		Warning.Printf("GetPostBySlug query: %v\n", err.Error())
		return err
	}

	var post Post

	for row.Next() {
		var dateTime time.Time

		err = row.Scan(&post.Slug, &post.Title, &post.Content, &post.Author, &post.Category, &dateTime, &post.Published)
		if err != nil {
			Warning.Printf("Row scan: %v\n", err.Error())
			return nil
		}

		post.CreatedAt = dateTime.Format("02.01.2006")
	}

	return post
}

func GetPostList(ctx context.Context, limit int) (result interface{}) {
	var post Post
	var posts []Post

	var dateTime time.Time

	rows, err := db.Query(ctx, "SELECT slug, title, content, author, category, created_at, published FROM posts LIMIT $1", limit)
	if err != nil {
		Warning.Printf("GetPostList query: %v\n", err.Error())
		return err
	}

	for rows.Next() {
		err = rows.Scan(&post.Slug, &post.Title, &post.Content, &post.Author, &post.Category, &dateTime, &post.Published)
		if err != nil {
			Warning.Printf("Row scan: %v\n", err.Error())
			return nil
		}

		post.CreatedAt = dateTime.Format("02.01.2006")

		posts = append(posts, post)
	}

	return posts
}

func InsertPost(ctx context.Context, post Post) error {
	if SlugExists(ctx, post.Slug) {
		Warning.Printf("Slug \"%s\" already exists!\n", post.Slug)
		return errors.New("slug already exists")
	}

	_, err := db.Exec(
		ctx,
		"INSERT INTO posts (slug, title, content, author, category, created_at, published) VALUES ($1, $2, $3, $4, $5, CURRENT_TIMESTAMP, $6)",
		post.Slug, post.Title, post.Content, post.Author, post.Category, post.Published,
	)
	if err != nil {
		Warning.Printf("InsertPost exec query: %v\n", err.Error())
		return err
	}

	return nil
}

func SlugExists(ctx context.Context, slug string) bool {
	row, err := db.Query(ctx, "SELECT slug FROM posts WHERE slug=$1 LIMIT 1", slug)
	if err != nil {
		Error.Fatalf("SlugExists query: %v\n", err.Error())
	}

	var slug_exists string

	for row.Next() {
		err = row.Scan(&slug_exists)
		if err != nil {
			Error.Fatalf("Row scan: %v\n", err.Error())
		}
	}

	return slug_exists != ""
}

func UpdatePost(ctx context.Context, post Post, old_slug string) error {
	_, err := db.Exec(
		ctx,
		"UPDATE posts SET slug=$1, title=$2, content=$3, author=$4, category=$5, published=$6 WHERE slug=$7",
		post.Slug, post.Title, post.Content, post.Author, post.Category, post.Published, old_slug,
	)
	if err != nil {
		Warning.Printf("UpdatePost exec query: %v\n", err.Error())
		return err
	}

	return nil
}

func DeletePost(ctx context.Context, slug string) error {
	_, err := db.Exec(ctx, "DELETE FROM posts WHERE slug=$1", slug)
	if err != nil {
		Warning.Printf("DeletePost exec query: %v\n", err.Error())
		return err
	}

	return nil
}

query post result

query list result

答案1

得分: 0

总结一下我们在评论中发现的内容:

> 将GraphQL对象的created_at重命名为createdAt。

英文:

To sum up what we found in the comments

> Rename GraphQL object created_at to createdAt

huangapple
  • 本文由 发表于 2021年12月10日 04:12:40
  • 转载请务必保留本文链接:https://go.coder-hub.com/70296129.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定