Upgrade to Pro — share decks privately, control downloads, hide ads and more …

OpenAPI Generator Perl Clientでも型チューニングしたい!!

OpenAPI Generator Perl Clientでも型チューニングしたい!!

吉祥寺.pm30【オンライン】  の登壇資料です
https://kichijojipm.connpass.com/event/254162/

AnaTofuZ

July 28, 2022
Tweet

More Decks by AnaTofuZ

Other Decks in Technology

Transcript

  1. OpenAPIで/pet にPOSTするrequestBodyの内容 送るPetObjectには型が存在する 配列も送ることができる Pet: type: object properties: id: type:

    integer format: int64 name: type: string example: doggie age: type: integer format: int64 photoUrls: type: array items: type: string
  2. PerlClient API Clientのインスタンスを作って、APIに対応する use WWW::OpenAPIClient::PetApi; my $api_instance = WWW::OpenAPIClient::PetApi->new( #

    Configure OAuth2 access token for authorization: petstore_auth access_token => 'YOUR_ACCESS_TOKEN', ); my $age = "25"; my $pet = WWW::OpenAPIClient::Object::Pet->new(age => $age); eval { $api_instance->add_pet(pet => $pet); }; if ($@) { warn "Exception when calling PetApi->add_pet: $@\n"; }
  3. 突然のサーバーエラー golangで書いたサーバーに対してリクエストしたらエラーが発生した parsing body body from \"\" failed, because json:

    cannot unmarshal string into Go struct field AddPet.age of type int64 ageで死んでいるけど、ちゃんとageには25って数値を与えたはず...
  4. コードを見返す my $age = '25'; my $pet = WWW::OpenAPIClient::Object::Pet->new(age =>

    $age); $api_instance->add_pet(pet => $pet); 25で送っとるやん
  5. コードを見返す my $age = '25'; my $pet = WWW::OpenAPIClient::Object::Pet->new(age =>

    $age); $api_instance->add_pet(pet => $pet); 25で送っとるやん よく見たら '25' だな....
  6. コードを見返す my $age = '25'; my $pet = WWW::OpenAPIClient::Object::Pet->new(age =>

    $age); $api_instance->add_pet(pet => $pet); 25で送っとるやん よく見たら '25' だな.... これPerlのJSON問題じゃん!!!!
  7. json変換部分 TO_JSON といういかにもなメソッドがある Perlはオブジェクトを直接JSON化できない それでもなんとかオブジェクトから変換したい時用のJSONモジュールのAPI attribute_map の中身をなんか $_data に素朴に詰めている 素朴なので型とか一切みてない...

    # used by JSON for serialization sub TO_JSON { my $self = shift; my $_data = {}; foreach my $_key (keys %{$self->attribute_map}) { if (defined $self->{$_key}) { $_data->{$self->attribute_map->{$_key}} = $self->{$_key}; } } return $_data; }
  8. というわけで気合でどうにかするように 型をチェックしながら強制的にコンテキストを操作!!! if ( grep( /^$type$/, ('int', 'double'))) { #

    https://metacpan.org/pod/JSON#simple-scalars # numify it, ensuring it will be dumped as a number return $data + 0; } elsif ($type eq 'string') { # https://metacpan.org/pod/JSON#simple-scalars # stringified return $data . q(); } elsif ($type eq 'boolean') { # https://metacpan.org/pod/JSON#JSON::true,-JSON::false,-JSON::null return $data ? \1 : \0;
  9. というわけで気合でどうにかするように Date型も正しい値を返すように!!! } elsif ($type eq 'DATE') { if (ref($data)

    eq 'DateTime') { # https://metacpan.org/pod/DateTime#$dt-%3Eymd($optional_separator),-$dt-%3Emdy(...),-$dt-%3Edmy(...) return $data->ymd; } return $data .q(); } elsif ($type eq 'DATE_TIME') { # the date-time notation as defined by RFC 3339, section 5.6, for example, 2017-07-21T17:32:28Z if (ref($data) eq 'DateTime') { # https://metacpan.org/pod/DateTime#$dt-%3Erfc3339 return $data->rfc3339; } return $data .q(); } else { # hash (model), In this case, the TO_JSON of the $data object is executed return $data; }