ããã«ã¡ã¯ãï¼æããnewmoã§ã¤ã³ã¿ã¼ã³ããã¦ããå ä¹å (@horinouchi09)ã¨ç³ãã¾ãã
nemwoã§ã¯ããã¯ã¨ã³ãã¨ã³ã¸ãã¢ã¨ãã¦ããã¸ãã¹ãã¡ã¤ã³ã®APIã®éçºããã©ãããã©ã¼ã ã¨ã³ã¸ãã¢ãªã³ã°ã®ã¿ã¹ã¯ãªã©å¤å²ã«ããã£ã¦ãããã¯ãéçºã«æºãã£ã¦ãã¾ãã
Goè¨èªã§ã®éçºã¯æªçµé¨ããã®ã¹ã¿ã¼ãã§ããããããã¯ã¨ã³ãã¨ã³ã¸ãã¢ã®itoãããã¯ããå¤ãã®æ¹ã ã«ãµãã¼ããã¦ããã ããæ¥½ããéçºãã§ãã¦ãã¾ãï¼
ãã¦ãä»åã¯ç§ãnewmoã§ã®ã¤ã³ã¿ã¼ã³ãéãã¦äººçåã®OSS Contributeããã話ããã¾ãã
newmoã®éçºã¹ã¿ã¤ã«
newmoã§ã¯ã¯ã©ã¤ã¢ã³ããããµã¼ãã¼ã®APIãå¼ã³åºãã¹ã¿ã¤ã«ã¨ãã¦GraphQLãæ¡ç¨ãã¦ãã¾ãï¼è©³ããã¯ãã¡ããã覧ãã ããï¼ã
GraphQLã®ãã£ã¬ã¯ãã£ã
GraphQLã«é¢ãã詳ãã説æã¯çç¥ãã¾ãããGraphQLã§ã¯ä»¥ä¸ã®ãããªã¹ãã¼ããå®ç¾©ãããã¨ã§APIãæç¤ºãããã¨ãã§ãã¾ãã
# ã¹ãã¼ãå®ç¾© type Query { passenger: Passenger! } type Passenger { passengerId: String! name: String! nickname: String! @deprecated(reason: "old") }
å
ã»ã©ã®ã¹ãã¼ãå®ç¾©ã®ä¾ã«ãã£ã@deprecated
ã¯ãã£ã¬ã¯ãã£ãã¨å¼ã°ãããã®ã§ãã
GraphQLã§ã¯ããã£ã¬ã¯ãã£ããã¹ãã¼ãå®ç¾©ã®ãã£ã¼ã«ããªã©ã«ä»ä¸ãããã¨ã§æ å ±ã追å ãããã¨ãã§ãã¾ãã
ä¾ãã°ãå
ã»ã©ã®ä¾ã®@deprecated
ã¯ãPassengerã®nicknameãã£ã¼ã«ãã鿍奍ã§ãããã¨ãæå³ããGraphQLã®æ¨æºä»æ§ã§å®ç¾©ããã¦ãããã£ã¬ã¯ãã£ãã§ãã
ããã«ã@deprecated
ã®ãããªæ¨æºã§ç¨æããã¦ãããã£ã¬ã¯ãã£ãã«å ãã¦ãnewmoã§ã¯ç¬èªã®ãã£ã¬ã¯ãã£ããå®ç¾©ãã¦ãã¾ãã
@validateString
ã¨ãããã£ã¬ã¯ãã£ãããã®ä¸ä¾ã§ãã
# ä¾ input DriverInformationInput { driverId: String! @validateString(format: UUID) }
ããã§ã®@validateString
ã¯ã¯ã©ã¢ã³ãããéããã¦ããdriverIdã®ããªãã¼ã·ã§ã³ã«ã¼ã«ãæç¤ºã§ãããã£ã¬ã¯ãã£ãã§ãã
ãã£ã¬ã¯ãã£ãã¨ãã¦å®ç¾©ãããã¨ã§driverIdãUUIDã®å½¢å¼ã§ãããã¨ãã¯ã©ã¤ã¢ã³ããããæç½ã«ãªã仿§ãæç¢ºã«ãªãã¾ããããã«newmoã§ã¯gqlgenã¨ããGoç¨ã®GraphQLã³ã¼ãçæãã¼ã«ã«ãã©ã°ã¤ã³ã追å ãããã¨ã§ããªãã¼ã·ã§ã³ã®ã³ã¼ããèªåã§çæãããããã«ãã¦ãã¾ãã
ã³ã¼ãçæã®å®è£ ã¨ãã¦ã¯ãgqlgenãæä¾ãã¦ããGenerateCodeã¨ããhookãå©ç¨ãã¦ãã©ã°ã¤ã³ãæ¸ããããªãã¼ã·ã§ã³ã®å®è£ ãå«ã¾ããresolverã®ã³ã¼ããèªåã§çæãããããã«ãã¦ãã¾ããã
import "github.com/99designs/gqlgen/api" // gqlgenã«ããã³ã¼ãçæé¨å if err := api.Generate( cfg, api.AddPlugin(plugin.New()), // pluginã®è¿½å ); err != nil { return fmt.Errorf("failed to generate files: %w", err) }
// pluginã«å®è£ ãã¦ããGenerateCodeã®ä¾ func (m *Plugin) GenerateCode(data *codegen.Data) error { if !data.Config.Resolver.IsDefined() { return nil } // å ·ä½çãªãã¸ã㯠// å é¨ã§ã¯"github.com/99designs/gqlgen/codegen/templates"ã®Renderã§Goã®ãã¡ã¤ã«ãçæãã¦ãã¾ãã return m.generateSingleFile(data) }
èªå¯ç¨ã®ãã£ã¬ã¯ãã£ãã®å°å ¥
APIã«ã¯ããããã®èªå¯ç¨ã®ãã¼ã¯ã³ãå¿ è¦ã§ããããããç¾ç¶ã®ã¹ãã¼ãããã¯ã©ã®APIãã©ã®ãããªèªå¯æ å ±ãå¿ è¦ããããã¾ãããã¾ããèªå¯ãã§ãã¯ãææ¸ãã§å®è£ ããå¿ è¦ãããæ¼ããçºçãããããªã©ã®åé¡ãããã¾ããã
ããã§èªå¯ç¨ã®ãã£ã¬ã¯ãã£ã@authorization
ãå®ç¾©ãããã¨ã§è¡¨ç¾åãé«ãã¤ã¤ããã®ãããªãã£ã¬ã¯ãã£ããå
ã«èªå¯ãã§ãã¯ã®ã³ã¼ããèªåçæããããã¨èãã¾ããã
@authorizationã®ä»æ§
type Query { Driver: Driver! @authorization(userType: hoge) }
@authorization
ã¯ä¸è¨ã®ä¾ã®ããã«QueryãMutationã®ãã£ã¼ã«ãã«ä»ä¸ãããã¨ã§èªå¯æ
å ±ã表ç¾ããããã«ãããã¨èãã¾ããã
ãããããã®ã¾ã¾ã§ã¯å
¨ã¦ã®QueryãMutationã®ãã£ã¼ã«ãã«å¯¾ãã¦@authorization
ãä»ä¸ãã¦ãããªããã°ãªãã¾ãããã¾ããnewmoã§ã¯åã¹ãã¼ãã®å¤§åã®APIãåä¸ã®èªå¯æ
å ±ãå¿
è¦ã¨ãã¦ããã®ã§ãã¹ãã¼ãã®ããã©ã«ãã®èªå¯æ
å ±ãå®ç¾©ã§ããæ¹ãåççã§ãã
ããã§ä»¥ä¸ã®ããã«schemaã«å¯¾ãã¦@authorization
ãä»ä¸ãããã¨ã«ãã¾ããã
extend schema @authorization(userType: hoge) type Query { Driver: Driver! }
ãã®ããã«å®ç¾©ãã¦ã@authorization
ã®ãªãDriver
ãuserTypeãhogeã§ãããã¨ãå¿
è¦ã«ãªããã®ã¨ãã¦å®è£
ãé²ãã¾ãã
gqlgenã«ããã³ã¼ãçæ
ãã£ã¬ã¯ãã£ãã®ä»æ§ã決ã¾ãã°ã次ã¯@authorization
ã«æ²¿ã£ãã³ã¼ããçæããgqlgenã®ãã©ã°ã¤ã³ã®å®è£
ã§ãã
æ°ããªãã¡ã¤ã«ãçæããã«ã¯ã以ä¸ã®CodeGeneratorã¨ããã¤ã³ã¿ã¼ãã§ã¤ã¹ãæºãããã©ã°ã¤ã³ãä½ããGenrateCodeå ã§ãã¸ãã¯ãæ¸ããã¨ã«ãªãã¾ãã
type CodeGenerator interface { GenerateCode(cfg *codegen.Data) error }
ããã§ã®codegen.Dataã¯ä»¥ä¸ã®ãããªæ§é ä½ã§ãã
ãã®ä¸ã§schemaã«ä»ä¸ãããã£ã¬ã¯ãã£ããå
¥ã£ã¦ãããªSchema *ast.Schema
ã¯ä»¥ä¸ã®ãããªæ§é ä½ã§ããã
type Schema struct { Query *Definition Mutation *Definition Subscription *Definition Types map[string]*Definition Directives map[string]*DirectiveDefinition PossibleTypes map[string][]*Definition Implements map[string][]*Definition Description string Comment *CommentGroup }
ãããããã®Schemaã¨ããæ§é ä½ã®ä¸ã«ã¯schemaã«ä»ä¸ããããã£ã¬ã¯ãã£ããå
¥ã£ã¦ãã¾ããã§ããï¼ãã®ä¸ã®Directives
ã¯ã¹ãã¼ãå
¨ä½ã§å®ç¾©ããã¦ãããã£ã¬ã¯ãã£ããæãã¦ãã¦ãschemaã«ä»ä¸ããããã£ã¬ã¯ãã£ããæ ¼ç´ãã¦ãã訳ã§ã¯ããã¾ããï¼ã
gqlgenã®å©ç¨ããData
ã«schemaä¸ã®ãã£ã¬ã¯ãã£ããå
¥ã£ã¦ããªãã®ã§ã¯ããã©ã°ã¤ã³ã¨ãã¦å
ã»ã©ã®ä»æ§ãæºããã³ã¼ãçæãå®è£
ãããã¨ãã§ãã¾ããã
gqlparserã®ä¿®æ£
gqlgenã¯gqlparserã¨ããGraphQLã¹ãã¼ãããã¼ã¹ããå¥ãªãã¸ããªã®OSSã«ä¾åãã¦ãã¾ãã
ç¹ã«åè¿°ããSchema *ast.Schema
ã«ã¯ãgqlparserã®LoadSchemaã¨ãã颿°ãç¨ãã¦å®ç¾©ãããã¹ãã¼ããè½ã¨ããã¾ãã¦ãã¾ããgqlparserã®LoadSchemaã®ä¸ã§ä½¿ããã¦ããvalidatorã®LoadSchemaã¯ä»¥ä¸ã®ãããªé¢æ°ã§ãã
func LoadSchema(inputs ...*Source) (*Schema, error) { sd, err := parser.ParseSchemas(inputs...) if err != nil { return nil, gqlerror.WrapIfUnwrapped(err) } return ValidateSchemaDocument(sd) }
ããããgqlparserãèªã¿è¾¼ãã§ããã¨ãParserSchema
ã§ã¯schemaã«ä»ä¸ãããã£ã¬ã¯ãã£ãããã¡ãã¨Parseãã¦ãã¾ããããValidateSchemaDocument
å
ã§æ¨ã¦ããã¦ãããã¨ããããã¾ããã
ããã§ã以ä¸ã®ããã«SchemaDirectives
ã¨ãããã£ã¼ã«ãã追å ãValidateSchemaDocument
å
ã§ä»ãè¶³ãããã«å¤æ´ãããã«ãªã¯ã¨ã¹ããæãããã¨ã«ãã¾ããã
type Schema struct { Query *Definition Mutation *Definition Subscription *Definition SchemaDirectives DirectiveList // ãã®ãã£ã¼ã«ãã追å ï¼ Types map[string]*Definition Directives map[string]*DirectiveDefinition PossibleTypes map[string][]*Definition Implements map[string][]*Definition Description string Comment *CommentGroup }
å®éã®ãã«ãªã¯ã¨ã¹ãããã¡ãã§ãã
https://github.com/vektah/gqlparser/pull/318/files
ãã¡ãã®ãã«ãªã¯ã¨ã¹ãããã¼ã¸ãããå®éã«newmoã®gqlgenã¯Schemaã«ä»ä¸ãããã£ã¬ã¯ãã£ããå ã«ã³ã¼ãçæãã§ããããã«ãªãã¾ããã
çµããã«
ãã®ãããªèæ¯ã§äººçåã®OSS Contributeã«æåãããã¨ãã§ãã¾ããï¼
newmoã§ã¯å¨ãã®ã¨ã³ã¸ãã¢ã®æ¹ã ãå½ããåã®ããã«OSSã«ãã«ãªã¯ã¨ã¹ããæãã¦ããã®ã§ãèªåèªèº«ã®æèãå¤ãã£ã¦ãã¦ããæè¦ãããã¾ãã
newmoã¯ãã¸ãã¹ãã¡ã¤ã³ã®éçºã«ã¹ãã¼ãæããã䏿¹ã§ãçç£æ§ãé«ããããã®ãã¼ã«ã®æ´åãå°æ¥ã®è² åµã«ãªããªããããªè¨è¨ãªã©ã«ãåãå ¥ãã¦ãããã¤ã³ã¿ã¼ã³ã¨ãã¦åå¼·ã§ãããã¨ã大å¤å¤ãã§ãã
ä»å¾ãnewmoã®ãããã¯ãéçºã«å°ãã§ãåã«ãªãããç§»åã§å°åãã«ã©ãã«ã«ããå®ç¾ã§ããããã«éé²ãã¾ãï¼
newmoã§ã¯ã¨ã³ã¸ãã¢ãç©æ¥µçã«æ¡ç¨ä¸ã§ãï¼ãã£ãªã¢ãµã¤ãã¯ãã¡ãâ careers.newmo.me