Henry Van Styn
<vanstyn@cpan.org>
The Perl Conference 2017
June 20, Washington, DC
www.rapidapp.info
rapi.io/blog
irc.perl.org - #rapidapp
Rapi::Blogmaximalist control, minimalist effort
@vanstyn
slides: rapi.io/tpc2017
About me
• Henry Van Styn (@vanstyn)
• Owner of IntelliTree Solutions, perl shop and consultancy
• Author/maintainer of RapidApp
• Catalyst and DBIx::Class contributor
• Given talks/demos of RapidApp for the past several years at The Perl
Conference
• This year I wanted to give a RapidApp demo of a
bigger, real-world app that’s real-world useful
• Married this with solving another of my long-time
unmet needs:
A real, modern perl blog platform…
Why another blog platform?
• Many reasons, a better mousetrap…
• RapidApp is already very well-suited to the problem domain
Biggest reason:
Fresh take on front-end APIs
(i.e. “themes”)
The problem with “themes”
• The word itself implies restrictiveness
‣ changing the appearance of something that is already defined
• Inventing concepts of “pages” and “sections” and “blocks” and layouts and on
and on and on that you have to adhere to
• URL end-points are predetermined, rendered HTML assembled in domain-
specific manner
• Have to learn platform-specific APIs to even get to “Hello world”
• Integrating and adapting custom HTML can be difficult and frustrating,
especially when working with designers
Rapi::Blog’s approach:
• Term chosen to give more emphasis than “theme”
• Is an ordinary, native HTML website/structure first and handles its own
business as much as possible
• Lives at the root of the site like the HTML wants
‣ This is the main blocker elsewhere
• Supports “opportunistic” templates
‣ But can still be static HTML, and just work
• The backend exposes APIs the scaffold can use, however it wants
“scaffolds”
Backend / Model
Template API
Basic Architecture:
‣ Public website structure
‣ Native HTML, CSS,
JavaScript, Images, etc
‣ HTML can include
template directives ‣ Database of ‘Posts’
‣ Taxonomies
‣ Relationships
‣ Business Logic
‣ Permissions
‣ Expose Blog-specific
template directives/methods
Scaffold
directory
Advanced
CRUD
Interfaces
RapidApp
Lets see it in action
• Start with a running site, go through the public-facing functionality -
browsing posts, pages, search, etc
• Go through the password-protected features - creating/editing posts,
comments, the new markdown editor, basic administration
• Browse the scaffold config and the templates and how they work
• Show how to create new sites with the rabl.pl create script
- demo -
How it works
• Rapi::Blog is a subclass of RapidApp::Builder
• Plack/PSGI app with very simple options:
my $app = Rapi::Blog->new({
site_path => $dir,
scaffold_path => "$dir/scaffold"
});
# Plack/PSGI app:
$app->to_app
Options
• site_path
• directory where the site lives - used for data persistence
• database files are created automatically for fresh sites
• scaffold_path
• the “document root” for the site
• serves literal/real paths from “/”
• defaults to ‘scaffold/’ inside the site_path directory
Scaffold
• Ordinary directory served at the root of the site
✴ img/foo.png served as /img/foo.png, home.html served as /home.html, and so on
• Merge/overlay with the Catalyst/RapidApp controller/module namespaces
automagically
• With no configuration it is a simple static website/folder
• Any of the files can function as templates (TT) and call directives and
accessors provided by the API
• scaffold.yml config file tells the backend how to use it
✴ such as which template to use to display posts
The scaffold tells the backend what
to do, not the other way around.
scaffold.yml
static_paths : [ css/, js/, fonts/, img/ ]
private_paths : [ private/, scaffold.yml ]
default_ext : html
landing_page : recent_posts
not_found : private/404.html
view_wrappers:
- { path: post/, type: include, wrapper: private/post.html }
scaffold.yml
static_paths : [ css/, js/, fonts/, img/ ]
private_paths : [ private/, scaffold.yml ]
default_ext : html
landing_page : recent_posts
not_found : private/404.html
view_wrappers:
- { path: post/, type: include, wrapper: private/post.html }
* which paths are static-only (no template directives) - mainly for performance
scaffold.yml
static_paths : [ css/, js/, fonts/, img/ ]
private_paths : [ private/, scaffold.yml ]
default_ext : html
landing_page : recent_posts
not_found : private/404.html
view_wrappers:
- { path: post/, type: include, wrapper: private/post.html }
* paths which should not be served publicly (but can still be included from other templates)
scaffold.yml
static_paths : [ css/, js/, fonts/, img/ ]
private_paths : [ private/, scaffold.yml ]
default_ext : html
landing_page : recent_posts
not_found : private/404.html
view_wrappers:
- { path: post/, type: include, wrapper: private/post.html }
* default file extension (lets ‘/foo’ work the same as ‘/foo.html’)
scaffold.yml
static_paths : [ css/, js/, fonts/, img/ ]
private_paths : [ private/, scaffold.yml ]
default_ext : html
landing_page : recent_posts
not_found : private/404.html
view_wrappers:
- { path: post/, type: include, wrapper: private/post.html }
* page to serve for root (‘/’) request
scaffold.yml
static_paths : [ css/, js/, fonts/, img/ ]
private_paths : [ private/, scaffold.yml ]
default_ext : html
landing_page : recent_posts
not_found : private/404.html
view_wrappers:
- { path: post/, type: include, wrapper: private/post.html }
* page to serve for HTTP/404 Not Found
scaffold.yml
static_paths : [ css/, js/, fonts/, img/ ]
private_paths : [ private/, scaffold.yml ]
default_ext : html
landing_page : recent_posts
not_found : private/404.html
view_wrappers:
- { path: post/, type: include, wrapper: private/post.html }
* special URL dispatch template wrappers to expose “Posts” …
scaffold.yml
view_wrappers:
- {
path: post/,
type: include,
wrapper: private/post.html
}
scaffold.yml
view_wrappers:
- {
path: post/,
type: include,
wrapper: private/post.html
}
Use this template (as a wrapper)
scaffold.yml
view_wrappers:
- {
path: post/,
type: include,
wrapper: private/post.html
}
Use this template (as a wrapper)
for requests starting with this
scaffold.yml
view_wrappers:
- {
path: post/,
type: include,
wrapper: private/post.html
}
Use this template (as a wrapper)
for requests starting with this
e.g. this is how /post/some-name.md renders ‘some-name.md’ from the database
Showing the demo code
• Browse the site dir
• Browse the scaffold files
• Show the scaffold.yml
• Show the app.psgi
Creating a new site is easy
rabl.pl create path/to/my-cool-blog
Easy setup with Docker
docker pull rapi/psgi
mkdir my-cool-blog
docker create -it 
--name=my-cool-blog --hostname=my-cool-blog 
-p 5001:5000 
-v $(pwd)/my-cool-blog:/opt/app 
rapi/psgi
docker start my-cool-blog
docker exec -it my-cool-blog bash
# run in the shell of the Docker container:
rabl.pl create /opt/app
app-restart && exit
Planned TBD Features
• Support multiple content formats
‣ Internals already support multiple formats and post-processors
• Expand Post database model + expose easier access to customize
• Add more prefabbed scaffolds with fancier features
• Better user auth features
‣ login via 3rd-party, self-signup w/ captcha, password reset, etc
• RSS feeds
Henry Van Styn
<vanstyn@cpan.org>
The Perl Conference 2017
June 20, Washington, DC
Questions?
@vanstyn
www.rapidapp.info
rapi.io/blog
irc.perl.org - #rapidapp
slides: rapi.io/tpc2017

