ããŒã1.ãµãŒããŒ
ããŒã2.ã¯ã©ã€ã¢ã³ã
ããŒã3.çªç¶å€ç°
ããŒã4.æ€èšŒã çµè«
æ€èšŒãšUnionType
ç§ãçŽé¢ããªããã°ãªããªãã£ãèå³æ·±ãã¿ã¹ã¯ã®1ã€ã¯ãããŒã¿ãå€æŽãããšãã®ãµãŒããŒæ€èšŒã§ããã ãªããžã§ã¯ãã®å€æŽæã«ãšã©ãŒãçºçããå Žåã¯ã©ããªããŸããïŒ èšäºã§ã¯ããã®åé¡ã®å€ãã®è§£æ±ºçãèŠã€ããããšãã§ããŸãããè€ååã®Unionã¿ã€ãã䜿çšããããšã«ããŸããã ç°¡åã«èšãã°ãUnionãšã¯ãresolveïŒïŒã®å®è¡çµæã«å¿ããŠããªã¯ãšã¹ãã®çµæã1ã€ã®ã¿ã€ãã ãã§ãªããç°ãªãå Žåããããšããããšã§ãã
ããå§ããŸããã
ããšãã°ããŠãŒã¶ãŒãªããžã§ã¯ãã«ã¡ãŒã«ãã£ãŒã«ããè¿œå ãïŒ ããŒã1.ãµãŒããŒãåç §ïŒã誀ã£ãã¢ãã¬ã¹ã§ãªããžã§ã¯ããä¿åã§ããªãããã«ããŸãã
ïŒ èšäºã®å®æãããããžã§ã¯ãã¯githubããããŠã³ããŒãã§ããŸã ïŒ
æé 1.ããŒã¿ããŒã¹ã«ãã£ãŒã«ããè¿œå ãã
ããŒã1ãããµãŒããŒã«æ»ãããŠãŒã¶ãŒã«ã¡ãŒã«ãã£ãŒã«ããè¿œå ããŸãããã ããŒã¿ããŒã¹ã«ãã£ãŒã«ããè¿œå ããã«ã¯ã移è¡ãäœæããŸãã
$> yii migrate/create add_email_to_user
ãããéããŠãsafeUpïŒïŒã¡ãœãããå€æŽããŸãã
public function safeUp() { $this->addColumn('user', 'email', $this->string()); }
ä¿åããŠå®è¡
$> yii migrate
æé 2.ã«ãŒã«ããŠãŒã¶ãŒãªããžã§ã¯ãã«è¿œå ãã
Yiiã§æ€èšŒãå®è£ ããå¯äžã®æ£ããæ¹æ³ã¯ãModel :: rulesïŒïŒã¡ãœããããªãŒããŒã©ã€ãããããšã§ãã ãã®ã¡ã«ããºã ã¯ãä»»æã«ã«ã¹ã¿ãã€ãºãããæ€èšŒã®å¯èœãªéãåºç¯ãªå®è£ ãæäŸãããã¹ãŠã®æ©èœã«è©³çŽ°ãªããã¥ã¡ã³ããæ·»ä»ãããŠããŸãã ãããåé¿ãã䟡å€ãããã®ã¯ããããŸããªå Žåã®ã¿ã§ã99ïŒ ã§ãã¬ãŒã ã¯ãŒã¯ããŒã«ã䜿çšããŠãã¹ãŠãå®è¡ã§ããŸãã
/models/User.phpïŒ
... /** * @inheritdoc */ public function rules() { return [ [['id', 'email'], 'required'], [['id', 'status'], 'integer'], [['createDate', 'modityDate', 'lastVisitDate'], 'safe'], [['firstname', 'lastname', 'email'], 'string', 'max' => 45], ['email', 'email'], ]; } ...
ãããã£ãŠãrulesïŒïŒã¡ãœããã«3ã€ã®ã«ãŒã«ãè¿œå ããŸããã
- ãã£ãŒã«ãã空ã«ããããšã¯ã§ããŸããã
- ãã£ãŒã«ãã¯æååã§ãªããã°ãªããŸããã
- ãã£ãŒã«ãã«ã¯æå¹ãªé»åã¡ãŒã«ãå«ãŸããŠããå¿ èŠããããŸãã
ã¹ããã3. GraphQLã¿ã€ããæŽæ°ãã
ã¹ããŒã/ UserType.phpã§ã¯ãå€æŽã¯æå°éã§ãã
... 'email' => [ 'type' => Type::string(), ], ...
ããããçªç¶å€ç°ã§ã¯ã楜ãã¿ãå§ãŸããŸãã
ã¹ããã4. ValidationErrorTypeãè¿œå ãã
Yiiãã¬ãŒã ã¯ãŒã¯ã«æ £ããŠããªãå Žåããã£ãŒã«ããæ€èšŒãããªãã£ãããã«ãªããžã§ã¯ããä¿åãããªãã£ãå Žåã$ object-> getErrorsïŒïŒã¡ãœããã䜿çšããŠãã¹ãŠã®ãšã©ãŒãååŸã§ããããšãæ確ã«ããŸãã ïŒ
[ '' => [ ' ', ' ', ... ], ... ]
ãã®åœ¢åŒã¯éåžžã«äŸ¿å©ã§ãããGraphQLã«ã¯é©ããŠããŸããã äºå®ãé£æ³é åã¯ãªããžã§ã¯ãã®ãã£ãŒã«ããšãªããªããžã§ã¯ãã«å€æããããããJSONã§çŽæ¥åãåºãããšã¯ã§ãããåãªããžã§ã¯ãã«ã¯ç¬èªã®å±æ§ããããŸãã ãããŠãåãã®ããã«ãGraphQLã¯äºæž¬å¯èœãªçµæã§ã®ã¿æ©èœããŸãã ãããã¯ããã¡ãããUserValidationErrorã®ãããªãªããžã§ã¯ãããšã«åå¥ã®ã¿ã€ããäœæã§ããŸãããã®ã¿ã€ãã§ã¯ããã¹ãŠã®ãã£ãŒã«ãããªããžã§ã¯ãèªäœã®ãã£ãŒã«ããšäžèŽããType :: listOfïŒType :: stringïŒïŒïŒãå«ã¿ãŸãã ããããéåžžã«å€ãã®ã¿ã€ãã®æåäœæã¯ããŸãã«ãæé©ã§ã¯ãªãããã§ããã
ãŠãããŒãµã«ã¹ããŒã/ ValidationErrorTypeæ§é ãæã€åäžã®ã¯ã©ã¹ãè¿œå ããŸãã
<?php namespace app\schema; use GraphQL\Type\Definition\ObjectType; use GraphQL\Type\Definition\Type; class ValidationErrorType extends ObjectType { public function __construct() { $config = [ 'fields' => function() { return [ 'field' => Type::string(), 'messages' => Type::listOf(Type::string()), ]; }, ]; parent::__construct($config); } }
ãã®ã¿ã€ãã«ã¯ã1ã€ã®ãã£ãŒã«ãã®æ€èšŒãšã©ãŒæ å ±ãå«ãŸããŸãã ç§ã®å ŽåãValidationErrorTypeã¿ã€ãã®ãã£ãŒã«ãã¯æããã§ããããšã©ãŒãçºçãããã£ãŒã«ãã®ååãšããšã©ãŒãå«ãã¡ãã»ãŒãžã®ãªã¹ããå«ãŸããŠããŸãã ãã¹ãŠãéåžžã«ç°¡åã§ãã
1ã€ã ãã§ãªãããã¹ãŠã®ãã£ãŒã«ããæ€èšŒããçµæãè¿ãå¿ èŠããããããå¥ã®ã¿ã€ããäœæããŸãïŒschema / ValidationErrorsListTypeïŒ
<?php namespace app\schema; use GraphQL\Type\Definition\ObjectType; use GraphQL\Type\Definition\Type; class ValidationErrorsListType extends ObjectType { public function __construct() { $config = [ 'fields' => function() { return [ 'errors' => Type::listOf(Types::validationError()), ]; }, ]; parent::__construct($config); } }
ã¹ããã5. UnionTypeãçæãã
GraphQLã«ã¯UnionåããããŸããããã¯ãresolveïŒïŒãã£ãŒã«ãã®çµæã1ã€ã®åã ãã§ãªããããã€ãã®åã®1ã€ãè¿ãå Žåã§ãïŒãã§ã«æžããããã§ãããããã§ããäžåºŠèšåãã䟡å€ããããŸããïŒã ãããã£ãŠãç§ãã¡ã®ç®æšã¯ããªããžã§ã¯ãã®å€æŽ/äœæãå€æŽããã«æ€èšŒã«åæ Œãããããã®éã®å Žåãæ€èšŒã«æåãããšãå€æŽããããªããžã§ã¯ãèªäœãŸãã¯ValidationErrorsListTypeåã®ãªããžã§ã¯ããè¿ãããšã§ãã
äžä»£ãšã¯ã©ãããæå³ã§ããïŒ äºå®ãæ»ãã®UnionTypeãåçªç¶å€ç°ã«å¯ŸããŠäœæããã®ã§ã¯ãªããåºæ¬åã«åºã¥ããŠãã®å Žã§çæããŸãã ã©ã®ããã«æ£ç¢ºã«ãä»ç§ã¯è¡šç€ºããŸãã
ã¹ããŒã/ Types.phpãå€æŽããŸãã
... use GraphQL\Type\Definition\UnionType; use yii\base\Model; ... private static $validationError; private static $validationErrorsList; // private static $valitationTypes; ... // c public static function validationError() { return self::$validationError ?: (self::$validationError = new ValidationErrorType()); } public static function validationErrorsList() { return self::$validationErrorsList ?: (self::$validationErrorsList = new ValidationErrorsListType()); } // , // , public static function validationErrorsUnionType(ObjectType $type) { // - , // , // ( , / // GraphQL ) if (!isset(self::$valitationTypes[$type->name . 'ValidationErrorsType'])) { // self::$valitationTypes , self::$valitationTypes[$type->name . 'ValidationErrorsType'] = new UnionType([ // 'name' => $type->name . 'ValidationErrorsType', // // ( , // ) 'types' => [ $type, Types::validationErrorsList(), ], // resolveType // // / , // // $model->getError() // 'resolveType' => function ($value) use ($type) { if ($value instanceof Model) { // return $type; } else { // ( , // , // ) return Types::validationErrorsList(); } } ]); } return self::$valitationTypes[$type->name . 'ValidationErrorsType']; } ...
ã¹ããã6.çªç¶å€ç°
UserMutationTypeã«å€æŽãå ããŸãã
... use app\schema\Types; ... // update 'type' => Types::validationErrorsUnionType(Types::user()), ... // 'email' => Type::string(), ... 'resolve' => function(User $user, $args) { // , // .. : // , // , $user->setAttributes($args); if ($user->save()) { return $user; } else { // , - // , // foreach ($user->getErrors() as $field => $messages) { // ValidationErrorType $errors[] = [ 'field' => $field, 'messages' => $messages, ]; } // // // ( ValidationErrorsListType) return ['errors' => $errors]; } } ...
ãããã©ã®ããã«æ©èœããããèŠãæéã§ãã
ãã¹ãäž
GraphiQLãå床éããæãç°¡åãªããšãè©ŠããŠãã ããã
å ¥åãã£ãŒã«ãã§Ctrl +ã¹ããŒã¹ãã¯ãªãã¯ããŠãæŽæ°ã¡ãœãããè¿ãå 容ã確èªããŸãã
ãããã
ããŠãç§ãã¡ã¯äœãå¿ èŠãªã®ããå°ããããšããŠããã®ã§ãäœãèµ·ãããèŠãŠãããŸãã
ã芧ã®ãšãããæåã®ã«ãŒã«ãæ©èœããŸãããããã¯ããã£ãŒã«ããå¿ é ã§ããããšã瀺ããŠããŸãã
ã«ãŒã«2-å®éã«ã¯ãã¡ãŒã«ãã£ãŒã«ãã¯ãã®ãããªãã®ã§ãªããã°ãªããŸããã æ€èšŒã¯æ©èœããŸããã
ããŠãæåŸã«æåããçµæãèŠãŠã¿ãŸãããïŒ
äžè¬ã«ã説æãããŠããæ€èšŒã®ã¢ãããŒãã¯ãå¯äžã®æé©ã§äžå®å šãªãã®ã§ã¯ãªããç¹å®ã®ããŒãºã«åãããŠæ¹åããã³æ¹åã§ãããšç¢ºä¿¡ããŠããŸãããäžè¬çã«ã¯éåžžã«æ®éçã§ãããå®éã«èª°ããå©ããŠåé¡ã®è§£æ±ºçãèŠã€ããããããšãé¡ã£ãŠããŸãåé¡ã
çµè«
çµè«ãå°ãåºããŠãããã®ãæ£ç¢ºã«ç解ããã«ã¯ã4ã€ã®ããŒããã¹ãŠãèªãããšããå§ãããŸãã
GraphQLã䜿çšããå¿ èŠãããã®ã¯ãã€ã§ããïŒ
ãŸãããŸããã²ãŒã ãããããã«å€ãããã©ãããç解ããå¿
èŠããããŸãã ãã¡ãããããã€ãã®ç°¡åãªã¡ãœãããäœæããã¿ã¹ã¯ãããå Žåã¯ãGraphQLã¯å¿
èŠãããŸããã ããã¯é¡åŸ®é¡ã䜿ã£ãäžçš®ã®éã§ãã ç§èŠãGraphQLã®äž»ãªå©ç¹ã®1ã€ã¯ãã¹ã±ãŒãªã³ã°ã®å©äŸ¿æ§ã§ãã ãããŠãã¹ã±ãŒãªã³ã°ããèœåãå¿
èŠã§ã ã»ãŒ ã©ã®ãããžã§ã¯ãã§ãïŒããã«ãäžèŠãããšãããŸã£ããå¿
èŠã®ãªããããžã§ã¯ãã§ãïŒã
APIããå¹³åãã§ããå ŽåãååãšããŠãéžæãããããã³ã«ã®éããæããããšã¯ãããŸããã GraphQLã®çªç¶å€ç°ã¯RESTaã®ã¢ã¯ã·ã§ã³ïŒããŒã«ã®äžã§åããŠãã1ã2æéåŸïŒãããã³op-æ¢ã«RESTful APIãµãŒããŒãæã£ãŠããŸãã
ã ãã...
ãšã³ããªã®ãããå€ãéåžžã«äœãã GraphQLã¯ãšãªèšèªã®æ¬è³ªãç解ããããããèšèªã®ããã¯ãšã³ããšããã³ããšã³ãã«å¿ èŠãªã©ã€ãã©ãªãèŠã€ããããããã©ã®ããã«æ©èœããããç解ããŸããããã«ã¯1æ¥ïŒãŸãã¯æ°æéïŒããããããŸããã
æ°ãããã®ã æ°ããçµéšã¯åžžã«æçšã§ãïŒãã€ãã¹ã§ãã£ãŠãïŒã ãåç¥ã®ããã«ãWebãã¯ãããžãŒã®åéã§ã¯ãæ°ãããã®ããã€ãã¹ããŠãç§ãã¡ã¯å£åããŠããããšãç¥ãããŠããŸãã
å€éšïŒå€éšïŒAPIã®äœ¿çšæ³ã æçµè£œåããå€æ°ã®ã¯ã©ã€ã¢ã³ãã䜿çšããAPIïŒäœãç¥ããªãïŒã§ããå ŽåãGraphQLã¯éåžžã«æè»æ§ããããŸãããããã®ã¯ã©ã€ã¢ã³ãã¯ãŸã£ããç°ãªãããŒãºãæã€ããšãã§ããããã§ãã ããããããã¯äž¡åã®å£ã§ãã æè¡çã«ã¯ãããã¯å©ç¹ã§ãããæ®å¿µãªããšã«ãã¯ã©ã€ã¢ã³ãã¯äœãæ°ããããšãåŠã°ãªããã°ãªãããGraphQL APIã®çµéšãæã€éçºè ãæ¢ãå¿ èŠããããšããäºå®ã«ãã£ãŠãã¯ã©ã€ã¢ã³ããæŒãã®ããããšãã§ããŸãã GraphQLã®å Žåããããã®çšèªã¯å®éã«ã¯éåžžã«çãå Žåããããšããäºå®ã«ããããããïŒã
GraphQLã¯ããªã¢ãŒãäœæ¥ã®å Žåã«ã圹ç«ã¡ãŸãããã®çµæãããã¯ãšã³ãéçºè ãšããã³ããšã³ãéçºè ã®éã®å¯æ¥ãªã³ãã¥ãã±ãŒã·ã§ã³ã®æ¬ åŠïŒæ¯æ¥ã®ã¹ã«ã€ãåŒã³åºããåžžã«ãå¯æ¥ãªãã³ãã¥ãã±ãŒã·ã§ã³ãä¿èšŒãããšã¯éããŸããïŒã
æ¬ ç¹ã®ãã¡ãGraphQL + PHPã®ãããã¯ãŒã¯äžã®ããã€ãã®äŸãæããããšæããŸãããªããªããçã®smushyãã£ã³ã¯ã¯Node.jsãŸãã¯Goã®ããããã䜿çšããããã§ãïŒãã®ã·ãªãŒãºã®èšäºãæžãããä¿ãããŸããïŒã Apolloã©ã€ãã©ãªãšåãç¶æ³ã§ãå ¬åŒããã¥ã¡ã³ãã¯ãã¹ãŠReactã§æžãããŠãããç§ã¯ããã¯ãšã³ãéçºè ãšããŠããããPolymerã§ã©ã®ããã«æ©èœããããç解ããã®ã«æéãè²»ããå¿ èŠããããŸãããã移è¡äžã«å€§ããªåé¡ãšã¯èšããŸããã§ããã ãšããã§ã Mediumã®éåžžã«æçãªApolloããã°ãèªãããšããå§ãããŸãã GraphQLã«é¢ããèå³æ·±ãå®çšçãªèšäºãæ¬åœã«ãããããããŸãã
ãŸããçæã®1ã€ã¯ãSwaggerãApiDoc.jsã®ãããªäŸ¿å©ãªããã¥ã¡ã³ããžã§ãã¬ãŒã¿ãŒããªãããšã§ãã ç§ã¯ãŸã 1å°ã®çºé»æ©ãèŠã€ããããšãã§ããŸããããæ®å¿µãªãããããã¯éåžžã«æ²æšã§ãã PDFã®èª¬æãããé«åºŠãªããã¥ã¡ã³ãã®çµéšãããå Žåã¯ãã³ã¡ã³ãã§å ±æããŠãã ããã
æåäŒæ¥ã®GraphQLãæ¢ã«äœ¿çšããŠããã®ã¯èª°ã§ããïŒ
Github äžè¬ã«ããµã€ãã®å¯Ÿè±¡èªè ã¯éçºè ã§ãããAPIã䜿çšã§ãããã©ããã«ã€ããŠå¿é ããããšã¯ãªããããé©ãã¹ãããšã¯äœããããŸããã ããã¥ã¡ã³ãã¯éåžžã«çŸããææ ®æ·±ãã泚ç®ã«å€ããŸããGraphQLã®åºæ¬ããããã°æ¹æ³ãRESTããã®ç§»è¡ã«é¢ããã¬ã€ãã«é¢ããæ å ±ãå°ãå«ãŸããŠããŸãã
ãã§ã€ã¹ãã㯠GraphQLèªäœã®ã³ã³ã»ããã®éçºè ã§ãããç©æ¥µçã«æšé²ããŠããŸãã Facebookã¯GraphQLãã©ã®ããã«äœ¿çšããŠãããã«ã€ããŠããããã¯ãŒã¯ã«é¢ããå€ãã®ã¬ããŒãããããŸãã
PSïŒåéïŒ APIã§OPTIONSã¡ãœããã䜿çšããŠãªã¯ãšã¹ãåŠçãå®è£ ããããšãå¿ããªãã§ãã ãããããã«ããããµãŒããŒã¯ããã®ãããªãã¹ãŠã®ãªã¯ãšã¹ãã«å¯ŸããŠåžžã«200ã®HTTPã³ãŒããšç©ºã®ããã£ãè¿ããŸãã ããã¯ããªãã®ç¥çµçŽ°èãæããŸãã
äžè¬ã«ãAPIãéçºãããšãã¯CORSã®ããããŒãå¿ããªãã§ãã ããïŒ
<IfModule mod_headers.c> Header add Access-Control-Allow-Origin "*" Header add Access-Control-Allow-Headers "Content-Type, Authorization" Header add Access-Control-Allow-Methods "GET, POST, OPTIONS" </IfModule>