{"id":490,"date":"2010-06-05T14:10:21","date_gmt":"2010-06-05T13:10:21","guid":{"rendered":"http:\/\/www.streppone.it\/cosimo\/blog\/2010\/06\/disassembling-a-real-world-plack-psgi-application\/"},"modified":"2010-06-05T14:10:21","modified_gmt":"2010-06-05T13:10:21","slug":"disassembling-a-real-world-plack-psgi-application","status":"publish","type":"post","link":"https:\/\/www.streppone.it\/cosimo\/blog\/2010\/06\/disassembling-a-real-world-plack-psgi-application\/","title":{"rendered":"Disassembling a real world Plack PSGI application"},"content":{"rendered":"<p><span class='imgright'><img alt='' src='http:\/\/files.myopera.com\/cstrep\/blog\/neomatrix.jpg' \/><\/span><\/p>\n<p>After I <a href=\"http:\/\/my.opera.com\/cstrep\/blog\/2010\/05\/27\/plack-the-grand-glue\" rel=\"nofollow\">started playing with Plack<\/a>, I tried to evaluate whether to continue using it for our <b>mission-critical production stuff<\/b> or give up, going back to the same techniques we already use (successfully).<\/p>\n<p>I think it&#39;s time to develop and deploy a Plack based application. In my grand plan, :-), I&#39;d like to deploy <a href=\"http:\/\/github.com\/yappo\/nginx-psgi-patchs\" rel=\"nofollow\">nginx with PSGI support<\/a>, or even more ambitiously, nginx or apache with <b><a href=\"http:\/\/search.cpan.org\/~miyagawa\/Starman-0.2004\/lib\/Starman.pm\" rel=\"nofollow\">Starman<\/a> as &quot;backend&quot; http server<\/b>. We&#39;ll see&#8230;<\/p>\n<p>In the meantime, I&#39;d like to write here a couple of niceties about Plack and Starman, showing some real code I wrote when I started.<\/p>\n<h2>A real world PSGI application<\/h2>\n<p>Here&#39;s a sample PSGI application currently under development:<\/p>\n<pre>\r\n#!\/usr\/bin\/env perl\r\n#\r\n# Sample PSGI application\r\n#\r\n\r\nuse strict;\r\n#se warnings;\r\nuse constant ENVIRONMENT         =&gt; &#39;development&#39;;\r\nuse constant APACHE_DEPLOYMENT   =&gt; (ENVIRONMENT eq &#39;production&#39;);\r\nuse constant ENABLE_ACCESS_LOG   =&gt; (ENVIRONMENT eq &#39;development&#39;);\r\nuse constant ENABLE_DEBUG_PANELS =&gt; (ENVIRONMENT eq &#39;development&#39;);\r\n\r\nuse Plack::Builder;\r\nuse AuthOpera;\r\nuse AuthOpera::Account;\r\n\r\nmy $app = AuthOpera::Account-&gt;new(); \r\n\r\nbuilder {\r\n\r\n    enable_if { not APACHE_DEPLOYMENT }\r\n        &#39;Plack::Middleware::Static&#39;, \r\n        path =&gt; qr{^\/(bitmaps\/|images\/|js\/|css\/|downtime\/|favicon.ico$|ping.html$)},\r\n        root =&gt; &#39;..&#39;,\r\n        ;\r\n\r\n    mount &quot;\/account&quot; =&gt; builder {\r\n\r\n        enable_if { ENABLE_DEBUG_PANELS } &#39;StackTrace&#39;;\r\n        enable_if { ENABLE_DEBUG_PANELS } &#39;Debug&#39;;   # panels =&gt; [ qw(DBITrace Memory) ];\r\n        enable_if { ENABLE_DEBUG_PANELS } &#39;Lint&#39;;\r\n        enable_if { ENABLE_DEBUG_PANELS } &#39;Runtime&#39;;\r\n        enable_if { ENABLE_ACCESS_LOG   } &#39;AccessLog&#39;;\r\n\r\n        $app;\r\n\r\n    }\r\n\r\n}\r\n<\/pre>\n<p>Of course, the main application code is not here, but in the <code>AuthOpera::Account<\/code> class. That&#39;s not really relevant to what we&#39;re discussing here. Let&#39;s just say that any class, to be a valid and complete PSGI application, has to:<\/p>\n<ul>\n<li>subclass from <a href=\"http:\/\/search.cpan.org\/~miyagawa\/Plack-0.9938\/lib\/Plack\/Component.pm\" rel=\"nofollow\">Plack::Component<\/a><\/li>\n<li>have a <code>call()<\/code> method<\/li>\n<li>the <code>call()<\/code> method must return a valid PSGI response. Example:\n<pre>\r\npackage MyPSGIApp;\r\n\r\nuse strict;\r\nuse Data:: Dumper ();\r\nuse parent &#39;Plack::Component&#39;;\r\n\r\nsub call {\r\n    # $env is the full PSGI environment\r\n    my ($self, $env) = @_;\r\n\r\n    return [\r\n\r\n        # HTTP Status code\r\n        200,\r\n\r\n        # HTTP headers as arrayref\r\n        [ &#39;Content-type&#39; =&gt; &#39;text\/html&#39; ],\r\n\r\n        # Response body as array ref\r\n        [ &#39;&lt;!DOCTYPE html&gt;&#39;,\r\n          &#39;&lt;body&gt;&lt;h1&gt;Hello world&lt;\/h1&gt;&lt;pre&gt;&#39;,\r\n          Data:: Dumper:: Dumper($env),\r\n          &#39;&lt;\/pre&gt;&lt;\/body&gt;&lt;\/html&gt;&#39;,\r\n        ],\r\n    ];\r\n}\r\n\r\n1;\r\n<\/pre>\n<\/li>\n<\/ul>\n<p>That&#39;s it, <b>this is a full PSGI application<\/b> that does dump all its PSGI environment.<\/p>\n<p>Of course in a real example, you probably want a template engine to return the page content, etc&#8230; That&#39;s what we are building for our applications. Actually just assembling the components we already have developed during these years, so we have template classes, config classes, localization, database access, etc&#8230;<\/p>\n<p>So we&#39;re <b>basically just gluing these ready made components inside the PSGI application<\/b>, and then using them. I don&#39;t think this is particularly original, but it allows us to quickly &quot;port&quot; our code to PSGI and thus run anywhere we want to.\n<\/p>\n<h2><code>app.psgi<\/code> in detail<\/h2>\n<p>Now, let&#39;s see the PSGI app in more detail.<\/p>\n<pre>\r\nuse constant ENVIRONMENT         =&gt; &#39;development&#39;;\r\nuse constant APACHE_DEPLOYMENT   =&gt; (ENVIRONMENT eq &#39;production&#39;);\r\nuse constant ENABLE_ACCESS_LOG   =&gt; (ENVIRONMENT eq &#39;development&#39;);\r\nuse constant ENABLE_DEBUG_PANELS =&gt; (ENVIRONMENT eq &#39;development&#39;);\r\n<\/pre>\n<p>These constants are used to turn on and off certain features mentioned later in the <code>builder {}<\/code> block. I just found out the other day that <b>these constants are near to useless<\/b>. That is because <code>plackup<\/code> and <code>starman<\/code> already provide a <code>-E environment<\/code> switch. If you start your application with:<\/p>\n<pre>starman -E development myapp.psgi     # same with plackup, the default server<\/pre>\n<p>then Plack will <b>by default enable the debugging panels and the Apache-style access log<\/b>. I found out about this after having written that file. This means that the following <code>enable_if<\/code>s are <b>unnecessary<\/b>:<\/p>\n<pre>mount &quot;\/myroot&quot; =&gt; builder {\r\n    enable_if { ENABLE_DEBUG_PANELS } &#39;StackTrace&#39;;\r\n    enable_if { ENABLE_DEBUG_PANELS } &#39;Debug&#39;;   # panels =&gt; [ qw(DBITrace Memory) ];\r\n    enable_if { ENABLE_DEBUG_PANELS } &#39;Lint&#39;;\r\n    enable_if { ENABLE_DEBUG_PANELS } &#39;Runtime&#39;;\r\n    enable_if { ENABLE_ACCESS_LOG   } &#39;AccessLog&#39;;\r\n    $app;\r\n}<\/pre>\n<p>I think Plack enables by default at least <code>StackTrace<\/code>, <code>Debug<\/code>, and <code>AccessLog<\/code>. In my case, however, I&#39;m also enabling <code>RunTime<\/code> and <code>Lint<\/code>. But more importantly, I need to differentiate between Apache deployment and Starman deployment. That affects the way static files are served.<\/p>\n<p>When deploying under Apache, I don&#39;t need the following:<\/p>\n<pre>\r\nenable_if { not APACHE_DEPLOYMENT }\r\n    &#39;Plack::Middleware::Static&#39;,\r\n    path =&gt; qr{^\/(bitmaps\/|images\/|js\/|css\/|downtime\/|favicon.ico$|ping.html$)},\r\n    root =&gt; &#39;..&#39;;\r\n<\/pre>\n<p>because my PSGI application is enabled in an Apache &lt;Location&gt; block, as in:<\/p>\n<pre>\r\n&lt;Location \/myroot\/&gt;\r\n    SetHandler perl-script\r\n    PerlResponseHandler Plack::Handler::Apache2\r\n    PerlSetVar psgi_app \/my\/path\/to\/app.psgi\r\n&lt;\/Location&gt;\r\n<\/pre>\n<p>So Apache already takes care of serving the static files for me. However, when running completely under Starman, I need to tell it which folders or paths need to be served as static files, and where they are located. This is the purpose of the <a href=\"http:\/\/search.cpan.org\/~miyagawa\/Plack-0.9938\/lib\/Plack\/Middleware\/Static.pm\" rel=\"nofollow\">Static middleware<\/a>:<\/p>\n<pre>enable_if { not APACHE_DEPLOYMENT } &#39;Plack::Middleware::Static&#39;,\r\n    path =&gt; qr{^\/(images\/|js\/|css\/|favicon.ico$)},\r\n    root =&gt; &#39;\/var\/www\/something&#39;;\r\n<\/pre>\n<p>If you&#39;re always deploying through plackup or starman, then, again, you don&#39;t need any <code>enable_if<\/code>, just <code>enable<\/code>. Maybe it&#39;s also a good idea to put everything under <code>\/static<\/code>. For me that wasn&#39;t possible, since I already had existing content:<\/p>\n<pre>enable &#39;Plack::Middleware::Static&#39;,\r\n    path =&gt; qr{^\/static\/},\r\n    root =&gt; &#39;\/var\/www\/something&#39;;\r\n<\/pre>\n<h2><code>Plack::Builder<\/code><\/h2>\n<p>About the <code>Plack::Builder<\/code> bit, and the related <code>builder<\/code> function. That is a function that helps you specify what you want Plack to run and how. Example:<\/p>\n<pre>builder {\r\n    enable &#39;StackTrace&#39;;\r\n    enable &#39;Debug&#39;;\r\n    enable &#39;AccessLog&#39;;\r\n    $app\r\n}<\/pre>\n<p>where <b>StackTrace<\/b>, <b>Debug<\/b>, and <b>AccessLog<\/b> are all <b>middleware<\/b> classes, so causes Plack to wrap your final <code>$app<\/code> application first with the AccessLog middleware, then Debug and then StackTrace. I didn&#39;t check the code, but I believe this creates 3 different PSGI applications that are meant to fiddle with the response that your own application generates.<\/p>\n<p>PSGI makes this possible, and it&#39;s just great. <b>More middleware means easier and faster development. And ultimately, very good middleware makes for great reuse too.<\/b><\/p>\n<h2>The <code>mount<\/code> wrapper<\/h2>\n<p>I used <code>mount<\/code> in my example very basicly, but you can use <code>mount<\/code> to assemble compounds of applications in a very simple way. The same thing you do, for example, with <a href=\"http:\/\/www.djangoproject.com\" rel=\"nofollow\">Django<\/a> and <code>urls.py<\/code>, except that, if you have seen a non-trivial urls.py, it looks like spaghetti after a while. Compare with this:<\/p>\n<pre>\r\nmy $app1 = MyApp-&gt;new();\r\nmy $app2 = MyApp2-&gt;new();\r\n#...\r\n\r\nbuilder {\r\n\r\n    enable &#39;Plack::Middleware::Static&#39;, \r\n        path =&gt; qr{^\/static\/},\r\n        root =&gt; &#39;\/var\/www\/something&#39;;\r\n\r\n    mount &quot;\/path1&quot; =&gt; builder {\r\n        enable &#39;StackTrace&#39;;\r\n        $app;\r\n    }\r\n\r\n    mount &quot;\/path2&quot; =&gt; $app2;\r\n\r\n    mount &quot;\/path3&quot; =&gt; builder {\r\n        enable &#39;SomeMiddleware&#39;;\r\n        $app3;\r\n    }\r\n\r\n}\r\n<\/pre>\n<p>Of course, then you have to add some dispatcher logic to your applications, but in the Plack world, <a href=\"http:\/\/github.com\/miyagawa\/plack-dispatching-samples\" rel=\"nofollow\">we don&#39;t lack good dispatchers<\/a>.<\/p>\n<p>Plack rocks.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>After I started playing with Plack, I tried to evaluate whether to continue using it for our mission-critical production stuff or give up, going back to the same techniques we already use (successfully). I think it&#39;s time to develop and deploy a Plack based application. In my grand plan, :-), I&#39;d like to deploy nginx [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[259,49,91,427,50,293,229,230,48],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v22.9 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Disassembling a real world Plack PSGI application - Random hacking<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.streppone.it\/cosimo\/blog\/2010\/06\/disassembling-a-real-world-plack-psgi-application\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Disassembling a real world Plack PSGI application - Random hacking\" \/>\n<meta property=\"og:description\" content=\"After I started playing with Plack, I tried to evaluate whether to continue using it for our mission-critical production stuff or give up, going back to the same techniques we already use (successfully). I think it&#039;s time to develop and deploy a Plack based application. In my grand plan, :-), I&#039;d like to deploy nginx [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.streppone.it\/cosimo\/blog\/2010\/06\/disassembling-a-real-world-plack-psgi-application\/\" \/>\n<meta property=\"og:site_name\" content=\"Random hacking\" \/>\n<meta property=\"article:published_time\" content=\"2010-06-05T13:10:21+00:00\" \/>\n<meta property=\"og:image\" content=\"http:\/\/files.myopera.com\/cstrep\/blog\/neomatrix.jpg\" \/>\n<meta name=\"author\" content=\"cosimo\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"cosimo\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"6 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/www.streppone.it\/cosimo\/blog\/2010\/06\/disassembling-a-real-world-plack-psgi-application\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/www.streppone.it\/cosimo\/blog\/2010\/06\/disassembling-a-real-world-plack-psgi-application\/\"},\"author\":{\"name\":\"cosimo\",\"@id\":\"https:\/\/www.streppone.it\/cosimo\/blog\/#\/schema\/person\/c443bedbf6ecf99550d6395620801df1\"},\"headline\":\"Disassembling a real world Plack PSGI application\",\"datePublished\":\"2010-06-05T13:10:21+00:00\",\"dateModified\":\"2010-06-05T13:10:21+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/www.streppone.it\/cosimo\/blog\/2010\/06\/disassembling-a-real-world-plack-psgi-application\/\"},\"wordCount\":716,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/www.streppone.it\/cosimo\/blog\/#\/schema\/person\/c443bedbf6ecf99550d6395620801df1\"},\"image\":{\"@id\":\"https:\/\/www.streppone.it\/cosimo\/blog\/2010\/06\/disassembling-a-real-world-plack-psgi-application\/#primaryimage\"},\"thumbnailUrl\":\"http:\/\/files.myopera.com\/cstrep\/blog\/neomatrix.jpg\",\"keywords\":[\"apache\",\"cpan\",\"development\",\"nginx\",\"perl\",\"plack\",\"PSGI\",\"starman\",\"web\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/www.streppone.it\/cosimo\/blog\/2010\/06\/disassembling-a-real-world-plack-psgi-application\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.streppone.it\/cosimo\/blog\/2010\/06\/disassembling-a-real-world-plack-psgi-application\/\",\"url\":\"https:\/\/www.streppone.it\/cosimo\/blog\/2010\/06\/disassembling-a-real-world-plack-psgi-application\/\",\"name\":\"Disassembling a real world Plack PSGI application - Random hacking\",\"isPartOf\":{\"@id\":\"https:\/\/www.streppone.it\/cosimo\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/www.streppone.it\/cosimo\/blog\/2010\/06\/disassembling-a-real-world-plack-psgi-application\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/www.streppone.it\/cosimo\/blog\/2010\/06\/disassembling-a-real-world-plack-psgi-application\/#primaryimage\"},\"thumbnailUrl\":\"http:\/\/files.myopera.com\/cstrep\/blog\/neomatrix.jpg\",\"datePublished\":\"2010-06-05T13:10:21+00:00\",\"dateModified\":\"2010-06-05T13:10:21+00:00\",\"breadcrumb\":{\"@id\":\"https:\/\/www.streppone.it\/cosimo\/blog\/2010\/06\/disassembling-a-real-world-plack-psgi-application\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.streppone.it\/cosimo\/blog\/2010\/06\/disassembling-a-real-world-plack-psgi-application\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.streppone.it\/cosimo\/blog\/2010\/06\/disassembling-a-real-world-plack-psgi-application\/#primaryimage\",\"url\":\"http:\/\/files.myopera.com\/cstrep\/blog\/neomatrix.jpg\",\"contentUrl\":\"http:\/\/files.myopera.com\/cstrep\/blog\/neomatrix.jpg\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.streppone.it\/cosimo\/blog\/2010\/06\/disassembling-a-real-world-plack-psgi-application\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.streppone.it\/cosimo\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Disassembling a real world Plack PSGI application\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.streppone.it\/cosimo\/blog\/#website\",\"url\":\"https:\/\/www.streppone.it\/cosimo\/blog\/\",\"name\":\"Random hacking\",\"description\":\"Assume nothing. Code defensively. Keep it simple, stupid!\",\"publisher\":{\"@id\":\"https:\/\/www.streppone.it\/cosimo\/blog\/#\/schema\/person\/c443bedbf6ecf99550d6395620801df1\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/www.streppone.it\/cosimo\/blog\/?s={search_term_string}\"},\"query-input\":\"required name=search_term_string\"}],\"inLanguage\":\"en-US\"},{\"@type\":[\"Person\",\"Organization\"],\"@id\":\"https:\/\/www.streppone.it\/cosimo\/blog\/#\/schema\/person\/c443bedbf6ecf99550d6395620801df1\",\"name\":\"cosimo\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.streppone.it\/cosimo\/blog\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/cb1d938720df45a2720724aae99e3bfc?s=96&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/cb1d938720df45a2720724aae99e3bfc?s=96&r=g\",\"caption\":\"cosimo\"},\"logo\":{\"@id\":\"https:\/\/www.streppone.it\/cosimo\/blog\/#\/schema\/person\/image\/\"},\"url\":\"https:\/\/www.streppone.it\/cosimo\/blog\/author\/cosimo\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Disassembling a real world Plack PSGI application - Random hacking","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.streppone.it\/cosimo\/blog\/2010\/06\/disassembling-a-real-world-plack-psgi-application\/","og_locale":"en_US","og_type":"article","og_title":"Disassembling a real world Plack PSGI application - Random hacking","og_description":"After I started playing with Plack, I tried to evaluate whether to continue using it for our mission-critical production stuff or give up, going back to the same techniques we already use (successfully). I think it&#39;s time to develop and deploy a Plack based application. In my grand plan, :-), I&#39;d like to deploy nginx [&hellip;]","og_url":"https:\/\/www.streppone.it\/cosimo\/blog\/2010\/06\/disassembling-a-real-world-plack-psgi-application\/","og_site_name":"Random hacking","article_published_time":"2010-06-05T13:10:21+00:00","og_image":[{"url":"http:\/\/files.myopera.com\/cstrep\/blog\/neomatrix.jpg"}],"author":"cosimo","twitter_card":"summary_large_image","twitter_misc":{"Written by":"cosimo","Est. reading time":"6 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.streppone.it\/cosimo\/blog\/2010\/06\/disassembling-a-real-world-plack-psgi-application\/#article","isPartOf":{"@id":"https:\/\/www.streppone.it\/cosimo\/blog\/2010\/06\/disassembling-a-real-world-plack-psgi-application\/"},"author":{"name":"cosimo","@id":"https:\/\/www.streppone.it\/cosimo\/blog\/#\/schema\/person\/c443bedbf6ecf99550d6395620801df1"},"headline":"Disassembling a real world Plack PSGI application","datePublished":"2010-06-05T13:10:21+00:00","dateModified":"2010-06-05T13:10:21+00:00","mainEntityOfPage":{"@id":"https:\/\/www.streppone.it\/cosimo\/blog\/2010\/06\/disassembling-a-real-world-plack-psgi-application\/"},"wordCount":716,"commentCount":0,"publisher":{"@id":"https:\/\/www.streppone.it\/cosimo\/blog\/#\/schema\/person\/c443bedbf6ecf99550d6395620801df1"},"image":{"@id":"https:\/\/www.streppone.it\/cosimo\/blog\/2010\/06\/disassembling-a-real-world-plack-psgi-application\/#primaryimage"},"thumbnailUrl":"http:\/\/files.myopera.com\/cstrep\/blog\/neomatrix.jpg","keywords":["apache","cpan","development","nginx","perl","plack","PSGI","starman","web"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.streppone.it\/cosimo\/blog\/2010\/06\/disassembling-a-real-world-plack-psgi-application\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.streppone.it\/cosimo\/blog\/2010\/06\/disassembling-a-real-world-plack-psgi-application\/","url":"https:\/\/www.streppone.it\/cosimo\/blog\/2010\/06\/disassembling-a-real-world-plack-psgi-application\/","name":"Disassembling a real world Plack PSGI application - Random hacking","isPartOf":{"@id":"https:\/\/www.streppone.it\/cosimo\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.streppone.it\/cosimo\/blog\/2010\/06\/disassembling-a-real-world-plack-psgi-application\/#primaryimage"},"image":{"@id":"https:\/\/www.streppone.it\/cosimo\/blog\/2010\/06\/disassembling-a-real-world-plack-psgi-application\/#primaryimage"},"thumbnailUrl":"http:\/\/files.myopera.com\/cstrep\/blog\/neomatrix.jpg","datePublished":"2010-06-05T13:10:21+00:00","dateModified":"2010-06-05T13:10:21+00:00","breadcrumb":{"@id":"https:\/\/www.streppone.it\/cosimo\/blog\/2010\/06\/disassembling-a-real-world-plack-psgi-application\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.streppone.it\/cosimo\/blog\/2010\/06\/disassembling-a-real-world-plack-psgi-application\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.streppone.it\/cosimo\/blog\/2010\/06\/disassembling-a-real-world-plack-psgi-application\/#primaryimage","url":"http:\/\/files.myopera.com\/cstrep\/blog\/neomatrix.jpg","contentUrl":"http:\/\/files.myopera.com\/cstrep\/blog\/neomatrix.jpg"},{"@type":"BreadcrumbList","@id":"https:\/\/www.streppone.it\/cosimo\/blog\/2010\/06\/disassembling-a-real-world-plack-psgi-application\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.streppone.it\/cosimo\/blog\/"},{"@type":"ListItem","position":2,"name":"Disassembling a real world Plack PSGI application"}]},{"@type":"WebSite","@id":"https:\/\/www.streppone.it\/cosimo\/blog\/#website","url":"https:\/\/www.streppone.it\/cosimo\/blog\/","name":"Random hacking","description":"Assume nothing. Code defensively. Keep it simple, stupid!","publisher":{"@id":"https:\/\/www.streppone.it\/cosimo\/blog\/#\/schema\/person\/c443bedbf6ecf99550d6395620801df1"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.streppone.it\/cosimo\/blog\/?s={search_term_string}"},"query-input":"required name=search_term_string"}],"inLanguage":"en-US"},{"@type":["Person","Organization"],"@id":"https:\/\/www.streppone.it\/cosimo\/blog\/#\/schema\/person\/c443bedbf6ecf99550d6395620801df1","name":"cosimo","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.streppone.it\/cosimo\/blog\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/cb1d938720df45a2720724aae99e3bfc?s=96&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/cb1d938720df45a2720724aae99e3bfc?s=96&r=g","caption":"cosimo"},"logo":{"@id":"https:\/\/www.streppone.it\/cosimo\/blog\/#\/schema\/person\/image\/"},"url":"https:\/\/www.streppone.it\/cosimo\/blog\/author\/cosimo\/"}]}},"_links":{"self":[{"href":"https:\/\/www.streppone.it\/cosimo\/blog\/wp-json\/wp\/v2\/posts\/490"}],"collection":[{"href":"https:\/\/www.streppone.it\/cosimo\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.streppone.it\/cosimo\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.streppone.it\/cosimo\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.streppone.it\/cosimo\/blog\/wp-json\/wp\/v2\/comments?post=490"}],"version-history":[{"count":0,"href":"https:\/\/www.streppone.it\/cosimo\/blog\/wp-json\/wp\/v2\/posts\/490\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.streppone.it\/cosimo\/blog\/wp-json\/wp\/v2\/media?parent=490"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.streppone.it\/cosimo\/blog\/wp-json\/wp\/v2\/categories?post=490"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.streppone.it\/cosimo\/blog\/wp-json\/wp\/v2\/tags?post=490"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}