Rapi::Blog talk - TPC 2017

  • 1.
    Henry Van Styn <vanstyn@cpan.org> ThePerl Conference 2017 June 20, Washington, DC www.rapidapp.info rapi.io/blog irc.perl.org - #rapidapp Rapi::Blogmaximalist control, minimalist effort @vanstyn slides: rapi.io/tpc2017
  • 3.
    About me • HenryVan Styn (@vanstyn) • Owner of IntelliTree Solutions, perl shop and consultancy • Author/maintainer of RapidApp • Catalyst and DBIx::Class contributor • Given talks/demos of RapidApp for the past several years at The Perl Conference
  • 4.
    • This yearI wanted to give a RapidApp demo of a bigger, real-world app that’s real-world useful • Married this with solving another of my long-time unmet needs: A real, modern perl blog platform…
  • 5.
    Why another blogplatform? • Many reasons, a better mousetrap… • RapidApp is already very well-suited to the problem domain Biggest reason: Fresh take on front-end APIs (i.e. “themes”)
  • 6.
    The problem with“themes” • The word itself implies restrictiveness ‣ changing the appearance of something that is already defined • Inventing concepts of “pages” and “sections” and “blocks” and layouts and on and on and on that you have to adhere to • URL end-points are predetermined, rendered HTML assembled in domain- specific manner • Have to learn platform-specific APIs to even get to “Hello world” • Integrating and adapting custom HTML can be difficult and frustrating, especially when working with designers
  • 7.
    Rapi::Blog’s approach: • Termchosen to give more emphasis than “theme” • Is an ordinary, native HTML website/structure first and handles its own business as much as possible • Lives at the root of the site like the HTML wants ‣ This is the main blocker elsewhere • Supports “opportunistic” templates ‣ But can still be static HTML, and just work • The backend exposes APIs the scaffold can use, however it wants “scaffolds”
  • 8.
    Backend / Model TemplateAPI Basic Architecture: ‣ Public website structure ‣ Native HTML, CSS, JavaScript, Images, etc ‣ HTML can include template directives ‣ Database of ‘Posts’ ‣ Taxonomies ‣ Relationships ‣ Business Logic ‣ Permissions ‣ Expose Blog-specific template directives/methods Scaffold directory Advanced CRUD Interfaces RapidApp
  • 9.
    Lets see itin action • Start with a running site, go through the public-facing functionality - browsing posts, pages, search, etc • Go through the password-protected features - creating/editing posts, comments, the new markdown editor, basic administration • Browse the scaffold config and the templates and how they work • Show how to create new sites with the rabl.pl create script - demo -
  • 10.
    How it works •Rapi::Blog is a subclass of RapidApp::Builder • Plack/PSGI app with very simple options: my $app = Rapi::Blog->new({ site_path => $dir, scaffold_path => "$dir/scaffold" }); # Plack/PSGI app: $app->to_app
  • 11.
    Options • site_path • directorywhere the site lives - used for data persistence • database files are created automatically for fresh sites • scaffold_path • the “document root” for the site • serves literal/real paths from “/” • defaults to ‘scaffold/’ inside the site_path directory
  • 12.
    Scaffold • Ordinary directoryserved at the root of the site ✴ img/foo.png served as /img/foo.png, home.html served as /home.html, and so on • Merge/overlay with the Catalyst/RapidApp controller/module namespaces automagically • With no configuration it is a simple static website/folder • Any of the files can function as templates (TT) and call directives and accessors provided by the API • scaffold.yml config file tells the backend how to use it ✴ such as which template to use to display posts
  • 13.
    The scaffold tellsthe backend what to do, not the other way around.
  • 14.
    scaffold.yml static_paths : [css/, js/, fonts/, img/ ] private_paths : [ private/, scaffold.yml ] default_ext : html landing_page : recent_posts not_found : private/404.html view_wrappers: - { path: post/, type: include, wrapper: private/post.html }
  • 15.
    scaffold.yml static_paths : [css/, js/, fonts/, img/ ] private_paths : [ private/, scaffold.yml ] default_ext : html landing_page : recent_posts not_found : private/404.html view_wrappers: - { path: post/, type: include, wrapper: private/post.html } * which paths are static-only (no template directives) - mainly for performance
  • 16.
    scaffold.yml static_paths : [css/, js/, fonts/, img/ ] private_paths : [ private/, scaffold.yml ] default_ext : html landing_page : recent_posts not_found : private/404.html view_wrappers: - { path: post/, type: include, wrapper: private/post.html } * paths which should not be served publicly (but can still be included from other templates)
  • 17.
    scaffold.yml static_paths : [css/, js/, fonts/, img/ ] private_paths : [ private/, scaffold.yml ] default_ext : html landing_page : recent_posts not_found : private/404.html view_wrappers: - { path: post/, type: include, wrapper: private/post.html } * default file extension (lets ‘/foo’ work the same as ‘/foo.html’)
  • 18.
    scaffold.yml static_paths : [css/, js/, fonts/, img/ ] private_paths : [ private/, scaffold.yml ] default_ext : html landing_page : recent_posts not_found : private/404.html view_wrappers: - { path: post/, type: include, wrapper: private/post.html } * page to serve for root (‘/’) request
  • 19.
    scaffold.yml static_paths : [css/, js/, fonts/, img/ ] private_paths : [ private/, scaffold.yml ] default_ext : html landing_page : recent_posts not_found : private/404.html view_wrappers: - { path: post/, type: include, wrapper: private/post.html } * page to serve for HTTP/404 Not Found
  • 20.
    scaffold.yml static_paths : [css/, js/, fonts/, img/ ] private_paths : [ private/, scaffold.yml ] default_ext : html landing_page : recent_posts not_found : private/404.html view_wrappers: - { path: post/, type: include, wrapper: private/post.html } * special URL dispatch template wrappers to expose “Posts” …
  • 21.
    scaffold.yml view_wrappers: - { path: post/, type:include, wrapper: private/post.html }
  • 22.
    scaffold.yml view_wrappers: - { path: post/, type:include, wrapper: private/post.html } Use this template (as a wrapper)
  • 23.
    scaffold.yml view_wrappers: - { path: post/, type:include, wrapper: private/post.html } Use this template (as a wrapper) for requests starting with this
  • 24.
    scaffold.yml view_wrappers: - { path: post/, type:include, wrapper: private/post.html } Use this template (as a wrapper) for requests starting with this e.g. this is how /post/some-name.md renders ‘some-name.md’ from the database
  • 25.
    Showing the democode • Browse the site dir • Browse the scaffold files • Show the scaffold.yml • Show the app.psgi
  • 26.
    Creating a newsite is easy rabl.pl create path/to/my-cool-blog
  • 27.
    Easy setup withDocker docker pull rapi/psgi mkdir my-cool-blog docker create -it --name=my-cool-blog --hostname=my-cool-blog -p 5001:5000 -v $(pwd)/my-cool-blog:/opt/app rapi/psgi docker start my-cool-blog docker exec -it my-cool-blog bash # run in the shell of the Docker container: rabl.pl create /opt/app app-restart && exit
  • 28.
    Planned TBD Features •Support multiple content formats ‣ Internals already support multiple formats and post-processors • Expand Post database model + expose easier access to customize • Add more prefabbed scaffolds with fancier features • Better user auth features ‣ login via 3rd-party, self-signup w/ captcha, password reset, etc • RSS feeds
  • 29.
    Henry Van Styn <vanstyn@cpan.org> ThePerl Conference 2017 June 20, Washington, DC Questions? @vanstyn www.rapidapp.info rapi.io/blog irc.perl.org - #rapidapp slides: rapi.io/tpc2017

Editor's Notes

  • #2 Going to talk about the open-source, RapidApp web framework Which has been an in-house platform that we’ve been developing internally for 5 years. Just started open-sourcing within the past year. which is an extension to Catalyst that focuses on building database-driven apps faster than ever.
  • #30 Going to talk about the open-source, RapidApp web framework Which has been an in-house platform that we’ve been developing internally for 5 years. Just started open-sourcing within the past year. which is an extension to Catalyst that focuses on building database-driven apps faster than ever.