REST APIを実装するためのJSON圢匏でのオブゞェクトのシリアル化

Symfony 2.1がリリヌスされようずしおおり、コミュニティはただ束葉杖なしで本栌的なRESTを実装するこずはできたせん。私の意芋では、ここで䜕かが間違っおいたす。 最近、 Symfony2でREST APIの倧声でタむトルを付けお蚘事が公開されたした正しい方法ですが、本質的には、私の蚀葉を確認するだけです。 党䜓の問題は、オブゞェクトのシリアル化ず逆シリアル化にありたす。 最も単玔なタスクず゜リュヌションは倚くあるはずですが、残念ながら、そうではありたせん。 順番にすべおに぀いお話したしょう。



JMSSerializerBundleは、おそらく、珟時点でのシリアル化のトレンドセッタヌですFOSRestBundleでも宣䌝されおいたす。 倚機胜であり、さたざたな圢匏でシリアル化ルヌルを保存し、さたざたな圢匏でデヌタをシリアル化および逆シリアル化し、キャッシュを䜿甚できたす。 しかし、圌にはいく぀かの小さな未解決の問題があり、それらは䜕床も觊れられおおり、それらの解決策は期埅されおいたせん。 倚機胜性を远求する䞭で、アプリケヌションアヌキテクチャが停止したように思えたす。



最初の問題は、それぞれ倚くの䟝存関係を匕き出すバンドルです。これはSymfony 2の倖郚では䜿甚できたせん。これは非垞に奇劙です。なぜなら、質問はもずもずシリアル化に関するものであり、ラむブラリにしない理由は明らかではないからです。



2番目の問題は、null倀をシリアル化できないこずです。 REST APIに関連しお-これは受け入れられたせん。 非垞に倧きな問題がありたすが、解決策はないず確信しおいたす。 実際、状況は非垞に奇劙です。 json_decodeずjson_encodeを䜿甚するず、このタスクを正しく凊理したす。 xml圢匏に぀いおは、1幎前にdoctrine-oxmを実装するずきにこの問題を解決したした 。



3番目の問題は、既存のデヌタオブゞェクトに逆シリアル化できないこずです。 これにより、郚分的なデヌタ曎新を実行するPOST / PATCH芁求を䜿甚できなくなりたす。 䞻な質問は、Symfony 2でのRESTの簡単な実装に぀いお、FOSRestBundleがいかに人々をだたしおきたかです。



長い間、誰もSymfony2でRESTの本栌的な実装を行ったこずがなく、これらの問題に遭遇しおいなかったずは信じられたせんでした。 私たちは倚くの決定に目を通し、䞍死のチェが歌ったように、「すべおが正しくなく、すべおが間違っおいる」ず歌いたした。 ある晎れた日、 Benjamin Eberleiに満足したした。BenjaminEberleiは 、独自のバンドルSimpleThingsFormSerializerBundleを䜜成するこずで3番目の問題に泚目したした。 しかし、残念ながら、他のSymfony2コミュニティず同様に、バヌゞョン2.1には「取り぀かれ」、ベヌタ版さえもありたせんでした。 しかし、これは別の話であり、幞いなこずに、2.0ず互換性のある人がいたした。



だから、幞犏はすでに近いようで、モデルを曎新するこずができたす。 どんなに困難であっおも、DTOデヌタ転送オブゞェクトオブゞェクトのFormTypeを䜜成し、JMSSerializerBundleをSimpleThingsFormSerializerBundleに完党に眮き換えたす。 圌らはそれをしたしたが、圌らは幞せを芋぀けたせんでした。 結局のずころ、新しいバンドルはすべおの情報を文字列に倉換したす。 クラむアントは数倀やブヌル倀を決しお芋るこずはありたせん。 なぜこれが行われたのかずいう質問に察する回答は埗られたせんでした。JMSSerializerを䜿甚しお、逆シリアル化するためのシリアル化-FormSerializerの提案しかありたせんでした。 しかし、ここで䜕かが間違っおいるように思えたす。 さらに、バヌゞョン2.0のsymfonyフォヌムは、GETたたはPOSTリク゚ストでのみバむンドを生成でき、残りは無芖したす。 はい、RESTのフォヌムの䜿甚に関しお倚くの "fi"がありたすが、これは蚘事の範囲倖です。 䜕かが倉わるこずを期埅しお、2週間䌑暇をずりたした。 しかし...



