SlideShare ist ein Scribd-Unternehmen logo
1 von 100
Downloaden Sie, um offline zu lesen
HTMX: WEB 1.0
WITH WEB 2.0 BENEFITS
WITHOUT THE GRIFT OF WEB 3.0
MARTIJN DASHORST
# jfall.
WHO HAS HEARD OF
HTMX BEFORE
THIS TALK?
WHO HAS HEARD OF
INTERCOOLER
TURBOLINKS, OR
HOTWIRE?
HTMX is an old idea
that's getting a lot
of new attention
— @bholmesdev
https://www.youtube.com/watch?v=AOzy44b2gko
https://htmx.org/essays/when-to-use-hypermedia/
https://htmx.org/essays/when-to-use-hypermedia/
https://htmx.org/essays/when-to-use-hypermedia/
https://htmx.org/essays/when-to-use-hypermedia/
HERE WE ARE
I THOUGHT IT WAS A GOOD IDEA TO PITCH A PRESENTATION
FOR JFALL ABOUT HTMX TO GET TO KNOW IT BETTER. SO...
MARTIJN DASHORST
● 18 YEARS @TOPICUS
PARNASSYS, PARRO, SOMTODAY, EDUARTE
SPREEKUUR.NL, DARMKANKER SCREENING,
CORONATEST.NL, FORCE (MORTGAGES)
● BACKEND DEVELOPER BY HEART
● LOVES CREATING FIXING LEGACY SOFTWARE
● CONTRIBUTOR APACHE WICKET
● CO-AUTHORED WICKET IN ACTION
WHY HTMX?
HTMX = WEB 1.0 + WEB 2.0 - WEB 3.0
01
04
02
05
03
WHAT IS HTMX?
HOW DOES IT WORK?
DEMOS
CONCLUSIONS
HTMX
https://htmx.org
intercooler 2013-2020
14kb JavaScript library (gzipped)
- no dependencies
- no build
- attributes
- css classes
- request/response headers
- events
- extensions
- javascript API
HTMX
https://htmx.org
version 1.9.8 (Nov 6, 2023)
14kb JavaScript library (gzipped)
- no dependencies
- no build
- attributes
- css classes
- request/response headers
- events
- extensions
- javascript API
<script src="htmx.js"></script>
HTMX
https://htmx.org
version 1.9.8 (Nov 6, 2023)
14kb JavaScript library (gzipped)
- no dependencies
- no build
- attributes
- css classes
- request/response headers
- events
- extensions
- javascript API
<script src="htmx.js"></script>
<button
hx-get="/counter"
hx-swap="outerHTML">
Click me</button>
HTMX
https://htmx.org
version 1.9.8 (Nov 6, 2023)
14kb JavaScript library (gzipped)
- no dependencies
- no build
- attributes
- css classes
- request/response headers
- events
- extensions
- javascript API
<script src="htmx.js"></script>
<button
hx-get="/counter"
hx-swap="outerHTML"
hx-indicator="#indicator"
>Click me</button>
<i id="indicator"
class="htmx-indicator spinner-border">
</i>
By Carson Gross
https://bigsky.software
A Return to Hypermedia –
"Curing Your JavaScript Fatigue
Using The Original Architecture
Of The Web"
htmx: Writing JavaScript to Avoid
Writing JavaScript
HTMx: Building modern web
applications without JS
HTMX
one day code base understandable and grug can
get work done, everything good!
next day impossible: complexity demon spirit has
entered code and very dangerous situation!
— https://grugbrain.dev/
WHY HTMX?
HTMX = WEB 1.0 + WEB 2.0 - WEB 3.0
01
04
02
05
03
WHAT IS HTMX?
HOW DOES IT WORK?
DEMOS
CONCLUSIONS
BUILDING A REST API
FOR A WEB PORTAL AND NATIVE APP
MY EXPERIENCES
REST server
xml
html
xml
BUILDING A REST API
FOR A WEB PORTAL
MY EXPERIENCES
BUILDING A REST API
FOR A WEB PORTAL
MY EXPERIENCES
data format for API:
JSON or XML
BUILDING A REST API
FOR A WEB PORTAL
MY EXPERIENCES
data format for API:
JSON or XML
POST or PUT?
BUILDING A REST API
FOR A WEB PORTAL
MY EXPERIENCES
data format for API:
JSON or XML
caching the resources
POST or PUT?
BUILDING A REST API
FOR A WEB PORTAL
MY EXPERIENCES
data format for API:
JSON or XML
caching the resources
paging of results
POST or PUT?
BUILDING A REST API
FOR A WEB PORTAL
MY EXPERIENCES
data format for API:
JSON or XML
versioning the API
caching the resources
paging of results
POST or PUT?
BUILDING A REST API
FOR A WEB PORTAL
MY EXPERIENCES
data format for API:
JSON or XML
versioning the API
caching the resources
paging of results
POST or PUT?
POST to /resource or /
resource/new ?
BUILDING A REST API
FOR A WEB PORTAL
MY EXPERIENCES
data format for API:
JSON or XML
versioning the API
caching the resources
paging of results
POST or PUT?
POST to /resource or /
resource/new ?
Links between
resources?
BUILDING A REST API
FOR A WEB PORTAL
MY EXPERIENCES
data format for API:
JSON or XML
versioning the API
caching the resources
paging of results
POST or PUT?
POST to /resource or /
resource/new ?
Links between
resources?
Complex UIs, more
generic REST resources,
God Objects
A FEW
MOMENTS
YEARS
LATER
SPA architecture =
JSON + REST
Dear Roy,
What is the best practice for versioning a REST API?
DON'T
— Roy T. Fielding
Dear Roy,
What is the best practice for versioning a REST API?
https:/
/www.slideshare.net/evolve_conference/201308-fielding-evolve#31
Dear Roy,
What is the best practice for versioning a REST API?
https:/
/www.slideshare.net/evolve_conference/201308-fielding-evolve#31
when you use hypertext as the engine of application
state, you don't need it
— Roy T. Fielding
SPA architecture =
JSON + RPC
"REST"
SPA architecture =
JSON + RPC
"REST"
WHY?
WHY CAN ONLY <A> AND <FORM> PERFORM
THOSE REQUESTS?
WHY ONLY GET & POST REQUESTS?
HTML 2.0 specification
https:/
/datatracker.ietf.org/doc/html/rfc1866
1995
https:/
/datatracker.ietf.org/doc/html/rfc1866
1995
WHY HTMX?
HTMX = WEB 1.0 + WEB 2.0 - WEB 3.0
01
04
02
05
03
WHAT IS HTMX?
HOW DOES IT WORK?
DEMOS
CONCLUSIONS
HOW DOES IT WORK?
Any HTML element can
interact as an
hypermedia component
HOW DOES IT WORK?
Any HTML element can
interact as an
hypermedia component
credit: @htmx.org@twitter
https:/
/twitter.com/htmx_org/status/1700259958405869711
HOW DOES IT WORK?
Any HTML element can
interact as an
hypermedia component
<button class="btn btn-success"
onclick="
const req = new XMLHttpRequest();
req.onload = (e) => {
const admin = document.getElementById('admin');
const newAdmin = req.responseXML.getElementById('admin');
admin.innerHTML = newAdmin.innerHTML;
};
req.responseType = 'document';
req.open('GET', '/admin');
req.overrideMimeType('text/html');
req.send();"
>Click me</button>
<section id="admin"></section>
HOW DOES IT WORK?
Any HTML element can
interact as an
hypermedia component
<button class="btn btn-primary"
hx-get="/admin"
hx-select="#admin"
hx-target="#admin"
>Click me</button>
<section id="admin"></section>
GETTING THE SCRIPT
<script src="https://unpkg.com/htmx.org@1.9.7"></script>
Quick and dirty
TIP: USE WEBJARS
i
Using webjars
<dependency>
<groupId>org.webjars.npm</groupId>
<artifactId>htmx.org</artifactId>
<version>1.9.7</version>
</dependency>
<script src="/webjars/htmx.org/1.9.7/dist/htmx.js"></script>
/META-INF/resources/webjars
«classpath»
SEE ALSO: https:/
/www.baeldung.com/maven-webjars
TIP: WEBJARS + LOCATOR
i
Spring
<dependency>
<groupId>org.webjars</groupId>
<artifactId>webjars-locator</artifactId>
<version>0.48</version>
</dependency>
<script src="/webjars/htmx.org/dist/htmx.js"></script>
no version
Quarkus
quarkus ext add io.quarkus:quarkus-webjars-locator
SEE ALSO: https:/
/www.baeldung.com/maven-webjars
HOW DOES IT WORK?
Any HTML element can
interact as an
hypermedia component
Attributes instruct
HTMX what to do with
what element
HOW DOES IT WORK?
Any HTML element can
interact as an
hypermedia component
Attributes instruct
HTMX what to do with
what element
hx-boost="true|false"
hx-get="/count"
hx-post="/count"
hx-target="#counter"
hx-swap="innerHTML|outerHTML|afterend|..."
hx-trigger="click|load|every 1s"
hx-select="#htmx-badge"
hx-swap-oob="true|outerHTML:selector"
hx-delete|patch|put="/url"
...
ATTRIBUTES – hx-boost
<nav hx-boost="true">
<li><a href="/menu1">Menu 1</a></li>
<li><a href="/menu2">Menu 2</a></li>
<li><a href="/menu3">Menu 3</a></li>
<li><a href="/menu4">Menu 4</a></li>
</nav>
Replaces the GET/POST request using AJAX and replaces the body using
innerHTML swap.
inherited
ATTRIBUTES – hx-get
<button hx-get="/speaker/1">Get speaker 1</button>
Issue a GET request to the specified URL and swap the returned HTML into
the DOM using a swap strategy
ATTRIBUTES – hx-get
<button hx-get="/speaker/1">Get speaker 1</button>
Issue a GET request to the specified URL and swap the returned HTML into
the DOM using a swap strategy
ATTRIBUTES – hx-get
<button hx-get="/speaker/1">Get speaker 1</button>
Issue a GET request to the specified URL and swap the returned HTML into
the DOM using a swap strategy
<div id="speaker">...</div>
ATTRIBUTES – hx-get
<button hx-get="/speaker/1">Get speaker 1</button>
Issue a GET request to the specified URL and swap the returned HTML into
the DOM using a swap strategy
<div id="speaker">...</div>
<button hx-get="/speaker/1">
Get speaker 1
</button>
ATTRIBUTES – hx-get
<button hx-get="/speaker/1">Get speaker 1</button>
Issue a GET request to the specified URL and swap the returned HTML into
the DOM using a swap strategy
<div id="speaker">...</div>
<button hx-get="/speaker/1">
<div id="speaker">...</div>
</button>
ATTRIBUTES – hx-swap
<button hx-get="/speaker/1"
hx-swap="outerHTML">Get speaker 1</button>
Controls how the HTML is swapped into the DOM.
innerHTML, outerHTML, beforebegin, afterbegin, beforeend, afterend, delete, none
<div id="speaker">...</div>
<button hx-get="/speaker/1"
hx-swap="outerHTML">Get speaker 1</button>
inherited
ATTRIBUTES – hx-swap
<button hx-get="/speaker/1"
hx-swap="outerHTML">Get speaker 1</button>
Controls how the HTML is swapped into the DOM.
innerHTML, outerHTML, beforebegin, afterbegin, beforeend, afterend, delete, none
<div id="speaker">...</div>
<div id="speaker">...</div>
ATTRIBUTES – hx-target
Controls which element in the DOM gets swapped with the returned HTML
using a swapping strategy.
inherited
<button hx-get="/speaker/1" hx-swap="outerHTML"
hx-target="#speaker">Get speaker 1</button>
<div id="speaker">No content</div>
ATTRIBUTES – hx-target
Controls which element in the DOM gets swapped with the returned HTML
using a swapping strategy.
inherited
<button hx-get="/speaker/1" hx-swap="outerHTML"
hx-target="#speaker">Get speaker 1</button>
<div id="speaker">No content</div>
<div id="speaker">Johan Janssen</div>
<div id="speaker">No content</div>
ATTRIBUTES – hx-target
Controls which element in the DOM gets swapped with the returned HTML
using a swapping strategy.
inherited
<button hx-get="/speaker/1" hx-swap="outerHTML"
hx-target="#speaker">Get speaker 1</button>
<div id="speaker">No content</div>
<div id="speaker" class="card">Johan Janssen</div>
<div id="speaker">No content</div>
ATTRIBUTES – hx-target
Controls which element in the DOM gets swapped with the returned HTML
using a swapping strategy.
inherited
<button hx-get="/speaker/1" hx-swap="outerHTML"
hx-target="#speaker">Get speaker 1</button>
<div id="speaker">No content</div>
<div id="speaker" class="card">Johan Janssen</div>
<div id="speaker" class="card">Johan Janssen</div>
ATTRIBUTES – hx-target
Inherited???
inherited
<menu>
<a hx-get="/speaker/1" hx-target="#speaker">Get speaker 1
<a hx-get="/speaker/2" hx-target="#speaker">Get speaker 2
<a hx-get="/speaker/3" hx-target="#speaker">Get speaker 3
<a hx-get="/speaker/4" hx-target="#speaker">Get speaker 4
</menu>
ATTRIBUTES – hx-target
hx-target is inherited and can be placed on a parent element.
inherited
<menu hx-target="#speaker">
<a hx-get="/speaker/1">Get speaker 1</a>
<a hx-get="/speaker/2">Get speaker 2</a>
<a hx-get="/speaker/3">Get speaker 3</a>
<a hx-get="/speaker/4">Get speaker 4</a>
</menu>
MORE ABOUT ATTRIBUTES
INHERITED ATTRIBUTES
NO JAVASCRIPT REQ'D
Removes repetition of
common attributes, such as
the target, swap method,
selecting elements etc.
Can be overridden by
hx-disinherit
With just the tags you can
create rich dynamically
updating pages.
Slap on some attributes and
continue.
In the HTML response you can
add more updates by using
out-of-band swaps
(hx-swap-oob)
UPDATE MULTIPLE ELEMENTS
HOW DOES IT WORK?
Any HTML element can
interact as an
hypermedia component
Attributes instruct
HTMX what to do with
what element
Server may need to
distinguish between
normal and HTMX
request: Headers
HX-Request always true
HX-Boosted indicates hx-boost request
HX-Current-URL ...
...
REQUEST HEADERS
RESPONSE HEADERS
HX-Redirect client-side redirect
HX-Refresh client-side full refresh of the page
HX-Retarget modify the hx-target
HX-Trigger trigger client-side events
...
HOW DOES IT WORK – HEADERS
Convenient for deciding to return a
partial or a full page
DETECT HTMX REQUEST
MODIFY REQUESTS
Change the target, or swapping
mechanism, send a redirect or replace
the URL in the location bar. And more.
HOW DOES IT WORK?
Any HTML element can
interact as an
hypermedia component
Attributes instruct
HTMX what to do with
what element
Server may need to
distinguish between
normal and HTMX
request: Headers
When a HTMX request
is in flight, feedback is
wanted for Users:
classes
htmx-indicator toggles visibility (opacity:1)
htmx-request applied to hx-indicator during request
htmx-added
htmx-swapping
htmx-settling
CLASSES
HOW DOES IT WORK – CLASSES
Convenient for deciding to return a
partial or a full page
INDICATOR
ANIMATIONS
Animate swapping of elements for a
more rich experience.
HOW DOES IT WORK?
Any HTML element can
interact as an
hypermedia component
Attributes instruct
HTMX what to do with
what element
Server may need to
distinguish between
normal and HTMX
request: Headers
When a HTMX request
is in flight, feedback is
wanted for Users:
classes
Complex needs for
reacting to interactions,
swapping, requests &
responses: events
HOW DOES IT WORK? – EVENTS
htmx:abort
htmx:afterOnLoad
htmx:afterProcessNode
htmx:afterRequest
htmx:afterSettle
htmx:afterSwap
htmx:beforeCleanupElement
htmx:beforeOnLoad
htmx:beforeProcessNode
htmx:beforeRequest
htmx:beforeSwap
htmx:beforeSend
htmx:configRequest
htmx:confirm
htmx:historyCacheError
htmx:historyCacheMiss
htmx:historyCacheMissError
htmx:historyCacheMissLoad
htmx:historyRestore
htmx:beforeHistorySave
htmx:load
htmx:noSSESourceError
htmx:onLoadError
htmx:oobAfterSwap
htmx:oobBeforeSwap
htmx:oobErrorNoTarget
htmx:prompt
htmx:pushedIntoHistory
htmx:responseError
htmx:sendError
htmx:sseError
htmx:sseOpen
htmx:swapError
htmx:targetError
htmx:timeout
htmx:validation:validate
htmx:validation:failed
htmx:validation:halted
htmx:xhr:abort
htmx:xhr:loadend
htmx:xhr:loadstart
htmx:xhr:progress
HOW DOES IT WORK? – EVENTS
before/after swaps
occurred, after DOM has
settled, out-of-bounds
swaps, etc.
Anything relevant to
modifying using the
history API
The lifecycle of the XHR
request: progress,
loadend, loadstart, etc.
Errors sending a request,
receiving a response,
targetting an element, etc.
SWAPPING HISTORY VALIDATION
Triggered when client side
validation is performed,
failed.
Configure the request
before it is sent to the
server, response
processing
XHR ERRORS REQUESTS
HOW DOES IT WORK?
Any HTML element can
interact as an
hypermedia component
Attributes instruct
HTMX what to do with
what element
Server may need to
distinguish between
normal and HTMX
request: Headers
When a HTMX request
is in flight, feedback is
wanted for Users:
classes
Complex needs for
reacting to interactions,
swapping, requests &
responses: events
In the events some
annoying JavaScript
needs to be executed
(e.g. add class):
JavaScript library
FINDING ELEMENTS
HOW DOES IT WORK? – JAVASCRIPT
addClass(), removeClass(),
toggleClass(), takeClass()
remove(), values()
EVENTS ON ELEMENTS
on(), off(), trigger()
closest(), find(), findAll() config, ajax(), process()
defineExtension(), removeExtension()
WORKING WITH CLASSES WORKING WITH ELEMENTS
INTERNALS & EXTENSIONS
HOW DOES IT WORK? – JAVASCRIPT
Documents
Projects
Members
Admin
Gangplank lookout killick jack yo-ho-ho Sea Legs yard
marooned interloper yawl. Gabion fire ship Brethren of the
Coast lanyard chase Cat o'nine tails dead men tell no tales
barque yawl Nelsons folly.
<ul class="list-group" hx-target="#content"
hx-on::after-request="htmx.takeClass(event.detail.elt, 'active')">
<li class="list-group-item" hx-get="/sub/Documents">Documents</li>
<li class="list-group-item" hx-get="/sub/Projects">Projects</li>
<li class="list-group-item" hx-get="/sub/Members">Members</li>
<li class="list-group-item" hx-get="/sub/Admin">Admin</li>
</ul>
<section id="content"></section>
HOW DOES IT WORK?
Any HTML element can
interact as an
hypermedia component
Attributes instruct
HTMX what to do with
what element
Server may need to
distinguish between
normal and HTMX
request: Headers
When a HTMX request
is in flight, feedback is
wanted for Users:
classes
Complex needs for
reacting to interactions,
swapping, requests &
responses: events
In the events some
annoying JavaScript
needs to be executed
(e.g. add class):
JavaScript library
We need to use a
different HTML
morphing algo,
serverside sent events
or web sockets:
extensions
FINALLY HATEOAS?
HTMX = WEB 1.0 + WEB 2.0 - WEB 3.0
01
04
02
05
03
WHAT IS HTMX?
HOW DOES IT WORK?
DEMOS
CONCLUSIONS
Examples
Fun with flags game
fun with flags
● quarkus
● qute
● websockets
● htmx
● htmx-ws
● bootstrap
● flag=icons
github.com/dashorst/funwithflags
WEBSOCKETS FTW!
@ServerEndpoint("/game/{player}")
public class FunWithFlagsWebSocket {
@OnOpen
public void onOpen(Session session, @PathParam("player") String encodedPlayer) {
var player = URLDecoder.decode(encodedPlayer, StandardCharsets.UTF_8);
sessions.put(player, session);
funWithFlagsGame.registerPlayer(session, player);
}
WEBSOCKETS FTW!
@ServerEndpoint("/game/{player}")
public class FunWithFlagsWebSocket {
@OnOpen
public void onOpen(Session session, @PathParam("player") String encodedPlayer) {
var player = URLDecoder.decode(encodedPlayer, StandardCharsets.UTF_8);
sessions.put(player, session);
funWithFlagsGame.registerPlayer(session, player);
}
<div id="game" hx-ext="ws" ws-connect="/game/{playername}" class="row">
<div class="col-12 text-center">
<h3>Joining lobby...</h3>
{#fragment id=lobby}
<ul class="list-group" id="lobby-list">
{#for player in players}
<li class="list-group-item {#if player.name == playername} list-group-
{/for}
</ul>
{/fragment}
<p>Waiting for other players to join!</p>
</div>
</div>
WEBSOCKETS FTW!
@ServerEndpoint("/game/{player}")
public class FunWithFlagsWebSocket {
@OnOpen
public void onOpen(Session session, @PathParam("player") String encodedPlayer) {
var player = URLDecoder.decode(encodedPlayer, StandardCharsets.UTF_8);
sessions.put(player, session);
funWithFlagsGame.registerPlayer(session, player);
}
<div id="game" hx-ext="ws" ws-connect="/game/{playername}" class="row">
<div class="col-12 text-center">
<h3>Joining lobby...</h3>
{#fragment id=lobby}
<ul class="list-group" id="lobby-list">
{#for player in players}
<li class="list-group-item {#if player.name == playername} list-group-
{/for}
</ul>
{/fragment}
<p>Waiting for other players to join!</p>
</div>
</div>
hx-ext="ws" ws-connect="/game/{playername}"
@ServerEndpoint("/game/{player}")
@OnOpen
public void onOpen(Session session, @PathParam("player")
SENDING TURN START TO PLAYERS
public void onTurnStarted(@Observes TurnStarted event) {
var game = event.game();
var turn = event.turn();
var countryToGuess = turn.countryToGuess();
for (Player player : game.players()) {
var turnHtml = Templates.game$turnPartial(player, game, turn, countryToGuess)
.render();
var rankHtml = Templates.game$rankingPartial(player, game, turn).render();
player.session().getAsyncRemote().sendObject(turnHtml + "n" + rankHtml);
}
}
<div id="turn" class="col-12 col-lg-6 offset-lg-3">
<h2>Round {game.turnNumber} of {game.numberOfTurns}</h2>
...
</div>
<div id="in-game-ranking" class="col-12 col-md-3">
<h3>Ranking round {game.turnNumber}</h3>
...
</div>
SENDING TURN START TO PLAYERS
public void onTurnStarted(@Observes TurnStarted event) {
var game = event.game();
var turn = event.turn();
var countryToGuess = turn.countryToGuess();
for (Player player : game.players()) {
var turnHtml = Templates.game$turnPartial(player, game, turn, countryToGuess)
.render();
var rankHtml = Templates.game$rankingPartial(player, game, turn).render();
player.session().getAsyncRemote().sendObject(turnHtml + "n" + rankHtml);
}
}
<div id="turn" class="col-12 col-lg-6 offset-lg-3">
<h2>Round {game.turnNumber} of {game.numberOfTurns}</h2>
...
</div>
<div id="in-game-ranking" class="col-12 col-md-3">
<h3>Ranking round {game.turnNumber}</h3>
...
</div>
SENDING TURN START TO PLAYERS
public void onTurnStarted(@Observes TurnStarted event) {
var game = event.game();
var turn = event.turn();
var countryToGuess = turn.countryToGuess();
for (Player player : game.players()) {
var turnHtml = Templates.game$turnPartial(player, game, turn, countryToGuess)
.render();
var rankHtml = Templates.game$rankingPartial(player, game, turn).render();
player.session().getAsyncRemote().sendObject(turnHtml + "n" + rankHtml);
}
}
<div id="turn" class="col-12 col-lg-6 offset-lg-3">
<h2>Round {game.turnNumber} of {game.numberOfTurns}</h2>
...
</div>
<div id="in-game-ranking" class="col-12 col-md-3">
<h3>Ranking round {game.turnNumber}</h3>
...
</div>
SENDING TURN START TO PLAYERS
public void onTurnStarted(@Observes TurnStarted event) {
var game = event.game();
var turn = event.turn();
var countryToGuess = turn.countryToGuess();
for (Player player : game.players()) {
var turnHtml = Templates.game$turnPartial(player, game, turn, countryToGuess)
.render();
var rankHtml = Templates.game$rankingPartial(player, game, turn).render();
player.session().getAsyncRemote().sendObject(turnHtml + "n" + rankHtml);
}
}
<div id="turn" class="col-12 col-lg-6 offset-lg-3">
<h2>Round {game.turnNumber} of {game.numberOfTurns}</h2>
...
</div>
<div id="in-game-ranking" class="col-12 col-md-3">
<h3>Ranking round {game.turnNumber}</h3>
...
</div>
SENDING TURN START TO PLAYERS
public void onTurnStarted(@Observes TurnStarted event) {
var game = event.game();
var turn = event.turn();
var countryToGuess = turn.countryToGuess();
for (Player player : game.players()) {
var turnHtml = Templates.game$turnPartial(player, game, turn, countryToGuess)
.render();
var rankHtml = Templates.game$rankingPartial(player, game, turn).render();
player.session().getAsyncRemote().sendObject(turnHtml + "n" + rankHtml);
}
}
<div id="turn" class="col-12 col-lg-6 offset-lg-3">
<h2>Round {game.turnNumber} of {game.numberOfTurns}</h2>
...
</div>
<div id="in-game-ranking" class="col-12 col-md-3">
<h3>Ranking round {game.turnNumber}</h3>
...
</div>
DEMO
FINALLY HATEOAS?
HTMX = WEB 1.0 + WEB 2.0 - WEB 3.0
01
04
02
05
03
WHAT IS HTMX?
HOW DOES IT WORK?
DEMOS
CONCLUSIONS
BACKEND DEVS REJOICE
HTMX: WEB 1.0 + WEB 2.0 - WEB 3.0
No more general APIs between your
user interface and your back end. Use
hypermedia as the engine for your
application state
Hypermedia On Whatever You'd Like.
Backend agnostic! Spring Boot,
Quarkus, JSP, PHP, DJango, Ruby on
Rails, ...
HTMX allows you to build rich front
ends without having to learn rich front
end technologies.
Just one script tag and your back end.
Written in whatever you'd like.
REST WITH HATEOAS HOWL STACK
REDUCE THE CHURN
It took me ~2 months spare time to write Fun with
Flags, but most of that time was spent figuring out
the game mechanics, not HTMX integration.
9/10, would use again1
1 (already using it in other projects)
HTMX.ORG
https://htmx.org
Great documentation,
examples and essays on the
fundamentals of HTMX and
hypermedia.
WARNING
Also memes
HYPERMEDIA
SYSTEMS
https://hypermedia.systems
Best explanation of
Hypermedia, REST,
RESTFUL and HATEOAS.
WARNING
Risk of wanting to use HTMX after reading
https:/
/fun-with-flags.eduarte.dev
Wanna play?
Scan this
CREDITS: This presentation template was created by Slidesgo, and
includes icons by Flaticon, and infographics & images by Freepik
THANKS!
Do you have any questions?
martijn.dashorst@topicus.nl
@dashorst@mastodon.social
martijndashorst.com
CREDITS
HTMX was conceived by Carson Gross
Title "HTMX: WEB 1.0 WITH WEB 2.0 BENEFITS WITHOUT THE GRIFT OF WEB 3.0"
was inspired by The Primagen
Template by slidesgo and includes images from flaticon and icons from freepik
Thanks for your attention
Please rate my session in the J-Fall app
# jfall.
fun-with-flags.eduarte.dev HTMX: web 1.0 + web 2.0 - web 3.0
Martijn Dashorst
topicus

Weitere ähnliche Inhalte

Was ist angesagt?

XSS - Do you know EVERYTHING?
XSS - Do you know EVERYTHING?XSS - Do you know EVERYTHING?
XSS - Do you know EVERYTHING?Yurii Bilyk
 
Upload files with grails
Upload files with grailsUpload files with grails
Upload files with grailsEric Berry
 
Forge UI: A New Way to Customize the Atlassian User Experience
Forge UI: A New Way to Customize the Atlassian User ExperienceForge UI: A New Way to Customize the Atlassian User Experience
Forge UI: A New Way to Customize the Atlassian User ExperienceAtlassian
 
What is Ajax technology?
What is Ajax technology?What is Ajax technology?
What is Ajax technology?JavaTpoint.Com
 
Lie to Me: Bypassing Modern Web Application Firewalls
Lie to Me: Bypassing Modern Web Application FirewallsLie to Me: Bypassing Modern Web Application Firewalls
Lie to Me: Bypassing Modern Web Application FirewallsIvan Novikov
 
Introduction to React JS
Introduction to React JSIntroduction to React JS
Introduction to React JSArno Lordkronos
 
React JS and why it's awesome
React JS and why it's awesomeReact JS and why it's awesome
React JS and why it's awesomeAndrew Hull
 
Integration patterns in AEM 6
Integration patterns in AEM 6Integration patterns in AEM 6
Integration patterns in AEM 6Yuval Ararat
 
The redux saga begins
The redux saga beginsThe redux saga begins
The redux saga beginsDaniel Franz
 
Security in PHP - 那些在滲透測試的小技巧
Security in PHP - 那些在滲透測試的小技巧Security in PHP - 那些在滲透測試的小技巧
Security in PHP - 那些在滲透測試的小技巧Orange Tsai
 
Enterprise Messaging with Apache ActiveMQ
Enterprise Messaging with Apache ActiveMQEnterprise Messaging with Apache ActiveMQ
Enterprise Messaging with Apache ActiveMQelliando dias
 
types of events in JS
types of events in JS types of events in JS
types of events in JS chauhankapil
 
Let's read code: the python-requests library
Let's read code: the python-requests libraryLet's read code: the python-requests library
Let's read code: the python-requests librarySusan Tan
 
Monitoramento Inteligente utilizando o ZABBIX
Monitoramento Inteligente utilizando o ZABBIXMonitoramento Inteligente utilizando o ZABBIX
Monitoramento Inteligente utilizando o ZABBIXLuiz Andrade
 

Was ist angesagt? (20)

XSS - Do you know EVERYTHING?
XSS - Do you know EVERYTHING?XSS - Do you know EVERYTHING?
XSS - Do you know EVERYTHING?
 
UEFI HTTP/HTTPS Boot
UEFI HTTP/HTTPS BootUEFI HTTP/HTTPS Boot
UEFI HTTP/HTTPS Boot
 
CloudInit Introduction
CloudInit IntroductionCloudInit Introduction
CloudInit Introduction
 
Upload files with grails
Upload files with grailsUpload files with grails
Upload files with grails
 
Forge UI: A New Way to Customize the Atlassian User Experience
Forge UI: A New Way to Customize the Atlassian User ExperienceForge UI: A New Way to Customize the Atlassian User Experience
Forge UI: A New Way to Customize the Atlassian User Experience
 
sveltekit-en.pdf
sveltekit-en.pdfsveltekit-en.pdf
sveltekit-en.pdf
 
What is Ajax technology?
What is Ajax technology?What is Ajax technology?
What is Ajax technology?
 
Lie to Me: Bypassing Modern Web Application Firewalls
Lie to Me: Bypassing Modern Web Application FirewallsLie to Me: Bypassing Modern Web Application Firewalls
Lie to Me: Bypassing Modern Web Application Firewalls
 
Introduction to React JS
Introduction to React JSIntroduction to React JS
Introduction to React JS
 
React JS and why it's awesome
React JS and why it's awesomeReact JS and why it's awesome
React JS and why it's awesome
 
Angular Observables & RxJS Introduction
Angular Observables & RxJS IntroductionAngular Observables & RxJS Introduction
Angular Observables & RxJS Introduction
 
Integration patterns in AEM 6
Integration patterns in AEM 6Integration patterns in AEM 6
Integration patterns in AEM 6
 
React Hooks
React HooksReact Hooks
React Hooks
 
The redux saga begins
The redux saga beginsThe redux saga begins
The redux saga begins
 
Security in PHP - 那些在滲透測試的小技巧
Security in PHP - 那些在滲透測試的小技巧Security in PHP - 那些在滲透測試的小技巧
Security in PHP - 那些在滲透測試的小技巧
 
Reactjs
Reactjs Reactjs
Reactjs
 
Enterprise Messaging with Apache ActiveMQ
Enterprise Messaging with Apache ActiveMQEnterprise Messaging with Apache ActiveMQ
Enterprise Messaging with Apache ActiveMQ
 
types of events in JS
types of events in JS types of events in JS
types of events in JS
 
Let's read code: the python-requests library
Let's read code: the python-requests libraryLet's read code: the python-requests library
Let's read code: the python-requests library
 
Monitoramento Inteligente utilizando o ZABBIX
Monitoramento Inteligente utilizando o ZABBIXMonitoramento Inteligente utilizando o ZABBIX
Monitoramento Inteligente utilizando o ZABBIX
 

Ähnlich wie HTMX: Web 1.0 with the benefits of Web 2.0 without the grift of Web 3.0

HTTP/2 : why upgrading the web? - DjangoCon Europe 2016 Budapest
HTTP/2 : why upgrading the web? - DjangoCon Europe 2016 BudapestHTTP/2 : why upgrading the web? - DjangoCon Europe 2016 Budapest
HTTP/2 : why upgrading the web? - DjangoCon Europe 2016 BudapestQuentin Adam
 
HTTP/2 : why upgrading the web? - apidays Paris
HTTP/2 : why upgrading the web? - apidays ParisHTTP/2 : why upgrading the web? - apidays Paris
HTTP/2 : why upgrading the web? - apidays ParisQuentin Adam
 
Fulfilling the Hypermedia Constraint via HTTP OPTIONS, The HTTP Vocabulary In...
Fulfilling the Hypermedia Constraint via HTTP OPTIONS, The HTTP Vocabulary In...Fulfilling the Hypermedia Constraint via HTTP OPTIONS, The HTTP Vocabulary In...
Fulfilling the Hypermedia Constraint via HTTP OPTIONS, The HTTP Vocabulary In...ruyalarcon
 
Http2: why the web is upgrading? - bdx.io 2015
Http2: why the web is upgrading?   - bdx.io 2015Http2: why the web is upgrading?   - bdx.io 2015
Http2: why the web is upgrading? - bdx.io 2015Quentin Adam
 
POX to HATEOAS: Our Company's Journey Building a Hypermedia API
POX to HATEOAS: Our Company's Journey Building a Hypermedia APIPOX to HATEOAS: Our Company's Journey Building a Hypermedia API
POX to HATEOAS: Our Company's Journey Building a Hypermedia APILuke Stokes
 
The end of polling : why and how to transform a REST API into a Data Streamin...
The end of polling : why and how to transform a REST API into a Data Streamin...The end of polling : why and how to transform a REST API into a Data Streamin...
The end of polling : why and how to transform a REST API into a Data Streamin...Audrey Neveu
 
Hanoi php day 2008 - 05. nguyen hai nhat huy - building-restful-web-service-w...
Hanoi php day 2008 - 05. nguyen hai nhat huy - building-restful-web-service-w...Hanoi php day 2008 - 05. nguyen hai nhat huy - building-restful-web-service-w...
Hanoi php day 2008 - 05. nguyen hai nhat huy - building-restful-web-service-w...Nguyen Duc Phu
 
The Power of Open Data
The Power of Open DataThe Power of Open Data
The Power of Open DataPhil Windley
 
Together Cheerfully to Walk with Hypermedia
Together Cheerfully to Walk with HypermediaTogether Cheerfully to Walk with Hypermedia
Together Cheerfully to Walk with HypermediaVladimir Tsukur
 
HTTP colon slash slash: end of the road? @ CakeFest 2013 in San Francisco
HTTP colon slash slash: end of the road? @ CakeFest 2013 in San FranciscoHTTP colon slash slash: end of the road? @ CakeFest 2013 in San Francisco
HTTP colon slash slash: end of the road? @ CakeFest 2013 in San FranciscoAlessandro Nadalin
 
KMUTNB - Internet Programming 2/7
KMUTNB - Internet Programming 2/7KMUTNB - Internet Programming 2/7
KMUTNB - Internet Programming 2/7phuphax
 
From ZERO to REST in an hour
From ZERO to REST in an hour From ZERO to REST in an hour
From ZERO to REST in an hour Cisco DevNet
 
ASP.NET Web API and HTTP Fundamentals
ASP.NET Web API and HTTP FundamentalsASP.NET Web API and HTTP Fundamentals
ASP.NET Web API and HTTP FundamentalsIdo Flatow
 

Ähnlich wie HTMX: Web 1.0 with the benefits of Web 2.0 without the grift of Web 3.0 (20)

HTTP/2 : why upgrading the web? - DjangoCon Europe 2016 Budapest
HTTP/2 : why upgrading the web? - DjangoCon Europe 2016 BudapestHTTP/2 : why upgrading the web? - DjangoCon Europe 2016 Budapest
HTTP/2 : why upgrading the web? - DjangoCon Europe 2016 Budapest
 
HTTP/2 : why upgrading the web? - apidays Paris
HTTP/2 : why upgrading the web? - apidays ParisHTTP/2 : why upgrading the web? - apidays Paris
HTTP/2 : why upgrading the web? - apidays Paris
 
Fulfilling the Hypermedia Constraint via HTTP OPTIONS, The HTTP Vocabulary In...
Fulfilling the Hypermedia Constraint via HTTP OPTIONS, The HTTP Vocabulary In...Fulfilling the Hypermedia Constraint via HTTP OPTIONS, The HTTP Vocabulary In...
Fulfilling the Hypermedia Constraint via HTTP OPTIONS, The HTTP Vocabulary In...
 
Http2: why the web is upgrading? - bdx.io 2015
Http2: why the web is upgrading?   - bdx.io 2015Http2: why the web is upgrading?   - bdx.io 2015
Http2: why the web is upgrading? - bdx.io 2015
 
POX to HATEOAS: Our Company's Journey Building a Hypermedia API
POX to HATEOAS: Our Company's Journey Building a Hypermedia APIPOX to HATEOAS: Our Company's Journey Building a Hypermedia API
POX to HATEOAS: Our Company's Journey Building a Hypermedia API
 
HTTP/2
HTTP/2HTTP/2
HTTP/2
 
The end of polling : why and how to transform a REST API into a Data Streamin...
The end of polling : why and how to transform a REST API into a Data Streamin...The end of polling : why and how to transform a REST API into a Data Streamin...
The end of polling : why and how to transform a REST API into a Data Streamin...
 
HTTP Basics Demo
HTTP Basics DemoHTTP Basics Demo
HTTP Basics Demo
 
Introduction to python scrapping
Introduction to python scrappingIntroduction to python scrapping
Introduction to python scrapping
 
Hanoi php day 2008 - 05. nguyen hai nhat huy - building-restful-web-service-w...
Hanoi php day 2008 - 05. nguyen hai nhat huy - building-restful-web-service-w...Hanoi php day 2008 - 05. nguyen hai nhat huy - building-restful-web-service-w...
Hanoi php day 2008 - 05. nguyen hai nhat huy - building-restful-web-service-w...
 
The Power of Open Data
The Power of Open DataThe Power of Open Data
The Power of Open Data
 
Together Cheerfully to Walk with Hypermedia
Together Cheerfully to Walk with HypermediaTogether Cheerfully to Walk with Hypermedia
Together Cheerfully to Walk with Hypermedia
 
HTTP colon slash slash: end of the road? @ CakeFest 2013 in San Francisco
HTTP colon slash slash: end of the road? @ CakeFest 2013 in San FranciscoHTTP colon slash slash: end of the road? @ CakeFest 2013 in San Francisco
HTTP colon slash slash: end of the road? @ CakeFest 2013 in San Francisco
 
ASP.NET WEB API Training
ASP.NET WEB API TrainingASP.NET WEB API Training
ASP.NET WEB API Training
 
KMUTNB - Internet Programming 2/7
KMUTNB - Internet Programming 2/7KMUTNB - Internet Programming 2/7
KMUTNB - Internet Programming 2/7
 
From ZERO to REST in an hour
From ZERO to REST in an hour From ZERO to REST in an hour
From ZERO to REST in an hour
 
11 asp.net web api
11 asp.net web api11 asp.net web api
11 asp.net web api
 
Talking to Web Services
Talking to Web ServicesTalking to Web Services
Talking to Web Services
 
URL Design
URL DesignURL Design
URL Design
 
ASP.NET Web API and HTTP Fundamentals
ASP.NET Web API and HTTP FundamentalsASP.NET Web API and HTTP Fundamentals
ASP.NET Web API and HTTP Fundamentals
 

Mehr von Martijn Dashorst

From Floppy Disks to Cloud Deployments
From Floppy Disks to Cloud DeploymentsFrom Floppy Disks to Cloud Deployments
From Floppy Disks to Cloud DeploymentsMartijn Dashorst
 
Converting 85% of Dutch Primary Schools from Oracle to PostgreSQL
Converting 85% of Dutch Primary Schools from Oracle to PostgreSQLConverting 85% of Dutch Primary Schools from Oracle to PostgreSQL
Converting 85% of Dutch Primary Schools from Oracle to PostgreSQLMartijn Dashorst
 
Solutions for when documentation fails
Solutions for when documentation fails Solutions for when documentation fails
Solutions for when documentation fails Martijn Dashorst
 
Whats up with wicket 8 and java 8
Whats up with wicket 8 and java 8Whats up with wicket 8 and java 8
Whats up with wicket 8 and java 8Martijn Dashorst
 
Java Serialization Deep Dive
Java Serialization Deep DiveJava Serialization Deep Dive
Java Serialization Deep DiveMartijn Dashorst
 
Scrum: van praktijk naar onderwijs
Scrum: van praktijk naar onderwijsScrum: van praktijk naar onderwijs
Scrum: van praktijk naar onderwijsMartijn Dashorst
 
Who Automates the Automators? (Quis Automatiet Ipsos Automates?)
Who Automates the Automators? (Quis Automatiet Ipsos Automates?)Who Automates the Automators? (Quis Automatiet Ipsos Automates?)
Who Automates the Automators? (Quis Automatiet Ipsos Automates?)Martijn Dashorst
 
Wicket 10 years and beyond
Wicket   10 years and beyond Wicket   10 years and beyond
Wicket 10 years and beyond Martijn Dashorst
 
Apache Wicket and Java EE sitting in a tree
Apache Wicket and Java EE sitting in a treeApache Wicket and Java EE sitting in a tree
Apache Wicket and Java EE sitting in a treeMartijn Dashorst
 
Vakmanschap is meesterschap
Vakmanschap is meesterschapVakmanschap is meesterschap
Vakmanschap is meesterschapMartijn Dashorst
 
Keep your Wicket application in production
Keep your Wicket application in productionKeep your Wicket application in production
Keep your Wicket application in productionMartijn Dashorst
 
Wicket In Action - oredev2008
Wicket In Action - oredev2008Wicket In Action - oredev2008
Wicket In Action - oredev2008Martijn Dashorst
 
Guide To Successful Graduation at Apache
Guide To Successful Graduation at ApacheGuide To Successful Graduation at Apache
Guide To Successful Graduation at ApacheMartijn Dashorst
 

Mehr von Martijn Dashorst (20)

From Floppy Disks to Cloud Deployments
From Floppy Disks to Cloud DeploymentsFrom Floppy Disks to Cloud Deployments
From Floppy Disks to Cloud Deployments
 
SOLID principles
SOLID principlesSOLID principles
SOLID principles
 
Converting 85% of Dutch Primary Schools from Oracle to PostgreSQL
Converting 85% of Dutch Primary Schools from Oracle to PostgreSQLConverting 85% of Dutch Primary Schools from Oracle to PostgreSQL
Converting 85% of Dutch Primary Schools from Oracle to PostgreSQL
 
Solutions for when documentation fails
Solutions for when documentation fails Solutions for when documentation fails
Solutions for when documentation fails
 
Whats up with wicket 8 and java 8
Whats up with wicket 8 and java 8Whats up with wicket 8 and java 8
Whats up with wicket 8 and java 8
 
Code review drinking game
Code review drinking gameCode review drinking game
Code review drinking game
 
Java Serialization Deep Dive
Java Serialization Deep DiveJava Serialization Deep Dive
Java Serialization Deep Dive
 
Code review drinking game
Code review drinking gameCode review drinking game
Code review drinking game
 
Scrum: van praktijk naar onderwijs
Scrum: van praktijk naar onderwijsScrum: van praktijk naar onderwijs
Scrum: van praktijk naar onderwijs
 
Who Automates the Automators? (Quis Automatiet Ipsos Automates?)
Who Automates the Automators? (Quis Automatiet Ipsos Automates?)Who Automates the Automators? (Quis Automatiet Ipsos Automates?)
Who Automates the Automators? (Quis Automatiet Ipsos Automates?)
 
De schone coder
De schone coderDe schone coder
De schone coder
 
Wicket 10 years and beyond
Wicket   10 years and beyond Wicket   10 years and beyond
Wicket 10 years and beyond
 
Apache Wicket and Java EE sitting in a tree
Apache Wicket and Java EE sitting in a treeApache Wicket and Java EE sitting in a tree
Apache Wicket and Java EE sitting in a tree
 
The State of Wicket
The State of WicketThe State of Wicket
The State of Wicket
 
Wicket 2010
Wicket 2010Wicket 2010
Wicket 2010
 
Vakmanschap is meesterschap
Vakmanschap is meesterschapVakmanschap is meesterschap
Vakmanschap is meesterschap
 
Keep your Wicket application in production
Keep your Wicket application in productionKeep your Wicket application in production
Keep your Wicket application in production
 
Wicket In Action - oredev2008
Wicket In Action - oredev2008Wicket In Action - oredev2008
Wicket In Action - oredev2008
 
Guide To Successful Graduation at Apache
Guide To Successful Graduation at ApacheGuide To Successful Graduation at Apache
Guide To Successful Graduation at Apache
 
Wicket In Action
Wicket In ActionWicket In Action
Wicket In Action
 

Kürzlich hochgeladen

A Guideline to Zendesk to Re:amaze Data Migration
A Guideline to Zendesk to Re:amaze Data MigrationA Guideline to Zendesk to Re:amaze Data Migration
A Guideline to Zendesk to Re:amaze Data MigrationHelp Desk Migration
 
Workforce Efficiency with Employee Time Tracking Software.pdf
Workforce Efficiency with Employee Time Tracking Software.pdfWorkforce Efficiency with Employee Time Tracking Software.pdf
Workforce Efficiency with Employee Time Tracking Software.pdfDeskTrack
 
Entropy, Software Quality, and Innovation (presented at Princeton Plasma Phys...
Entropy, Software Quality, and Innovation (presented at Princeton Plasma Phys...Entropy, Software Quality, and Innovation (presented at Princeton Plasma Phys...
Entropy, Software Quality, and Innovation (presented at Princeton Plasma Phys...Andrea Goulet
 
how-to-download-files-safely-from-the-internet.pdf
how-to-download-files-safely-from-the-internet.pdfhow-to-download-files-safely-from-the-internet.pdf
how-to-download-files-safely-from-the-internet.pdfMehmet Akar
 
IT Software Development Resume, Vaibhav jha 2024
IT Software Development Resume, Vaibhav jha 2024IT Software Development Resume, Vaibhav jha 2024
IT Software Development Resume, Vaibhav jha 2024vaibhav130304
 
Malaysia E-Invoice digital signature docpptx
Malaysia E-Invoice digital signature docpptxMalaysia E-Invoice digital signature docpptx
Malaysia E-Invoice digital signature docpptxMok TH
 
A Python-based approach to data loading in TM1 - Using Airflow as an ETL for TM1
A Python-based approach to data loading in TM1 - Using Airflow as an ETL for TM1A Python-based approach to data loading in TM1 - Using Airflow as an ETL for TM1
A Python-based approach to data loading in TM1 - Using Airflow as an ETL for TM1KnowledgeSeed
 
10 Essential Software Testing Tools You Need to Know About.pdf
10 Essential Software Testing Tools You Need to Know About.pdf10 Essential Software Testing Tools You Need to Know About.pdf
10 Essential Software Testing Tools You Need to Know About.pdfkalichargn70th171
 
Mastering Windows 7 A Comprehensive Guide for Power Users .pdf
Mastering Windows 7 A Comprehensive Guide for Power Users .pdfMastering Windows 7 A Comprehensive Guide for Power Users .pdf
Mastering Windows 7 A Comprehensive Guide for Power Users .pdfmbmh111980
 
Crafting the Perfect Measurement Sheet with PLM Integration
Crafting the Perfect Measurement Sheet with PLM IntegrationCrafting the Perfect Measurement Sheet with PLM Integration
Crafting the Perfect Measurement Sheet with PLM IntegrationWave PLM
 
Automate your OpenSIPS config tests - OpenSIPS Summit 2024
Automate your OpenSIPS config tests - OpenSIPS Summit 2024Automate your OpenSIPS config tests - OpenSIPS Summit 2024
Automate your OpenSIPS config tests - OpenSIPS Summit 2024Andreas Granig
 
Modern binary build systems - PyCon 2024
Modern binary build systems - PyCon 2024Modern binary build systems - PyCon 2024
Modern binary build systems - PyCon 2024Henry Schreiner
 
architecting-ai-in-the-enterprise-apis-and-applications.pdf
architecting-ai-in-the-enterprise-apis-and-applications.pdfarchitecting-ai-in-the-enterprise-apis-and-applications.pdf
architecting-ai-in-the-enterprise-apis-and-applications.pdfWSO2
 
AI/ML Infra Meetup | ML explainability in Michelangelo
AI/ML Infra Meetup | ML explainability in MichelangeloAI/ML Infra Meetup | ML explainability in Michelangelo
AI/ML Infra Meetup | ML explainability in MichelangeloAlluxio, Inc.
 
Microsoft 365 Copilot; An AI tool changing the world of work _PDF.pdf
Microsoft 365 Copilot; An AI tool changing the world of work _PDF.pdfMicrosoft 365 Copilot; An AI tool changing the world of work _PDF.pdf
Microsoft 365 Copilot; An AI tool changing the world of work _PDF.pdfQ-Advise
 
GraphSummit Stockholm - Neo4j - Knowledge Graphs and Product Updates
GraphSummit Stockholm - Neo4j - Knowledge Graphs and Product UpdatesGraphSummit Stockholm - Neo4j - Knowledge Graphs and Product Updates
GraphSummit Stockholm - Neo4j - Knowledge Graphs and Product UpdatesNeo4j
 
The Impact of PLM Software on Fashion Production
The Impact of PLM Software on Fashion ProductionThe Impact of PLM Software on Fashion Production
The Impact of PLM Software on Fashion ProductionWave PLM
 
StrimziCon 2024 - Transition to Apache Kafka on Kubernetes with Strimzi.pdf
StrimziCon 2024 - Transition to Apache Kafka on Kubernetes with Strimzi.pdfStrimziCon 2024 - Transition to Apache Kafka on Kubernetes with Strimzi.pdf
StrimziCon 2024 - Transition to Apache Kafka on Kubernetes with Strimzi.pdfsteffenkarlsson2
 

Kürzlich hochgeladen (20)

Top Mobile App Development Companies 2024
Top Mobile App Development Companies 2024Top Mobile App Development Companies 2024
Top Mobile App Development Companies 2024
 
AI Hackathon.pptx
AI                        Hackathon.pptxAI                        Hackathon.pptx
AI Hackathon.pptx
 
A Guideline to Zendesk to Re:amaze Data Migration
A Guideline to Zendesk to Re:amaze Data MigrationA Guideline to Zendesk to Re:amaze Data Migration
A Guideline to Zendesk to Re:amaze Data Migration
 
Workforce Efficiency with Employee Time Tracking Software.pdf
Workforce Efficiency with Employee Time Tracking Software.pdfWorkforce Efficiency with Employee Time Tracking Software.pdf
Workforce Efficiency with Employee Time Tracking Software.pdf
 
Entropy, Software Quality, and Innovation (presented at Princeton Plasma Phys...
Entropy, Software Quality, and Innovation (presented at Princeton Plasma Phys...Entropy, Software Quality, and Innovation (presented at Princeton Plasma Phys...
Entropy, Software Quality, and Innovation (presented at Princeton Plasma Phys...
 
how-to-download-files-safely-from-the-internet.pdf
how-to-download-files-safely-from-the-internet.pdfhow-to-download-files-safely-from-the-internet.pdf
how-to-download-files-safely-from-the-internet.pdf
 
IT Software Development Resume, Vaibhav jha 2024
IT Software Development Resume, Vaibhav jha 2024IT Software Development Resume, Vaibhav jha 2024
IT Software Development Resume, Vaibhav jha 2024
 
Malaysia E-Invoice digital signature docpptx
Malaysia E-Invoice digital signature docpptxMalaysia E-Invoice digital signature docpptx
Malaysia E-Invoice digital signature docpptx
 
A Python-based approach to data loading in TM1 - Using Airflow as an ETL for TM1
A Python-based approach to data loading in TM1 - Using Airflow as an ETL for TM1A Python-based approach to data loading in TM1 - Using Airflow as an ETL for TM1
A Python-based approach to data loading in TM1 - Using Airflow as an ETL for TM1
 
10 Essential Software Testing Tools You Need to Know About.pdf
10 Essential Software Testing Tools You Need to Know About.pdf10 Essential Software Testing Tools You Need to Know About.pdf
10 Essential Software Testing Tools You Need to Know About.pdf
 
Mastering Windows 7 A Comprehensive Guide for Power Users .pdf
Mastering Windows 7 A Comprehensive Guide for Power Users .pdfMastering Windows 7 A Comprehensive Guide for Power Users .pdf
Mastering Windows 7 A Comprehensive Guide for Power Users .pdf
 
Crafting the Perfect Measurement Sheet with PLM Integration
Crafting the Perfect Measurement Sheet with PLM IntegrationCrafting the Perfect Measurement Sheet with PLM Integration
Crafting the Perfect Measurement Sheet with PLM Integration
 
Automate your OpenSIPS config tests - OpenSIPS Summit 2024
Automate your OpenSIPS config tests - OpenSIPS Summit 2024Automate your OpenSIPS config tests - OpenSIPS Summit 2024
Automate your OpenSIPS config tests - OpenSIPS Summit 2024
 
Modern binary build systems - PyCon 2024
Modern binary build systems - PyCon 2024Modern binary build systems - PyCon 2024
Modern binary build systems - PyCon 2024
 
architecting-ai-in-the-enterprise-apis-and-applications.pdf
architecting-ai-in-the-enterprise-apis-and-applications.pdfarchitecting-ai-in-the-enterprise-apis-and-applications.pdf
architecting-ai-in-the-enterprise-apis-and-applications.pdf
 
AI/ML Infra Meetup | ML explainability in Michelangelo
AI/ML Infra Meetup | ML explainability in MichelangeloAI/ML Infra Meetup | ML explainability in Michelangelo
AI/ML Infra Meetup | ML explainability in Michelangelo
 
Microsoft 365 Copilot; An AI tool changing the world of work _PDF.pdf
Microsoft 365 Copilot; An AI tool changing the world of work _PDF.pdfMicrosoft 365 Copilot; An AI tool changing the world of work _PDF.pdf
Microsoft 365 Copilot; An AI tool changing the world of work _PDF.pdf
 
GraphSummit Stockholm - Neo4j - Knowledge Graphs and Product Updates
GraphSummit Stockholm - Neo4j - Knowledge Graphs and Product UpdatesGraphSummit Stockholm - Neo4j - Knowledge Graphs and Product Updates
GraphSummit Stockholm - Neo4j - Knowledge Graphs and Product Updates
 
The Impact of PLM Software on Fashion Production
The Impact of PLM Software on Fashion ProductionThe Impact of PLM Software on Fashion Production
The Impact of PLM Software on Fashion Production
 
StrimziCon 2024 - Transition to Apache Kafka on Kubernetes with Strimzi.pdf
StrimziCon 2024 - Transition to Apache Kafka on Kubernetes with Strimzi.pdfStrimziCon 2024 - Transition to Apache Kafka on Kubernetes with Strimzi.pdf
StrimziCon 2024 - Transition to Apache Kafka on Kubernetes with Strimzi.pdf
 

HTMX: Web 1.0 with the benefits of Web 2.0 without the grift of Web 3.0

  • 1. HTMX: WEB 1.0 WITH WEB 2.0 BENEFITS WITHOUT THE GRIFT OF WEB 3.0 MARTIJN DASHORST # jfall.
  • 2. WHO HAS HEARD OF HTMX BEFORE THIS TALK?
  • 3. WHO HAS HEARD OF INTERCOOLER TURBOLINKS, OR HOTWIRE?
  • 4. HTMX is an old idea that's getting a lot of new attention — @bholmesdev
  • 5.
  • 11. HERE WE ARE I THOUGHT IT WAS A GOOD IDEA TO PITCH A PRESENTATION FOR JFALL ABOUT HTMX TO GET TO KNOW IT BETTER. SO...
  • 12. MARTIJN DASHORST ● 18 YEARS @TOPICUS PARNASSYS, PARRO, SOMTODAY, EDUARTE SPREEKUUR.NL, DARMKANKER SCREENING, CORONATEST.NL, FORCE (MORTGAGES) ● BACKEND DEVELOPER BY HEART ● LOVES CREATING FIXING LEGACY SOFTWARE ● CONTRIBUTOR APACHE WICKET ● CO-AUTHORED WICKET IN ACTION
  • 13. WHY HTMX? HTMX = WEB 1.0 + WEB 2.0 - WEB 3.0 01 04 02 05 03 WHAT IS HTMX? HOW DOES IT WORK? DEMOS CONCLUSIONS
  • 14. HTMX https://htmx.org intercooler 2013-2020 14kb JavaScript library (gzipped) - no dependencies - no build - attributes - css classes - request/response headers - events - extensions - javascript API
  • 15. HTMX https://htmx.org version 1.9.8 (Nov 6, 2023) 14kb JavaScript library (gzipped) - no dependencies - no build - attributes - css classes - request/response headers - events - extensions - javascript API <script src="htmx.js"></script>
  • 16. HTMX https://htmx.org version 1.9.8 (Nov 6, 2023) 14kb JavaScript library (gzipped) - no dependencies - no build - attributes - css classes - request/response headers - events - extensions - javascript API <script src="htmx.js"></script> <button hx-get="/counter" hx-swap="outerHTML"> Click me</button>
  • 17. HTMX https://htmx.org version 1.9.8 (Nov 6, 2023) 14kb JavaScript library (gzipped) - no dependencies - no build - attributes - css classes - request/response headers - events - extensions - javascript API <script src="htmx.js"></script> <button hx-get="/counter" hx-swap="outerHTML" hx-indicator="#indicator" >Click me</button> <i id="indicator" class="htmx-indicator spinner-border"> </i>
  • 18. By Carson Gross https://bigsky.software A Return to Hypermedia – "Curing Your JavaScript Fatigue Using The Original Architecture Of The Web" htmx: Writing JavaScript to Avoid Writing JavaScript HTMx: Building modern web applications without JS HTMX
  • 19. one day code base understandable and grug can get work done, everything good! next day impossible: complexity demon spirit has entered code and very dangerous situation! — https://grugbrain.dev/
  • 20. WHY HTMX? HTMX = WEB 1.0 + WEB 2.0 - WEB 3.0 01 04 02 05 03 WHAT IS HTMX? HOW DOES IT WORK? DEMOS CONCLUSIONS
  • 21. BUILDING A REST API FOR A WEB PORTAL AND NATIVE APP MY EXPERIENCES REST server xml html xml
  • 22. BUILDING A REST API FOR A WEB PORTAL MY EXPERIENCES
  • 23. BUILDING A REST API FOR A WEB PORTAL MY EXPERIENCES data format for API: JSON or XML
  • 24. BUILDING A REST API FOR A WEB PORTAL MY EXPERIENCES data format for API: JSON or XML POST or PUT?
  • 25. BUILDING A REST API FOR A WEB PORTAL MY EXPERIENCES data format for API: JSON or XML caching the resources POST or PUT?
  • 26. BUILDING A REST API FOR A WEB PORTAL MY EXPERIENCES data format for API: JSON or XML caching the resources paging of results POST or PUT?
  • 27. BUILDING A REST API FOR A WEB PORTAL MY EXPERIENCES data format for API: JSON or XML versioning the API caching the resources paging of results POST or PUT?
  • 28. BUILDING A REST API FOR A WEB PORTAL MY EXPERIENCES data format for API: JSON or XML versioning the API caching the resources paging of results POST or PUT? POST to /resource or / resource/new ?
  • 29. BUILDING A REST API FOR A WEB PORTAL MY EXPERIENCES data format for API: JSON or XML versioning the API caching the resources paging of results POST or PUT? POST to /resource or / resource/new ? Links between resources?
  • 30. BUILDING A REST API FOR A WEB PORTAL MY EXPERIENCES data format for API: JSON or XML versioning the API caching the resources paging of results POST or PUT? POST to /resource or / resource/new ? Links between resources? Complex UIs, more generic REST resources, God Objects
  • 33.
  • 34. Dear Roy, What is the best practice for versioning a REST API?
  • 35. DON'T — Roy T. Fielding Dear Roy, What is the best practice for versioning a REST API? https:/ /www.slideshare.net/evolve_conference/201308-fielding-evolve#31
  • 36. Dear Roy, What is the best practice for versioning a REST API? https:/ /www.slideshare.net/evolve_conference/201308-fielding-evolve#31 when you use hypertext as the engine of application state, you don't need it — Roy T. Fielding
  • 37. SPA architecture = JSON + RPC "REST"
  • 38. SPA architecture = JSON + RPC "REST" WHY?
  • 39. WHY CAN ONLY <A> AND <FORM> PERFORM THOSE REQUESTS? WHY ONLY GET & POST REQUESTS?
  • 42. WHY HTMX? HTMX = WEB 1.0 + WEB 2.0 - WEB 3.0 01 04 02 05 03 WHAT IS HTMX? HOW DOES IT WORK? DEMOS CONCLUSIONS
  • 43. HOW DOES IT WORK? Any HTML element can interact as an hypermedia component
  • 44. HOW DOES IT WORK? Any HTML element can interact as an hypermedia component credit: @htmx.org@twitter https:/ /twitter.com/htmx_org/status/1700259958405869711
  • 45. HOW DOES IT WORK? Any HTML element can interact as an hypermedia component <button class="btn btn-success" onclick=" const req = new XMLHttpRequest(); req.onload = (e) => { const admin = document.getElementById('admin'); const newAdmin = req.responseXML.getElementById('admin'); admin.innerHTML = newAdmin.innerHTML; }; req.responseType = 'document'; req.open('GET', '/admin'); req.overrideMimeType('text/html'); req.send();" >Click me</button> <section id="admin"></section>
  • 46. HOW DOES IT WORK? Any HTML element can interact as an hypermedia component <button class="btn btn-primary" hx-get="/admin" hx-select="#admin" hx-target="#admin" >Click me</button> <section id="admin"></section>
  • 47. GETTING THE SCRIPT <script src="https://unpkg.com/htmx.org@1.9.7"></script> Quick and dirty
  • 48. TIP: USE WEBJARS i Using webjars <dependency> <groupId>org.webjars.npm</groupId> <artifactId>htmx.org</artifactId> <version>1.9.7</version> </dependency> <script src="/webjars/htmx.org/1.9.7/dist/htmx.js"></script> /META-INF/resources/webjars «classpath» SEE ALSO: https:/ /www.baeldung.com/maven-webjars
  • 49. TIP: WEBJARS + LOCATOR i Spring <dependency> <groupId>org.webjars</groupId> <artifactId>webjars-locator</artifactId> <version>0.48</version> </dependency> <script src="/webjars/htmx.org/dist/htmx.js"></script> no version Quarkus quarkus ext add io.quarkus:quarkus-webjars-locator SEE ALSO: https:/ /www.baeldung.com/maven-webjars
  • 50. HOW DOES IT WORK? Any HTML element can interact as an hypermedia component Attributes instruct HTMX what to do with what element
  • 51. HOW DOES IT WORK? Any HTML element can interact as an hypermedia component Attributes instruct HTMX what to do with what element hx-boost="true|false" hx-get="/count" hx-post="/count" hx-target="#counter" hx-swap="innerHTML|outerHTML|afterend|..." hx-trigger="click|load|every 1s" hx-select="#htmx-badge" hx-swap-oob="true|outerHTML:selector" hx-delete|patch|put="/url" ...
  • 52. ATTRIBUTES – hx-boost <nav hx-boost="true"> <li><a href="/menu1">Menu 1</a></li> <li><a href="/menu2">Menu 2</a></li> <li><a href="/menu3">Menu 3</a></li> <li><a href="/menu4">Menu 4</a></li> </nav> Replaces the GET/POST request using AJAX and replaces the body using innerHTML swap. inherited
  • 53. ATTRIBUTES – hx-get <button hx-get="/speaker/1">Get speaker 1</button> Issue a GET request to the specified URL and swap the returned HTML into the DOM using a swap strategy
  • 54. ATTRIBUTES – hx-get <button hx-get="/speaker/1">Get speaker 1</button> Issue a GET request to the specified URL and swap the returned HTML into the DOM using a swap strategy
  • 55. ATTRIBUTES – hx-get <button hx-get="/speaker/1">Get speaker 1</button> Issue a GET request to the specified URL and swap the returned HTML into the DOM using a swap strategy <div id="speaker">...</div>
  • 56. ATTRIBUTES – hx-get <button hx-get="/speaker/1">Get speaker 1</button> Issue a GET request to the specified URL and swap the returned HTML into the DOM using a swap strategy <div id="speaker">...</div> <button hx-get="/speaker/1"> Get speaker 1 </button>
  • 57. ATTRIBUTES – hx-get <button hx-get="/speaker/1">Get speaker 1</button> Issue a GET request to the specified URL and swap the returned HTML into the DOM using a swap strategy <div id="speaker">...</div> <button hx-get="/speaker/1"> <div id="speaker">...</div> </button>
  • 58. ATTRIBUTES – hx-swap <button hx-get="/speaker/1" hx-swap="outerHTML">Get speaker 1</button> Controls how the HTML is swapped into the DOM. innerHTML, outerHTML, beforebegin, afterbegin, beforeend, afterend, delete, none <div id="speaker">...</div> <button hx-get="/speaker/1" hx-swap="outerHTML">Get speaker 1</button> inherited
  • 59. ATTRIBUTES – hx-swap <button hx-get="/speaker/1" hx-swap="outerHTML">Get speaker 1</button> Controls how the HTML is swapped into the DOM. innerHTML, outerHTML, beforebegin, afterbegin, beforeend, afterend, delete, none <div id="speaker">...</div> <div id="speaker">...</div>
  • 60. ATTRIBUTES – hx-target Controls which element in the DOM gets swapped with the returned HTML using a swapping strategy. inherited <button hx-get="/speaker/1" hx-swap="outerHTML" hx-target="#speaker">Get speaker 1</button> <div id="speaker">No content</div>
  • 61. ATTRIBUTES – hx-target Controls which element in the DOM gets swapped with the returned HTML using a swapping strategy. inherited <button hx-get="/speaker/1" hx-swap="outerHTML" hx-target="#speaker">Get speaker 1</button> <div id="speaker">No content</div> <div id="speaker">Johan Janssen</div> <div id="speaker">No content</div>
  • 62. ATTRIBUTES – hx-target Controls which element in the DOM gets swapped with the returned HTML using a swapping strategy. inherited <button hx-get="/speaker/1" hx-swap="outerHTML" hx-target="#speaker">Get speaker 1</button> <div id="speaker">No content</div> <div id="speaker" class="card">Johan Janssen</div> <div id="speaker">No content</div>
  • 63. ATTRIBUTES – hx-target Controls which element in the DOM gets swapped with the returned HTML using a swapping strategy. inherited <button hx-get="/speaker/1" hx-swap="outerHTML" hx-target="#speaker">Get speaker 1</button> <div id="speaker">No content</div> <div id="speaker" class="card">Johan Janssen</div> <div id="speaker" class="card">Johan Janssen</div>
  • 64. ATTRIBUTES – hx-target Inherited??? inherited <menu> <a hx-get="/speaker/1" hx-target="#speaker">Get speaker 1 <a hx-get="/speaker/2" hx-target="#speaker">Get speaker 2 <a hx-get="/speaker/3" hx-target="#speaker">Get speaker 3 <a hx-get="/speaker/4" hx-target="#speaker">Get speaker 4 </menu>
  • 65. ATTRIBUTES – hx-target hx-target is inherited and can be placed on a parent element. inherited <menu hx-target="#speaker"> <a hx-get="/speaker/1">Get speaker 1</a> <a hx-get="/speaker/2">Get speaker 2</a> <a hx-get="/speaker/3">Get speaker 3</a> <a hx-get="/speaker/4">Get speaker 4</a> </menu>
  • 66. MORE ABOUT ATTRIBUTES INHERITED ATTRIBUTES NO JAVASCRIPT REQ'D Removes repetition of common attributes, such as the target, swap method, selecting elements etc. Can be overridden by hx-disinherit With just the tags you can create rich dynamically updating pages. Slap on some attributes and continue. In the HTML response you can add more updates by using out-of-band swaps (hx-swap-oob) UPDATE MULTIPLE ELEMENTS
  • 67. HOW DOES IT WORK? Any HTML element can interact as an hypermedia component Attributes instruct HTMX what to do with what element Server may need to distinguish between normal and HTMX request: Headers
  • 68. HX-Request always true HX-Boosted indicates hx-boost request HX-Current-URL ... ... REQUEST HEADERS RESPONSE HEADERS HX-Redirect client-side redirect HX-Refresh client-side full refresh of the page HX-Retarget modify the hx-target HX-Trigger trigger client-side events ... HOW DOES IT WORK – HEADERS Convenient for deciding to return a partial or a full page DETECT HTMX REQUEST MODIFY REQUESTS Change the target, or swapping mechanism, send a redirect or replace the URL in the location bar. And more.
  • 69. HOW DOES IT WORK? Any HTML element can interact as an hypermedia component Attributes instruct HTMX what to do with what element Server may need to distinguish between normal and HTMX request: Headers When a HTMX request is in flight, feedback is wanted for Users: classes
  • 70. htmx-indicator toggles visibility (opacity:1) htmx-request applied to hx-indicator during request htmx-added htmx-swapping htmx-settling CLASSES HOW DOES IT WORK – CLASSES Convenient for deciding to return a partial or a full page INDICATOR ANIMATIONS Animate swapping of elements for a more rich experience.
  • 71. HOW DOES IT WORK? Any HTML element can interact as an hypermedia component Attributes instruct HTMX what to do with what element Server may need to distinguish between normal and HTMX request: Headers When a HTMX request is in flight, feedback is wanted for Users: classes Complex needs for reacting to interactions, swapping, requests & responses: events
  • 72. HOW DOES IT WORK? – EVENTS htmx:abort htmx:afterOnLoad htmx:afterProcessNode htmx:afterRequest htmx:afterSettle htmx:afterSwap htmx:beforeCleanupElement htmx:beforeOnLoad htmx:beforeProcessNode htmx:beforeRequest htmx:beforeSwap htmx:beforeSend htmx:configRequest htmx:confirm htmx:historyCacheError htmx:historyCacheMiss htmx:historyCacheMissError htmx:historyCacheMissLoad htmx:historyRestore htmx:beforeHistorySave htmx:load htmx:noSSESourceError htmx:onLoadError htmx:oobAfterSwap htmx:oobBeforeSwap htmx:oobErrorNoTarget htmx:prompt htmx:pushedIntoHistory htmx:responseError htmx:sendError htmx:sseError htmx:sseOpen htmx:swapError htmx:targetError htmx:timeout htmx:validation:validate htmx:validation:failed htmx:validation:halted htmx:xhr:abort htmx:xhr:loadend htmx:xhr:loadstart htmx:xhr:progress
  • 73. HOW DOES IT WORK? – EVENTS before/after swaps occurred, after DOM has settled, out-of-bounds swaps, etc. Anything relevant to modifying using the history API The lifecycle of the XHR request: progress, loadend, loadstart, etc. Errors sending a request, receiving a response, targetting an element, etc. SWAPPING HISTORY VALIDATION Triggered when client side validation is performed, failed. Configure the request before it is sent to the server, response processing XHR ERRORS REQUESTS
  • 74. HOW DOES IT WORK? Any HTML element can interact as an hypermedia component Attributes instruct HTMX what to do with what element Server may need to distinguish between normal and HTMX request: Headers When a HTMX request is in flight, feedback is wanted for Users: classes Complex needs for reacting to interactions, swapping, requests & responses: events In the events some annoying JavaScript needs to be executed (e.g. add class): JavaScript library
  • 75. FINDING ELEMENTS HOW DOES IT WORK? – JAVASCRIPT addClass(), removeClass(), toggleClass(), takeClass() remove(), values() EVENTS ON ELEMENTS on(), off(), trigger() closest(), find(), findAll() config, ajax(), process() defineExtension(), removeExtension() WORKING WITH CLASSES WORKING WITH ELEMENTS INTERNALS & EXTENSIONS
  • 76. HOW DOES IT WORK? – JAVASCRIPT Documents Projects Members Admin Gangplank lookout killick jack yo-ho-ho Sea Legs yard marooned interloper yawl. Gabion fire ship Brethren of the Coast lanyard chase Cat o'nine tails dead men tell no tales barque yawl Nelsons folly. <ul class="list-group" hx-target="#content" hx-on::after-request="htmx.takeClass(event.detail.elt, 'active')"> <li class="list-group-item" hx-get="/sub/Documents">Documents</li> <li class="list-group-item" hx-get="/sub/Projects">Projects</li> <li class="list-group-item" hx-get="/sub/Members">Members</li> <li class="list-group-item" hx-get="/sub/Admin">Admin</li> </ul> <section id="content"></section>
  • 77. HOW DOES IT WORK? Any HTML element can interact as an hypermedia component Attributes instruct HTMX what to do with what element Server may need to distinguish between normal and HTMX request: Headers When a HTMX request is in flight, feedback is wanted for Users: classes Complex needs for reacting to interactions, swapping, requests & responses: events In the events some annoying JavaScript needs to be executed (e.g. add class): JavaScript library We need to use a different HTML morphing algo, serverside sent events or web sockets: extensions
  • 78. FINALLY HATEOAS? HTMX = WEB 1.0 + WEB 2.0 - WEB 3.0 01 04 02 05 03 WHAT IS HTMX? HOW DOES IT WORK? DEMOS CONCLUSIONS
  • 81. fun with flags ● quarkus ● qute ● websockets ● htmx ● htmx-ws ● bootstrap ● flag=icons github.com/dashorst/funwithflags
  • 82.
  • 83.
  • 84. WEBSOCKETS FTW! @ServerEndpoint("/game/{player}") public class FunWithFlagsWebSocket { @OnOpen public void onOpen(Session session, @PathParam("player") String encodedPlayer) { var player = URLDecoder.decode(encodedPlayer, StandardCharsets.UTF_8); sessions.put(player, session); funWithFlagsGame.registerPlayer(session, player); }
  • 85. WEBSOCKETS FTW! @ServerEndpoint("/game/{player}") public class FunWithFlagsWebSocket { @OnOpen public void onOpen(Session session, @PathParam("player") String encodedPlayer) { var player = URLDecoder.decode(encodedPlayer, StandardCharsets.UTF_8); sessions.put(player, session); funWithFlagsGame.registerPlayer(session, player); } <div id="game" hx-ext="ws" ws-connect="/game/{playername}" class="row"> <div class="col-12 text-center"> <h3>Joining lobby...</h3> {#fragment id=lobby} <ul class="list-group" id="lobby-list"> {#for player in players} <li class="list-group-item {#if player.name == playername} list-group- {/for} </ul> {/fragment} <p>Waiting for other players to join!</p> </div> </div>
  • 86. WEBSOCKETS FTW! @ServerEndpoint("/game/{player}") public class FunWithFlagsWebSocket { @OnOpen public void onOpen(Session session, @PathParam("player") String encodedPlayer) { var player = URLDecoder.decode(encodedPlayer, StandardCharsets.UTF_8); sessions.put(player, session); funWithFlagsGame.registerPlayer(session, player); } <div id="game" hx-ext="ws" ws-connect="/game/{playername}" class="row"> <div class="col-12 text-center"> <h3>Joining lobby...</h3> {#fragment id=lobby} <ul class="list-group" id="lobby-list"> {#for player in players} <li class="list-group-item {#if player.name == playername} list-group- {/for} </ul> {/fragment} <p>Waiting for other players to join!</p> </div> </div> hx-ext="ws" ws-connect="/game/{playername}" @ServerEndpoint("/game/{player}") @OnOpen public void onOpen(Session session, @PathParam("player")
  • 87. SENDING TURN START TO PLAYERS public void onTurnStarted(@Observes TurnStarted event) { var game = event.game(); var turn = event.turn(); var countryToGuess = turn.countryToGuess(); for (Player player : game.players()) { var turnHtml = Templates.game$turnPartial(player, game, turn, countryToGuess) .render(); var rankHtml = Templates.game$rankingPartial(player, game, turn).render(); player.session().getAsyncRemote().sendObject(turnHtml + "n" + rankHtml); } } <div id="turn" class="col-12 col-lg-6 offset-lg-3"> <h2>Round {game.turnNumber} of {game.numberOfTurns}</h2> ... </div> <div id="in-game-ranking" class="col-12 col-md-3"> <h3>Ranking round {game.turnNumber}</h3> ... </div>
  • 88. SENDING TURN START TO PLAYERS public void onTurnStarted(@Observes TurnStarted event) { var game = event.game(); var turn = event.turn(); var countryToGuess = turn.countryToGuess(); for (Player player : game.players()) { var turnHtml = Templates.game$turnPartial(player, game, turn, countryToGuess) .render(); var rankHtml = Templates.game$rankingPartial(player, game, turn).render(); player.session().getAsyncRemote().sendObject(turnHtml + "n" + rankHtml); } } <div id="turn" class="col-12 col-lg-6 offset-lg-3"> <h2>Round {game.turnNumber} of {game.numberOfTurns}</h2> ... </div> <div id="in-game-ranking" class="col-12 col-md-3"> <h3>Ranking round {game.turnNumber}</h3> ... </div>
  • 89. SENDING TURN START TO PLAYERS public void onTurnStarted(@Observes TurnStarted event) { var game = event.game(); var turn = event.turn(); var countryToGuess = turn.countryToGuess(); for (Player player : game.players()) { var turnHtml = Templates.game$turnPartial(player, game, turn, countryToGuess) .render(); var rankHtml = Templates.game$rankingPartial(player, game, turn).render(); player.session().getAsyncRemote().sendObject(turnHtml + "n" + rankHtml); } } <div id="turn" class="col-12 col-lg-6 offset-lg-3"> <h2>Round {game.turnNumber} of {game.numberOfTurns}</h2> ... </div> <div id="in-game-ranking" class="col-12 col-md-3"> <h3>Ranking round {game.turnNumber}</h3> ... </div>
  • 90. SENDING TURN START TO PLAYERS public void onTurnStarted(@Observes TurnStarted event) { var game = event.game(); var turn = event.turn(); var countryToGuess = turn.countryToGuess(); for (Player player : game.players()) { var turnHtml = Templates.game$turnPartial(player, game, turn, countryToGuess) .render(); var rankHtml = Templates.game$rankingPartial(player, game, turn).render(); player.session().getAsyncRemote().sendObject(turnHtml + "n" + rankHtml); } } <div id="turn" class="col-12 col-lg-6 offset-lg-3"> <h2>Round {game.turnNumber} of {game.numberOfTurns}</h2> ... </div> <div id="in-game-ranking" class="col-12 col-md-3"> <h3>Ranking round {game.turnNumber}</h3> ... </div>
  • 91. SENDING TURN START TO PLAYERS public void onTurnStarted(@Observes TurnStarted event) { var game = event.game(); var turn = event.turn(); var countryToGuess = turn.countryToGuess(); for (Player player : game.players()) { var turnHtml = Templates.game$turnPartial(player, game, turn, countryToGuess) .render(); var rankHtml = Templates.game$rankingPartial(player, game, turn).render(); player.session().getAsyncRemote().sendObject(turnHtml + "n" + rankHtml); } } <div id="turn" class="col-12 col-lg-6 offset-lg-3"> <h2>Round {game.turnNumber} of {game.numberOfTurns}</h2> ... </div> <div id="in-game-ranking" class="col-12 col-md-3"> <h3>Ranking round {game.turnNumber}</h3> ... </div>
  • 92. DEMO
  • 93. FINALLY HATEOAS? HTMX = WEB 1.0 + WEB 2.0 - WEB 3.0 01 04 02 05 03 WHAT IS HTMX? HOW DOES IT WORK? DEMOS CONCLUSIONS
  • 94. BACKEND DEVS REJOICE HTMX: WEB 1.0 + WEB 2.0 - WEB 3.0 No more general APIs between your user interface and your back end. Use hypermedia as the engine for your application state Hypermedia On Whatever You'd Like. Backend agnostic! Spring Boot, Quarkus, JSP, PHP, DJango, Ruby on Rails, ... HTMX allows you to build rich front ends without having to learn rich front end technologies. Just one script tag and your back end. Written in whatever you'd like. REST WITH HATEOAS HOWL STACK REDUCE THE CHURN
  • 95. It took me ~2 months spare time to write Fun with Flags, but most of that time was spent figuring out the game mechanics, not HTMX integration. 9/10, would use again1 1 (already using it in other projects)
  • 96. HTMX.ORG https://htmx.org Great documentation, examples and essays on the fundamentals of HTMX and hypermedia. WARNING Also memes
  • 97. HYPERMEDIA SYSTEMS https://hypermedia.systems Best explanation of Hypermedia, REST, RESTFUL and HATEOAS. WARNING Risk of wanting to use HTMX after reading
  • 99. CREDITS: This presentation template was created by Slidesgo, and includes icons by Flaticon, and infographics & images by Freepik THANKS! Do you have any questions? martijn.dashorst@topicus.nl @dashorst@mastodon.social martijndashorst.com CREDITS HTMX was conceived by Carson Gross Title "HTMX: WEB 1.0 WITH WEB 2.0 BENEFITS WITHOUT THE GRIFT OF WEB 3.0" was inspired by The Primagen Template by slidesgo and includes images from flaticon and icons from freepik
  • 100. Thanks for your attention Please rate my session in the J-Fall app # jfall. fun-with-flags.eduarte.dev HTMX: web 1.0 + web 2.0 - web 3.0 Martijn Dashorst topicus