...~~run anywhere~~.
--
# Learn once...
## ...write anywhere.
## ...~~run anywhere~~.
-- code
# Hello React
```javascript
const application = (
Hello world
);
const container = document.getElementById("root");
ReactDOM.render(application, container);
```
-- code threeway threeway-1
```javascript
// JSX
Hello world
```
```javascript
// Transpiled
React.createElement(
"h1",
{
title: "Hi!"
},
"Hello world"
)
```
```javascript
// Runtime: a React element
{
type: "h1",
props: {
title: "Hi!",
children: "Hello world",
},
}
```
-- code threeway threeway-2
```javascript
// JSX
Hello world
```
```javascript
// Transpiled
React.createElement(
"h1",
{
title: "Hi!"
},
"Hello world"
)
```
```javascript
// Runtime: a React element
{
type: "h1",
props: {
title: "Hi!",
children: "Hello world",
},
}
```
-- code threeway threeway-3
```javascript
// JSX
Hello world
```
```javascript
// Transpiled
React.createElement(
"h1",
{
title: "Hi!"
},
"Hello world"
)
```
```javascript
// Runtime: a React element
{
type: "h1",
props: {
title: "Hi!",
children: "Hello world",
},
}
```
-- code
# Anatomy of a React element
```javascript
{
type: "h1", // Component
props: {
title: "Hi!", // "Attributes"
children: "Hello world", // "Nested" stuff
},
}
```
-- code
# React rendering (ultra-oversimplified ^_^U)
```javascript
// ReactDOM.render(application, container);
function render(element, container) {
const node = document.createElement(element.type);
node.title = element.props.title;
node.innerText = element.children;
container.appendChild(node);
}
```
--
# Host Components
## Building blocks.
## Platform specific.
## DOM: div, span, h1, a, etc.
--
# Composite Components
## Abstraction.
## Code reuse.
## a.k.a Custom Components.
-- code
# Composite Components: abstraction & code reuse
```javascript
// This is a Component
function HelloWorld(props) {
return Hello world
;
}
```
-- code
# Composite Components: abstraction & code reuse
```javascript
// This is a Component
function HelloWorld(props) {
return Hello world
;
}
const application = (
);
const container = document.getElementById("root");
ReactDOM.render(application, container);
```
-- code
# Composite Components: composition
```javascript
// This is a Component
function Heading(props) {
return {props.children}
;
};
```
-- code
# Composite Components: composition
```javascript
// This is a Component
function Heading(props) {
return {props.children}
;
};
// This is another Component
function NiceText(props) {
return 🌻{props.children}🌻;
};
```
-- code
# Composite Components: composition
```javascript
// This is a Component
function Heading(props) {
return {props.children}
;
};
// This is another Component
function NiceText(props) {
return 🌻{props.children}🌻;
};
// Even the app is a Component!
function Application() {
return (
Hello world
);
};
```
-- code
# Composite Components: composition
```javascript
// This is a Component
function Heading(props) {
return {props.children}
;
};
// This is another Component
function NiceText(props) {
return 🌻{props.children}🌻;
};
// Even the app is a Component!
function Application() {
return (
Hello world
);
};
const container = document.getElementById("root");
ReactDOM.render(, container);
```
-- code
```javascript
render({
type: Application,
});
```
-- code
```javascript
render({
type: Heading,
props: {
title: "So nice!",
children: {
type: NiceText,
props: {
children: "Hello world",
},
}
},
})
```
-- code
```javascript
render({
type: Heading,
props: {
title: "So nice!",
children: {
type: "span"
props: {
children: "🌻Hello world🌻",
},
}
},
})
```
-- code
```javascript
render({
type: "h1",
props: {
title: "So nice!",
children: {
type: "span"
props: {
children: "🌻Hello world🌻",
},
}
},
})
```
-- trabe-green
# React key points
--
# Components everywhere
You use the same abstraction to build every aspect of your application.
--
# Simple yet powerful
A Component is a function accepting props and returning elements.
--
# It's declarative
You describe the UI and React renders it.
You handle React an element. It's up to React to render the UI.
-- quote
"You handle React an element. It's up to React to render the UI."
-- quote
"You handle React an element. It's up to React to render the UI."
🤔
-- quote
"You handle React an element. It's up to React to render the UI."
🤔
-- quote
"You handle React an element. It's up to React to render the UI."
🤔
-- quote
"You handle React an element. It's up to React to render the UI."
😬
--
# Host agnosticism
Same principles, different renderers
* ReactDOM
* ReactNative
* Ink
* Custom renderer 🤔
--
# Host agnosticism
Same principles, different renderers
* ReactDOM
* ReactNative
* Ink
* Custom renderer 🤨
--
# All you need to know
* https://reactjs.org
--
# The magic behind
the curtain
* https://pomb.us/build-your-own-react/
-- section
# Building a microservices framework
using cues from React
--
# The problem
* Build Node.js REST microservices.
* Fast development cycle.
* Support common infraestructure (log, tracing, metrics, etc).
--
# Koa.js primer
## In roughly 5 minutes
-- quote
>Next generation web framework for node.js
>[https://koajs.com](https://koajs.com)
--
# An example
* [Use case] Fetch from a REST endpoint
* [Use case] Filter the active items
* [Use case] Return the data
* [Cross stuff] Log the request
-- code code-small
# An example
```javascript
const Koa = require("koa");
const app = new Koa();
// Log request
app.use(async (ctx, next) => {
const start = new Date().getTime();
console.log("Request start");
await next();
const t = new Date().getTime() - start;
console.log("Request end", t , "ms");
});
// Fetch, filter, return response
app.use(async ctx => {
const res = await fetch("http://api.com/data");
const json = await res.json();
const data = json.filter(item => item.active);
ctx.status = 200;
ctx.body = data;
});
app.listen(3000);
```
--
# Takeaways
* Small API: `async (ctx,next) => {}`
* Just JS
* Everything is a middleware
* Composable
* Simple and elegant
--
# An example - Take 2
* [cross stuff] Request id
* [cross stuff] Propagate request id
* [cross stuff] Handle errors
-- code code-eagle-eye
# An example - Take 2
const Koa = require("koa");
const uuid = require("uuid");
const app = new Koa();
app.use(async (ctx, next) => {
ctx.state.requestId = uuid();
await next();
});
app.use(async (ctx, next) => {
const start = new Date().getTime();
console.log("Request start");
await next();
const t = new Date().getTime() - start;
console.log("Request end", t , "ms");
};
app.use(async (ctx, next) => {
try {
await next();
} catch(e) {
ctx.status = 500;
}
});
app.use(async ctx => {
const res = await fetch("http://api.com/data", {
headers: {
"x-request-id": ctx.state.requestId,
}
});
const json = await res.json();
const data = json.filter(item => item.active);
ctx.status = 200;
ctx.body = data;
});
app.listen(3000)
-- code code-eagle-eye
# An example - Take 2
const Koa = require("koa");
const uuid = require("uuid");
const app = new Koa();
app.use(async (ctx, next) => {
ctx.state.requestId = uuid();
await next();
});
app.use(async (ctx, next) => {
const start = new Date().getTime();
console.log("Request start");
await next();
const t = new Date().getTime() - start;
console.log("Request end", t , "ms");
};
app.use(async (ctx, next) => {
try {
await next();
} catch(e) {
ctx.status = 500;
}
});
app.use(async ctx => {
const res = await fetch("http://api.com/data", {
headers: {
"x-request-id": ctx.state.requestId,
}
});
const json = await res.json();
const data = json.filter(item => item.active);
ctx.status = 200;
ctx.body = data;
});
app.listen(3000)
--
# Solution
## "React for microservices"
## Just declare the use case
## Framework handles boilerplate
## Sane defaults with opt out
-- code
# Possible JSX syntax
```javascript
ReactMicroservices.render(
item.active} />
);
```
-- code
# Real syntax: fluid DSL
```javascript
service()
.use(logRequest())
.use(fetchJson("http://api.com/data"))
.use(filter(item => item.active));
.use(sendData())
.listen(3000)
```
-- code
# An example - Take 3
```javascript
service()
.use(tracing())
.use(metrics())
.use(logRequest())
.use(router()
.get("/endoint",
parallel(
pipe(
fetchJson("http://api.com/data1"),
filter(item => item.active))
),
fetchJson("http://api.com/data2"),
),
transform(([data1, data2] => ({ data1, data2 }))
sendData()
)
)
.listen(3000);
```
-- code
# Nothing changes
```javascript
ReactMicroservices.render(
item.active} />
({ data1, data2 })} />
);
```
--
# Parallelism
| React | Microservices |
Definition | <Jsx /> | Fluid JS DSL |
Component | function | function |
Element | {type,props} | {type,props} |
Host node | DOM | Koa, async function |
Renderer | ReactDOM | Custom builders |
-- code code-small threeway threeway-1
```javascript
service()
.use(status(404))
.listen(3000);
```
```javascript
{
type: "service",
props: {
children: [
{
type: "status",
props: {
code: 404,
},
},
],
},
}
```
```javascript
const app = new Koa();
app.use(
async ctx => {
ctx.status = 404;
});
app.listen(3000);
```
-- code code-small threeway threeway-2
```javascript
service()
.use(status(404))
.listen(3000);
```
```javascript
{
type: "service",
props: {
children: [
{
type: "status",
props: {
code: 404,
},
},
],
},
}
```
```javascript
const app = new Koa();
app.use(
async ctx => {
ctx.status = 404;
});
app.listen(3000);
```
-- code code-small threeway threeway-3
```javascript
service()
.use(status(404))
.listen(3000);
```
```javascript
{
type: "service",
props: {
children: [
{
type: "status",
props: {
code: 404,
},
},
],
},
}
```
```javascript
const app = new Koa();
app.use(
async ctx => {
ctx.status = 404;
});
app.listen(3000);
```
-- code
# For this service...
```javascript
service()
.use(fetchJson("http://api.com/data"))
.use(sendData())
.listen(3000);
```
-- code
# ...using these components...
```javascript
const sendData = () => component("SEND_DATA", {});
const fetchJson = (url) => component("FETCH_JSON", { url });
const service = () =>
component("SERVICE", { children: [] })
.addDSLMethods({
use: element => middleware => {
element.props.children.push(middleware);
},
listen: element => port => {
build(element).listen(port);
}
});
```
-- code
# ...generates this element
```javascript
{
type: "SERVICE",
props: {
children: [
{
type: "FETCH_JSON",
props: {
url: "http://api.com/data"
}
},
{
type: "SEND_DATA",
props: {},
}
]
}
}
```
-- code code-small
# Using this builders...
```javascript
const builders = {
"SERVICE": (element, build) => {
const app = new Koa();
element.props.children
.map(child => build(child))
.forEach(fn => app.use(fn));
return app;
},
"FETCH_JSON": (element, build) =>
async (ctx, next) => {
const res = await fetch(element.url);
const json = await res.json();
ctx.state.data = json;
await nex();
},
"SEND_DATA": (element, build) =>
async (ctx, next) => {
ctx.status = 200;
ctx.body = ctx.state.data;
await next();
},
};
```
-- code
# ...we get this Koa.js service
```
const app = new Koa();
app.use(async (ctx, next) => {
const res = await fetch("http://api.com/data");
const json = await res.json();
ctx.state.data = json;
await nex();
}
app.use(async (ctx, next) => {
ctx.status = 200;
ctx.body = ctx.state.data;
await next();
});
app.listen(3000);
```
--
# Design validation
## Does it hold?
--
# Enter the miniservice
## Serve both REST and GRPC endpoints
[Koa.js](https://koajs.com/) and [Mali.js](https://mali.js.org/)
-- code
service()
.use(logRequest())
.use(router()
.get("/endoint", /* ... */)
)
.listen(3000)
-- code
http()
.use(logRequest())
.use(router()
.get("/endoint", /* ... */)
)
.listen(3000)
-- code
service()
.connect(
http()
.use(logRequest())
.use(router()
.get("/endoint", /* ... */)
)
.listen(3000),