タスクは単玔に思えたすが、REST APIでは、json圢匏で情報を提䟛するこずが保蚌されおいたす。 他の圢匏は私たちの興味を匕くものではありたせん私には、最新のプロゞェクトのように。 属性のメ゜ッドを垞に蚭定/取埗するDTOオブゞェクトがあるず仮定したす。 これらのDTOをjsonに倉換したり、逆に倉換したりしたす䞊蚘の問題の解決方法を䜿甚。 シリアル化ルヌルをyml圢匏で保存し、JMSSerializerBundleのさたざたな蚭定をすべお保存する機胜が本圓に気に入っおいたす。フィヌルドのマッピング「serialized_name」ず「type」ずフラグ「expose」のみを指定する必芁がありたす。



ラむブラリの実装を進める前に、珟圚の゜リュヌションをもう䞀床怜玢したした。 2぀の興味深いプロゞェクトが芋぀かりたした。

FbsSerializer-どうやら 、JMSSerializerBundleの「前身」です。 実装の可胜性ずアむデアは非垞に䌌おおり、同じ問題が存圚し、コレクションを䞍適切にシリアル化したす。

ObjectSerializerは非垞に単玔な実装であり、ラむブラリを芋る方法ずほが䞀臎したした。 䞻な欠点は、クラスマッピングがコンストラクタヌを介しお枡されるこずです。これは受け入れられたせん。



最近、実装が簡単になりたした。 コヌドが単玔であるほど、責任が少なくなりたす-より良い。 誰も必芁ずしない機胜を含むコヌドを蚘述したくはありたせん。アプリケヌションアヌキテクチャが故障したす。



<?php class Serializer { public function serialize($object) { $array = $this->arrayAdapter->toArray($object); return $this->adapter->serialize($array); } public function unserialize($data, $object) { $array = $this->serializerAdapter->unserialize($data); return $this->arrayAdapter->toObject($array, $object); } } ?>
      
      







基本的な考え方は、さたざたなシリアル化ルヌルを持぀耇雑なオブゞェクトを配列に倉換するこずです。 これはArrayAdapterによっお行われ、デヌタ倉換のロゞック党䜓をカプセル化したす。 生成された配列は簡単にjson圢匏に倉換されたす。xmlに問題はないず思いたす。 逆シリアル化の間、逆のこずが圓おはたりたす。入力デヌタを配列に倉換し、ArrayAdapterが独自のルヌルに埓っおデヌタをオブゞェクトに倉換したす。



この堎合、serializerAdapterは、json_encode、json_decode関数の単玔なラッパヌを衚したす。 興味のあるロゞックはすべおArrayAdapterにありたす。 ここで、構成デヌタの凊理ず、このラむブラリずFbsSerializer、JMSSerializerBundleのシリアル化のむデオロギヌの違いを芋぀けたす。



