{"id":18124,"date":"2023-01-20T05:00:00","date_gmt":"2023-01-20T04:00:00","guid":{"rendered":"https:\/\/sii.pl\/blog\/?p=18124"},"modified":"2024-07-22T15:30:46","modified_gmt":"2024-07-22T13:30:46","slug":"flux-architektura-zarzadzania-stanem-w-aplikacjach-webowych","status":"publish","type":"post","link":"https:\/\/sii.pl\/blog\/flux-architektura-zarzadzania-stanem-w-aplikacjach-webowych\/","title":{"rendered":"Flux \u2013 architektura zarz\u0105dzania stanem w aplikacjach webowych"},"content":{"rendered":"\n<p>Podczas tworzenia aplikacji webowych du\u017c\u0105 rol\u0119 odgrywa przep\u0142yw danych. Istnieje kilka podej\u015b\u0107 maj\u0105cych go umo\u017cliwi\u0107 i u\u0142atwi\u0107. Jednym z pierwszych powszechnie stosowanych jest <strong>wzorzec publish-subscribe<\/strong>. Umo\u017cliwia on jednemu komponentowi subskrypcj\u0119 do zdarze\u0144 drugiego komponentu, jednocze\u015bnie wymuszaj\u0105c pewien stopie\u0144 enkapsulacji funkcjonalno\u015bci obu z nich. <\/p>\n\n\n\n<p>Szczeg\u00f3lnym przyk\u0142adem zastosowania tego wzorca jest system zdarze\u0144 u\u017cywany przez przegl\u0105darki. Dlatego te\u017c to w\u0142a\u015bnie tzw. pub\/sub by\u0142 g\u0142\u00f3wnym wyborem w pierwszych frameworkach w JavaScripcie.<\/p>\n\n\n\n<p>Niestety, takie <strong>rozwi\u0105zanie ma swoje wady<\/strong>. Wys\u0142anie kilku zdarze\u0144 jednocze\u015bnie mo\u017ce mie\u0107 niedeterministyczn\u0105 kolejno\u015b\u0107 wykonania, co wraz z rozwojem aplikacji mo\u017ce powodowa\u0107 problem skalowania zale\u017cno\u015bci, prowadz\u0105cy do chaosu w kodzie i wielu b\u0142\u0119d\u00f3w. Dodatkowo, zdarzenia z regu\u0142y odpowiadaj\u0105 za konkretne, bardzo granularne akcje, co sprawia, \u017ce utrzymanie sensownego cyklu \u017cycia komponent\u00f3w jest bardzo ci\u0119\u017ckie i pracoch\u0142onne.<\/p>\n\n\n\n<p>Wraz z rozwojem bogatego ekosystemu webowego powsta\u0142a te\u017c potrzeba stworzenia <strong>sensowniejszego wzorca zarz\u0105dzania stanem w aplikacjach<\/strong>. Potrzebie tej wyszed\u0142 naprzeciw Flux. W artykule przybli\u017c\u0119, czym jest Flux, z jakimi potencjalnymi problemami mo\u017cemy si\u0119 spotka\u0107 podczas wykorzystywania rozwi\u0105zania, a tak\u017ce kr\u00f3tko opisz\u0119 istniej\u0105ce implementacje.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Flux \u2013 czym jest i jak dzia\u0142a?<\/strong><\/h2>\n\n\n\n<p>Flux to opracowany przez Facebooka wzorzec architektury zarz\u0105dzania stanem aplikacji, kt\u00f3ry mia\u0142 rozwi\u0105za\u0107 wymienione wy\u017cej problemy. Ciekawostk\u0105 jest to, \u017ce wywodzi si\u0119 z uporczywego b\u0142\u0119du z licznikiem powiadomie\u0144 w czacie Facebooka, kt\u00f3rego naprawa wymaga\u0142a zmiany architektury ca\u0142ego serwisu. Zainteresowanych odsy\u0142am do prelekcji, w kt\u00f3rej opisano ten problem: <a href=\"https:\/\/www.youtube.com\/watch?v=nYkdrAPrdcw&amp;list=PLb0IAmt7-GS188xDYE-u1ShQmFFGbrk0v&amp;t=621s\" target=\"_blank\" aria-label=\" (opens in a new tab)\" rel=\"noreferrer noopener\" class=\"ek-link\" rel=\"nofollow\" >Hacker Way: Rethinking Web App Development at Facebook<\/a>.<\/p>\n\n\n\n<figure class=\"wp-block-embed aligncenter is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio\"><div class=\"wp-block-embed__wrapper\">\n<iframe title=\"Hacker Way: Rethinking Web App Development at Facebook\" width=\"500\" height=\"281\" src=\"https:\/\/www.youtube.com\/embed\/nYkdrAPrdcw?list=PLb0IAmt7-GS188xDYE-u1ShQmFFGbrk0v\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" referrerpolicy=\"strict-origin-when-cross-origin\" allowfullscreen><\/iframe>\n<\/div><\/figure>\n\n\n\n<p>Rdze\u0144 tego podej\u015bcia stanowi\u0105:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li><strong>niemutowalno\u015b\u0107 <\/strong>(ang. immutability) \u2013 wszelkie modyfikacje stanu powinny wi\u0105za\u0107 si\u0119 z utworzeniem nowego obiektu np. poprzez kopiowanie. Pozwala to aplikacji \u0142atwo wykry\u0107 zaistnia\u0142e zmiany i odpowiednio na nie zareagowa\u0107.<\/li><li><strong>jednokierunkowy przep\u0142yw danych<\/strong> (ang. unidirectional data flow) \u2013 dane mog\u0105 by\u0107 przekazywane tylko w jedn\u0105 stron\u0119, w d\u00f3\u0142 drzewa komponent\u00f3w. Zapewnia to wi\u0119ksz\u0105 przewidywalno\u015b\u0107 zachowania aplikacji, co dodatkowo wp\u0142ywa na \u0142atwo\u015b\u0107 w rozwi\u0105zywaniu problem\u00f3w z kodem aplikacji.<\/li><\/ul>\n\n\n\n<p>System zarz\u0105dzania stanem w architekturze Flux opiera si\u0119 o nast\u0119puj\u0105ce konstrukcje:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li><strong>magazyn <\/strong>(ang. store) \u2013 najwa\u017cniejszy element ca\u0142ego systemu. To on jest jedynym \u017ar\u00f3d\u0142em prawdy o przechowywanych danych i to on nimi zarz\u0105dza. Aplikacja mo\u017ce posiada\u0107 wiele magazyn\u00f3w \u2013 z regu\u0142y odpowiadaj\u0105cych za poszczeg\u00f3lne cz\u0119\u015bci aplikacji np. UserStore itd. Po zinterpretowaniu akcji wys\u0142anej przez dispatcher, magazyn emituje zdarzenie zmiany do zasubskrybowanych widok\u00f3w.<\/li><li><strong>akcje <\/strong>\u2013 obiekty opisuj\u0105ce, jaka zmiana stanu ma zaj\u015b\u0107. Zazwyczaj zawieraj\u0105 typ oraz \u0142adunek (ang. payload). Akcje s\u0105 rodzajem zdarze\u0144, kt\u00f3re po dotarciu do magazynu informuj\u0105 go o tym, kt\u00f3r\u0105 czynno\u015b\u0107 powinien wykona\u0107.<\/li><li><strong>widoki <\/strong>(ang. views) \u2013 elementy interfejsu, kt\u00f3re mog\u0105 zasubskrybowa\u0107 si\u0119 do magazynu i dzi\u0119ki temu reagowa\u0107 na wyemitowane przez niego zmiany danych. Zazwyczaj dzieli si\u0119 je na widoki-kontenery (\u0142\u0105cz\u0105ce si\u0119 z magazynami) oraz widoki prezentacyjne, kt\u00f3re dzia\u0142aj\u0105 tylko na danych przekazanych do nich przez nadrz\u0119dne komponenty.<\/li><li><strong>dispatcher <\/strong>\u2013 pojedynczy obiekt odpowiedzialny za rozg\u0142aszanie akcji z widok\u00f3w do wszystkich zasubskrybowanych magazyn\u00f3w.<\/li><\/ul>\n\n\n\n<p>Dodatkowo, by u\u0142atwi\u0107 tworzenie i wysy\u0142anie akcji, przyj\u0119to, \u017ce dobr\u0105 praktyk\u0105 jest tworzenie tzw. kreator\u00f3w akcji (ang. <em>action creators<\/em>), czyli funkcji, kt\u00f3re zwracaj\u0105 odpowiednio przygotowane obiekty akcji, gotowe do przekazania dispatcherowi.<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-full\"><a href=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2023\/01\/flux.drawio.png\"><img decoding=\"async\" width=\"465\" height=\"281\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2023\/01\/flux.drawio.png\" alt=\"Schemat przep\u0142ywu danych w architekturze Flux\" class=\"wp-image-18126\" srcset=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2023\/01\/flux.drawio.png 465w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2023\/01\/flux.drawio-300x181.png 300w\" sizes=\"(max-width: 465px) 100vw, 465px\" \/><\/a><figcaption><em>Ryc. 1 Schemat przep\u0142ywu danych w architekturze Flux<\/em><\/figcaption><\/figure><\/div>\n\n\n\n<p>Mechanizm zmiany stanu przedstawia si\u0119 nast\u0119puj\u0105co:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>widok wysy\u0142a akcj\u0119 (utworzon\u0105 np. poprzez kreator akcji) do dispatchera,<\/li><li>dispatcher rozg\u0142asza akcj\u0119 do wszystkich zarejestrowanych magazyn\u00f3w,<\/li><li>magazyn, kt\u00f3ry implementuje otrzyman\u0105 akcj\u0119, przetwarza sw\u00f3j stan w odpowiedni spos\u00f3b i rozsy\u0142a t\u0119 zmian\u0119 do widok\u00f3w, kt\u00f3re si\u0119 do niego zasubskrybowa\u0142y,<\/li><li>widoki renderuj\u0105 lub w inny spos\u00f3b przetwarzaj\u0105 otrzymane dane.<\/li><\/ul>\n\n\n\n<p>Takie podej\u015bcie umo\u017cliwia <strong>kontrolowalne i modularne podej\u015bcie do zarz\u0105dzania danymi<\/strong>, kt\u00f3re pozwala odseparowa\u0107 dane i logik\u0119 poszczeg\u00f3lnych domen aplikacji. Dodatkowo, centralnie sterowany mechanizm daje sposobno\u015b\u0107, aby w \u0142atwy spos\u00f3b zadba\u0107 o reaktywno\u015b\u0107 przep\u0142ywu danych.<\/p>\n\n\n\n<p>Flux zapewnia jednokierunkowy przep\u0142yw danych poprzez u\u017cycie globalnego systemu zarz\u0105dzania wiadomo\u015bciami, co wi\u0105\u017ce si\u0119 z przewidywalno\u015bci\u0105 wykonania kodu i w rezultacie przek\u0142ada si\u0119 na \u0142atwo\u015b\u0107 w pisaniu i utrzymaniu aplikacji. Komponenty, dzi\u0119ki oparciu si\u0119 o dane z magazynu, nie musz\u0105 ju\u017c subskrybowa\u0107 si\u0119 do konkretnych zdarze\u0144 wysy\u0142anych przez inne komponenty. Ich zadaniem jest od teraz tylko i wy\u0142\u0105cznie interpretacja zmian danych dostarczonych przez magazyn i wykonywanie odpowiedniej logiki.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Potencjalne problemy<\/strong><\/h2>\n\n\n\n<p>Niestety, Flux posiada tak\u017ce wady. Najwi\u0119ksz\u0105 z nich jest <strong>poziom skomplikowania takiej architektury<\/strong>, a co za tym idzie \u2013 trudno\u015b\u0107 w jej opanowaniu. Jednocze\u015bnie, z\u0142e jej u\u017cycie mo\u017ce jeszcze bardziej zagmatwa\u0107 kod i utrudni\u0107 naprawianie problem\u00f3w. Bardzo \u0142atwo spotka\u0107 kod, kt\u00f3ry \u017ale lub nadmiernie wykorzystuje architektur\u0119 Flux.<\/p>\n\n\n\n<p>Dodatkowo, z regu\u0142y implementacja tej architektury, korzystaj\u0105c z jednego z wielu istniej\u0105cych framework\u00f3w, <strong>wymaga masy czasu i pracy<\/strong>. Cz\u0119sto dla jednej funkcjonalno\u015bci nale\u017cy napisa\u0107 mn\u00f3stwo linii kodu, by obs\u0142u\u017cy\u0107 nawet najprostsz\u0105 interakcj\u0119 z magazynami.<\/p>\n\n\n\n<p>Flux nie jest z\u0142otym \u015brodkiem w aplikacjach webowych i <strong>nie zawsze jest konieczny<\/strong>. O ile samo to podej\u015bcie \u201enaprawi\u0142o\u201d \u015bwiat aplikacji webowych, tak w wi\u0119kszo\u015bci przypadk\u00f3w nie jest wymagane. Na wzorcu tym skorzystaj\u0105 g\u0142\u00f3wnie du\u017ce projekty, kt\u00f3rych domeny krzy\u017cuj\u0105 si\u0119 w wielu komponentach i pr\u00f3ba przekazywania do nich danych domenowych w tradycyjny spos\u00f3b zako\u0144czy\u0142aby si\u0119 ostatecznie katastrof\u0105.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Implementacje<\/strong><\/h2>\n\n\n\n<p>Sam Flux ko\u0144czy nied\u0142ugo 10 lat. Nic wi\u0119c dziwnego, \u017ce powsta\u0142o wiele niezale\u017cnych implementacji, kt\u00f3re bazuj\u0105 i cz\u0119sto rozwijaj\u0105 koncepcje opisane powy\u017cej. Najpopularniejsze z nich to:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li><strong>Redux <\/strong>\u2013 wed\u0142ug niekt\u00f3rych wzorcowa implementacja Fluxa, u\u017cywana przewa\u017cnie w tandemie z Reactem przy u\u017cyciu wrappera react-redux.<\/li><li><strong>NgRx <\/strong>\u2013 w wielu przypadkach uwa\u017cana za standard w aplikacjach tworzonych w Angularze. Cech\u0105 charakterystyczn\u0105 jest wykorzystanie RxJS i tzw. reaktywnych rozszerze\u0144 do kontroli zmian stanu.<\/li><li><strong>Pinia <\/strong>\u2013 oficjalnie polecana przez tw\u00f3rc\u00f3w Vue implementacja architektury Flux dla tego frameworka.<\/li><\/ul>\n\n\n\n<p>Innych implementacji jest mn\u00f3stwo, a kolejne lata przynios\u0105 pewnie ich jeszcze wi\u0119cej.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Podsumowanie<\/strong><\/h2>\n\n\n\n<p>Koncepcja architektury Flux odmieni\u0142a front-end i dzi\u0119ki swoim zaletom na pewno zostanie z nami na d\u0142ugo. Tylko czas poka\u017ce, czy za kilka lat kolejny uporczywy b\u0142\u0105d w jakim\u015b popularnym serwisie przyniesie drug\u0105 tak\u0105 rewolucj\u0119.<\/p>\n\n\n\n<p>***<\/p>\n\n\n\n<p>Je\u015bli interesuj\u0105 Ci\u0119 inne artyku\u0142y napisane przez ekspert\u00f3w z Centrum Kompetencyjnego Digital, poleci\u0107 mo\u017cemy m.in.: <a href=\"https:\/\/sii.pl\/blog\/more-reactive-angular\/?category=development-na-miekko&amp;tag=api,c,observable-streams,reactive-extensions,software-development\" target=\"_blank\" aria-label=\" (opens in a new tab)\" rel=\"noreferrer noopener\" class=\"ek-link\">More reactive Angular<\/a>, <a href=\"https:\/\/sii.pl\/blog\/podejscie-do-refaktoryzacji-w-projekcie-ze-starymi-technologiami\/?category=development-na-miekko&amp;tag=architektura-it,legacy-code,refaktoryzacja\" target=\"_blank\" aria-label=\" (opens in a new tab)\" rel=\"noreferrer noopener\" class=\"ek-link\">Podej\u015bcie do refaktoryzacji w projekcie ze starymi technologiami,<\/a> <a href=\"https:\/\/sii.pl\/blog\/net-i-raspberry-pi-mozliwosci-wykorzystania-platformy-na-mikrokomputerach\/?category=development-na-twardo&amp;tag=net,iot,raspberry-pi\" target=\"_blank\" aria-label=\" (opens in a new tab)\" rel=\"noreferrer noopener\" class=\"ek-link\">.NET i Raspberry Pi \u2013 mo\u017cliwo\u015bci wykorzystania platformy na mikrokomputerach,<\/a> &nbsp;<a href=\"https:\/\/sii.pl\/blog\/local-variable-type-inference-var-w-java-10\/?category=development-na-twardo&amp;tag=dobre-praktyki,java,var\" target=\"_blank\" aria-label=\" (opens in a new tab)\" rel=\"noreferrer noopener\" class=\"ek-link\">Local Variable Type Inference (var) w Java 10<\/a> oraz <a href=\"https:\/\/sii.pl\/blog\/collection-interface-co-warto-wiedziec\/?category=development-na-twardo&amp;tag=centrum-kompetencyjne-digital,collection-interface,java\" target=\"_blank\" aria-label=\" (opens in a new tab)\" rel=\"noreferrer noopener\" class=\"ek-link\">Collection interface \u2013 co warto wiedzie\u0107?<\/a><\/p>\n\n\n<div class=\"kk-star-ratings kksr-auto kksr-align-left kksr-valign-bottom\"\n    data-payload='{&quot;align&quot;:&quot;left&quot;,&quot;id&quot;:&quot;18124&quot;,&quot;slug&quot;:&quot;default&quot;,&quot;valign&quot;:&quot;bottom&quot;,&quot;ignore&quot;:&quot;&quot;,&quot;reference&quot;:&quot;auto&quot;,&quot;class&quot;:&quot;&quot;,&quot;count&quot;:&quot;3&quot;,&quot;legendonly&quot;:&quot;&quot;,&quot;readonly&quot;:&quot;&quot;,&quot;score&quot;:&quot;5&quot;,&quot;starsonly&quot;:&quot;&quot;,&quot;best&quot;:&quot;5&quot;,&quot;gap&quot;:&quot;11&quot;,&quot;greet&quot;:&quot;&quot;,&quot;legend&quot;:&quot;5\\\/5 ( votes: 3)&quot;,&quot;size&quot;:&quot;18&quot;,&quot;title&quot;:&quot;Flux \u2013 architektura zarz\u0105dzania stanem w aplikacjach webowych&quot;,&quot;width&quot;:&quot;139.5&quot;,&quot;_legend&quot;:&quot;{score}\\\/{best} ( {votes}: {count})&quot;,&quot;font_factor&quot;:&quot;1.25&quot;}'>\n            \n<div class=\"kksr-stars\">\n    \n<div class=\"kksr-stars-inactive\">\n            <div class=\"kksr-star\" data-star=\"1\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"2\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"3\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"4\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"5\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n    <\/div>\n    \n<div class=\"kksr-stars-active\" style=\"width: 139.5px;\">\n            <div class=\"kksr-star\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n    <\/div>\n<\/div>\n                \n\n<div class=\"kksr-legend\" style=\"font-size: 14.4px;\">\n            5\/5 ( votes: 3)    <\/div>\n    <\/div>\n","protected":false},"excerpt":{"rendered":"<p>Podczas tworzenia aplikacji webowych du\u017c\u0105 rol\u0119 odgrywa przep\u0142yw danych. Istnieje kilka podej\u015b\u0107 maj\u0105cych go umo\u017cliwi\u0107 i u\u0142atwi\u0107. Jednym z pierwszych &hellip; <a class=\"continued-btn\" href=\"https:\/\/sii.pl\/blog\/flux-architektura-zarzadzania-stanem-w-aplikacjach-webowych\/\">Continued<\/a><\/p>\n","protected":false},"author":454,"featured_media":19655,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"_editorskit_title_hidden":false,"_editorskit_reading_time":4,"_editorskit_is_block_options_detached":false,"_editorskit_block_options_position":"{}","inline_featured_image":false,"footnotes":""},"categories":[1316],"tags":[2427,1591,1554,1546],"class_list":["post-18124","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-development-na-miekko","tag-digital","tag-flux","tag-zalety-i-wady","tag-przeglad-narzedzi"],"acf":[],"aioseo_notices":[],"republish_history":[],"featured_media_url":"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2023\/01\/Flux-\u2013-architektura-zarzadzania-stanem-w-aplikacjach-webowych-1.jpg","category_names":["Development na mi\u0119kko"],"_links":{"self":[{"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/posts\/18124"}],"collection":[{"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/users\/454"}],"replies":[{"embeddable":true,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/comments?post=18124"}],"version-history":[{"count":3,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/posts\/18124\/revisions"}],"predecessor-version":[{"id":18466,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/posts\/18124\/revisions\/18466"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/media\/19655"}],"wp:attachment":[{"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/media?parent=18124"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/categories?post=18124"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/tags?post=18124"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}