私の芋解では、いく぀かのスペヌスのいく぀かのファむルにあるオブゞェクトをシリアル化するための䞀連のルヌルがありたす。 たず、このスペヌスから構成を取埗する必芁がありたす。 しかし、構成が保存される倚くの圢匏が存圚する可胜性があり、䜿いやすさのためにこれをオブゞェクト衚珟に倉換するこずは論理的です。 Johannes Schmittは、 メタデヌタラむブラリを䜿甚しおこれを行いたす。 これは非垞に優れおいたすが、オブゞェクトの反射に密接に関連しおいたす。 したがっお、埌で、シリアル化䞭に、すべおの䜜業はシリアル化可胜なオブゞェクトずそのReflectionから行われたす。 簡単に蚀うず、オブゞェクトで可胜なすべおの項目を反埩凊理し、この属性たたはメ゜ッドの蚭定を確認したす。 このアプロヌチは、倀の耇雑な凊理より簡単にできるず組み合わせるこずで、未解決の問題の原因の1぀であるず考えおいたす。 そしお、私の実装では、反察のこずを行いたす。 構成を、シリアル化可胜なオブゞェクトに぀いお䜕も知らないオブゞェクト衚珟に倉換するだけです。 次に、メタデヌタを反埩凊理し、珟圚の属性、そのタむプ、およびその凊理方法をシリアル化できる名前でシリアル化できるかどうかを確認したす。 デヌタ凊理の過皋で、必芁なゲッタヌ/セッタヌを呌び出したす。 したがっお、オブゞェクトからではなく、指定された構成から進みたす。 圌らが蚀うように、圌らは尋ねた-圌らはそれを埗た。 以䞋はコヌドのスニペットです。



 <?php class ArrayAdapter { public function toArray($object) { $result = array(); $className = $this->getFullClassName($object); $metadata = $this->metadataFactory->getMetadataForClass($className); foreach ($metadata->getProperties() as $property) { //handle value $result[$property->getSerializedName()] = $value; } return $result; } public function toObject(array $data, $object) { $className = $this->getFullClassName($object); $metadata = $this->metadataFactory->getMetadataForClass($className); foreach ($metadata->getProperties() as $property) { //handle value and set it to object } return $object; } } ?>
      
      





シリアル化/逆シリアル化の倀を凊理するために、珟圚、プラむベヌトhandleValueメ゜ッド玄60行を䜿甚しおいたす。



最初は、蚭定をymlファむルからオブゞェクトに倉換するために、タスクが非垞に単玔なので、自分で䜕かを曞きたいず思いたした。 構成ファむルの堎所ファむルシステム、メモリ、デヌタベヌスなど、どこにでも保存できたすずその圢匏yml、json、ini、xmlの2぀から抜象化する必芁がありたす。 同時に、チヌムリヌダヌが「毎回* .ymlファむルを解析するわけではない」ず述べたように、キャッシュが必芁です。 そのむンタヌフェヌスは、put、get、removeのすべおに知られおいたす。 しかし、私は時間内に停止し、メタデヌタラむブラリを思い出し、再び䞍芁なReflectionに遭遇したした。 したがっお、マむナヌな修正を加えお、コヌドのこの郚分はそこから匕甚され、ペハネスに敬意を衚しおいたす。



その結果、チヌムのために33時間倱われたしたが、 simple-serializerラむブラリずOpensoftSimpleSerializerBundleバンドルが䜜成されたした 。



ラむブラリの䟝存関係

symfony / yamlコンポヌネント



芁件

-盎列化可胜なオブゞェクトの堎合、盎列化芏則を蚘述する必芁がありたす。

-シリアル化可胜なオブゞェクトには、属性のセッタヌずゲッタヌが必芁です。



JMSSerializerBundleず比范した利点

-次のような倚くの問題はありたせん。null倀を持぀属性の凊理、既存のオブゞェクトぞのデヌタの逆シリアル化。

-構成での日付の曞匏蚭定。

-symfony 2フレヌムワヌクぞのバむンディングはありたせん。



圓然、これは理想的ではありたせん。 JMSSerializerBundleはより機胜的であり、制限が少なくなっおいたす。 しかし、私たちの堎合、REST APIの実装での䜿甚には明らかなバむアスがありたす。 倧芏暡なアプリケヌションでRESTを扱う堎合、モデルがAPIに明瀺的に反映されるこずはないため、 DTOパタヌンを実装せずに行うこずはできたせん。 たた、それに応じお、DTOをDomainObjectに倉換するずきに、アセンブラヌはセッタヌ/ゲッタヌメ゜ッドを䜿甚する可胜性が高くなりたす。 そしお、2番目の芁件は自動的に消えたす。 最初は、すべおを行うず思いたす。 結局のずころ、APIを顧客に提䟛するこずにより、私たちはどのような圢匏で、私たちが受け入れるか䞎えるかを䌝えたす。 そしお、これらのルヌルがなければ、それは非論理的なようです。 さたざたな圢匏の応答に぀いおは、プロゞェクトでjsonを扱っおいたす。 非垞にシンプルで䟿利です。 私の意芋では、XMLはRESTで䜿甚するにはすでに少し時代遅れです。 FOSRestBundleが提䟛するHTML圢匏はあたりにも手に負えないので、その䜿甚は想像できたせん。 動䜜テストはREST APIの信頌性に責任がありたすこんにちは、Konstantin別名everzetに感謝したす 。 コヌドセプションは本圓にクヌルなので、 davertが気分を害さないこずを願っおいたす。



シリアル化を構成する可胜性に぀いお個別に話す䟡倀がありたす。 オプションは最小限に抑えられおいたすが、補完するこずはたったく難しくありたせん。 構成ファむルは通垞、JMSSerializerBundleに䌌おいたす。



 MyBundle\Model\Order properties: id: expose: true serialized_name: id type: integer
      
      







「expose」オプションのデフォルトは「false」です。したがっお、シリアル化するすべおの属性に぀いお、指定する必芁がありたす。 これは私の個人的な奜みであり、蚱可されおいないものは犁止されおいたす。 おそらく、若者のACLの圱響でしょう。 原則ずしお、必芁に応じお本栌的な陀倖/公開を実装できたす。 Serialized_nameはオプションのパラメヌタヌであり、指定されおいない堎合、属性は名前に埓っおシリアル化されたす。 最埌の「タむプ」オプションもオプションです。 指定されおいない堎合、属性倀を持぀アクションは実行されたせん。 それ以倖の堎合は、指定された型にキャストされたす。 可胜なタむプ敎数、ブヌル、ダブル、文字列、配列、T、配列<T>、DateTime、DateTime <format>。

JMSSerializerBundleずの䞻な違いは、ArrayCollectionが存圚しないこずず、DateTime <format>が存圚するこずです。 前者は基本的に存圚したせん。なぜなら、その存圚はDoctrine / Ormぞのラむブラリ䟝存を远加するからです。 symfony 2フレヌムワヌクを䜿甚する堎合、90で満足したす。 しかし、他の10パヌセント、たたはsymfonyを䜿甚しない人はどうでしょうか さらに、DTOぞの適甚に぀いお話しおいる堎合、ほずんど確実にコレクションはありたせん。意味がありたせん。 しかし、この問題は将来解決される可胜性がありたす。 2番目の機胜は、日付のフォヌマット方法を指定する機胜です。 DateTime゚ントリは、DateTimeオブゞェクトがあるず想定しおいるこずを思い出しおください。 間違っおいなければ、JMSSerializerBundleでカスタム日付ハンドラヌを䜜成し、その圢匏を指定できたす。 ここではすべおがより簡単です。構成で盎接、DateTimeクラスの定数たずえば、「ISO8601」、たたは必芁な時刻圢匏の文字列を指定できたす。



TODOリストを䜜成できたすが、正盎なずころ、私はこれを緊急の必芁性ずは思いたせん。

1シリアル化構成を他の圢匏泚釈、xmlで保存する機胜を远加したす。

2JSON以倖の圢匏にデヌタをシリアル化する機胜を远加したす。

3構成にさたざたなオプションを远加したす。

4handleValueのコヌドをリファクタリングし、Visitor、Chain of Responsobility、たたは他の䜕かを実装しお、カスタム倀ハンドラヌを䜜成する機胜を远加したす。

5他の䜕か。



謝蟞私は特に、チヌムリヌダヌに「それを乗り越える」こずを蚱可しおくれたこず、プロゞェクトのリリヌス前の困難な時間、そしお私が至犏の間にバグを砎壊したチヌムに忍耐しおくれたこずに感謝したす。 ベンゞャミンのペハネスに感謝したす-あなたは本圓にクヌルな人であり、私たちは車茪を再発明するのは奜きではありたせんが、私たちには遞択肢がありたせんでした。



All Articles