SlideShare ist ein Scribd-Unternehmen logo
1 von 61
Downloaden Sie, um offline zu lesen
A MICRONAUT
WALKS INTO A SPA
MICRONAUT FOR SINGLE-PAGE-APPS
A MICRONAUT WALKS INTO A SPA
ABOUT ME
▸ Zachary Klein is a Senior Software Engineer
at OCI. He has been practicing web
development since 2010 and frontend
development since 2015. He’s a
contributor to both the Grails and
Micronaut frameworks, a conference
speaker and an occasional instructor in
OCI’s training practice.
▸ Zachary’s home base is in St Louis, MO,
along with his wife, Beth, and their three
children.
▸ Brief Introduction to Micronaut
▸ Restful Backends
▸ Gateways
▸ Security with JWT
▸ Building with Gradle
▸ Deploying a SPA in a JAR
A MICRONAUT WALKS INTO A SPA
AGENDA
AND GRAPHQL?
BRIEF INTRODUCTION TO MICRONAUT
▸ Designed with Microservices in mind
▸ Reactive HTTP server built on Netty
▸ AOT (Ahead of Time) Compilation for DI, AOP, and
configuration
▸ Declarative HTTP Client
▸ “Natively” Cloud-Native: service-discovery, LB,
circuit-breakers, tracing, and more
▸ Support for Java, Kotlin and Groovy
A MICRONAUT WALKS INTO A SPA
MICRONAUT
A MICRONAUT WALKS INTO A SPA
MICRONAUT: GETTING STARTED
~ curl -s "https://get.sdkman.io" | bash
~ source "$HOME/.sdkman/bin/sdkman-init.sh"
~ sdk install micronaut
~ mn create-app hello-world
A MICRONAUT WALKS INTO A SPA
MICRONAUT CLI
▸ Language defaults to Java
▸ Use --lang to specify groovy or kotlin
▸ Build tool defaults to Gradle
▸ Use --build to specify maven
▸ Run mn without arguments to enter interactive
mode - includes tab-completion
A MICRONAUT WALKS INTO A SPA
@Controller("/")
class HelloController {
@Get("/hello/{name}")
String hello(String name) {
return "Hello " + name;
}
}
MICRONAUT: CONTROLLERS & CLIENTS
@Client("/")
interface HelloClient {
@Get("/hello/{name}")
String hello(String name);
// Implementation generated
// at compile time
}
A MICRONAUT WALKS INTO A SPA
MICRONAUT: DEPENDENCY INJECTION
@Singleton //Bean definition generated at compile time
class WeatherService {
Integer currentTemp() { //... }
}
@Controller('/weather')
class WeatherController {
@Inject WeatherService weatherService
//DI computed at compile time
@Get("/")
HttpResponse<Integer> currentTemp() {
HttpResponse.ok(weatherService.currentTemp())
}
}
A MICRONAUT WALKS INTO A SPA
MICRONAUT: CLOUD NATIVE
//Lookup client from service-discovery registry
@Client(id="billing", path=“/billing")
interface BillingClient { ... }
//Automatically retry failing calls
@Client("https://api.external.service")
@Retryable(attempts = '3', delay = '5ms')
interface ExternalApiClient { ... }
//Immediately fail after set number of failures
//Begin accepting calls after `reset` interval
@Singleton
@CircuitBreaker(attempts = '5', reset = '300ms')
class MyService { ... }
SERVICE DISCOVERY
RETRYABLE
CIRCUIT BREAKERS
A MICRONAUT WALKS INTO A SPA
MICRONAUT: CLOUD NATIVE
▸ Cloud-Aware Environment Detection
▸ Cloud Provider Integration - AWS, GCP, Spring
Cloud
▸ Metrics & Monitoring
▸ Distributed Configuration
▸ Distributed Tracing
https://angular.io https://vuejs.org https://reactjs.org
~ vue create my-project~ ng new my-dream-app ~ npx create-react-app my-app
RESTFUL BACKENDS
BackendFrontend
REST
{JSON}
BackendFrontend
REST
{JSON}
▸ Declarative Routes via method annotations:
▸ @Get, @Put, @Post, @Delete
▸ JSON binding/rendering via Jackson
▸ Request Arguments via annotations:
▸ @Header, @Body, @CookieValue, @QueryValue
A MICRONAUT WALKS INTO A SPA
MICRONAUT & REST
A MICRONAUT WALKS INTO A SPA
JACKSON: JSON BINDING
public class Author {
private String name;
@JsonSerialize(MySerializer.class)
private Date birthday;
}
@Post(“/")
public HttpResponse<Author> save(
@Body Author author) {
if(bookRepository.save(author)) {
return HttpResponse.ok();
} else {
/* handle error */
}
}
https://www.baeldung.com/jackson-annotations
fetch("http://localhost:8080/
author/", {
method: "POST",
headers: new Headers({
"Content-Type":
"application/json"
}),
body: JSON.stringify({
name: "Author's Name",
birthday: "01/31/1985"
})
})
JAVASCRIPT
A MICRONAUT WALKS INTO A SPA
JACKSON: JSON RENDERING
{
“name": "Title Here”,
"author": {
"name": "Author"
},
"pages": 150,
"tags": [
"tech",
"bestseller"
]
}
@JsonIgnoreProperties({"id", "version"})
public class Book {
private Long id;
private Long version;
@JsonProperty(“name")
private String title;
private Author author;
private Integer pages;
private List<String> tags;
}
@Get("/{id}")
public Book show(Serializable id) {
return bookRepository.get(id);
}
https://www.baeldung.com/jackson-annotations
JSON
A MICRONAUT WALKS INTO A SPA
@Controller("/book")
class BookController {
@Post
HttpResponse<BookDetails> save(@Valid @Body BookDetails bookDetails) { /* .. */}
@Put
HttpResponse<BookDetails> update(@Valid @Body BookDetails bookDetails) { /* .. */}
@Delete("/{id}")
HttpResponse delete(Serializable id) { /* .. */}
@Get(“{?max,offset}")
@Transactional(readOnly = false)
HttpResponse<List<Book>> list(@Nullable Integer max, @Nullable Integer offset) { /* .. */}
@Get("/{id}")
@Transactional(readOnly = true)
HttpResponse<BookDetails> get(Serializable id) { /* .. */}
HttpResponse<Integer> count() { /* .. */}
}
REST CONTROLLER
BOOKCONTROLLER.JAVA
A MICRONAUT WALKS INTO A SPA
import { customHeaders } from "../security/SecurityUtils";
import { composeResourceURL } from "../rest/ClientUtils";
const list = (max, offset, callback, errorCallback) => {
fetch(composeResourceURL(“book","/", { max, offset }), {
method: "GET",
headers: customHeaders()
})
.then(response => response.json())
.then(json => callback(json))
.catch(error => errorCallback(error));
};
const get = (id, callback, errorCallback) => {
/* .. */
};
const save = (resource, callback, errorCallback) => {
/* .. */
};
const update = (resource, callback, errorCallback) => {
/* .. */
};
const remove = (id, callback, errorCallback) => {
/* .. */
};
export default { list, count, get, save, update, remove };
JAVASCRIPT CLIENT
BOOKCLIENT.JS
▸ Framework-agnostic client
▸ Using the fetch API (axios
is another popular option)
▸ Based on callback
functions (async/await is
another option)
▸ customHeaders() function
could return Authorization
headers, tenantId for
multi-tenancy, etc)
A MICRONAUT WALKS INTO A SPA
JAVASCRIPT CLIENT const composeResourceURL = (resource, append, params) => {
if (params !== null) {
append = `${append}${composeParams(params)}`;
}
return `${process.env.SERVER_URL}/${resource}/${append}`;
};
const composeParams = params => {
let paramString = "";
const paramKeys = Object.keys(params);
if (paramKeys.length > 0) {
paramString = "?";
paramKeys.map(key => {
const paramValue = params[key];
if (paramValue !== null && paramValue !== undefined) {
if (paramString !== "?") {
paramString = `${paramString}&`;
}
paramString = `${paramString}${key}=${params[key]}`;
}
});
}
return paramString;
};
export default { composeResourceURL };
CLIENTUTILS.JS
▸ General purpose REST
client functions
▸ Compose restful URL
with resource name,
path, parameters
▸ Compose URL
parameters from object
▸ Resolve Gateway URL
via Node environment
variable (e.g, SERVER_URL)
A MICRONAUT WALKS INTO A SPA
ENABLING CORS
▸ CORS support included in
Micronaut
▸ Disabled by default
▸ Can specify allowed
origins, methods, headers,
max age, and more.
micronaut:
application:
name: my-app
server:
cors:
enabled: true
APPLICATION.YML
▸ An alternative to REST
▸ Server provides a schema that
describes exposed resources
▸ Schema defines queries and mutations
▸ Clients can request only the resources
& fields they want
▸ Client libraries can intelligently merge
queries for efficiency
A MICRONAUT WALKS INTO A SPA
GRAPHQL
https://medium.freecodecamp.org/so-whats-this-graphql-thing-i-keep-hearing-about-baf4d36c20cf?gi=e256cd305c64
A MICRONAUT WALKS INTO A SPA
MICRONAUT & GRAPHQL
▸ micronaut-graphql library - contributed by Marcel Overdijk
▸ Wraps graphql-java and provides a default controller for accepting
queries & mutations
▸ The GraphQL schema still needs to be created, either manually via the
graphql-java API, or an integration library such as GORM for GraphQL
▸ Packages the GraphiQL in-browser IDE for exploring the GraphQL schema
▸ Example Projects: https://github.com/micronaut-projects/micronaut-
graphql/tree/master/examples/
A MICRONAUT WALKS INTO A SPA
MICRONAUT & GRAPHQL
dependencies {
compile “io.micronaut.graphql:micronaut-graphql”
}
BUILD.GRADLE
GATEWAYS
▸ Architectural pattern for microservice-based systems
▸ Expose a single client-facing API (for SPA, mobile, etc)
▸ Minimizing integration points - decoupling
▸ https://microservices.io/patterns/apigateway.html
A MICRONAUT WALKS INTO A SPA
GATEWAYS
Backend
Frontend
BillingMailAnalyticsInventory
Frontend
BillingMailAnalyticsInventory
Frontend
Billing
Frontend
MailAnalyticsInventory
Gateway
▸ Version by URL: @Get("/v1/user/profile")
▸ Using config property:
@Value("${core.api.version}")
String version
@Get("/${version}/user/profile")
‣ Client-facing versioning can be separate from versioning
within the microservice architecture
A MICRONAUT WALKS INTO A SPA
VERSIONING AN API
core:
api:
version: v1
APPLICATION.YML
BillingMailAnalyticsInventory
Frontend
Gateway
V1
Gateway
V2
BillingMailAnalyticsInventory
Frontend
Gateway
V1
Gateway
V2
▸ Partition your API
▸ Support different
client experiences/
functions (e.g, admin
vs customer)
A MICRONAUT WALKS INTO A SPA
MULTIPLE GATEWAYS
Billing
Web
MailAnalyticsInventory
Gateway
Admin Web
Admin
Gateway
Mobile
Mobile
Gateway
A MICRONAUT WALKS INTO A SPA
MICRONAUT PETSTORE
https://github.com/micronaut-projects/micronaut-examples/tree/master/petstore
SECURITY WITH JWT
A MICRONAUT WALKS INTO A SPA
JWTI: JSON WEB TOKEN
‣ Open standard for representing
claims securely between two parties
‣ Tokens can be signed with either a
secret or public/private key
‣ Standard approach for stateless
authentication
‣ Ideal for transmitting authentication
& authorization data between
microservices and single-page-apps
A MICRONAUT WALKS INTO A SPA
MICRONAUT SECURITY
▸ Core Micronaut Library - supports JWT, Session, Basic Auth
▸ Annotation-based API & config-based URL mappings
▸ Support for token propagation
▸ Supports RFC 6750 Bearer Token 
▸ JWTs can be read from cookie
dependencies {
compile "io.micronaut:micronaut-security-jwt"
}
micronaut:
security:
enabled: true
token:
jwt:
enabled: true
signatures:
secret:
generator:
secret: changeMe
APPLICATION.YML
BUILD.GRADLE
A MICRONAUT WALKS INTO A SPA
@SECURED ANNOTATION
▸ @Secured annotation applied
to controllers and methods
▸ All routes blocked by default
▸ Can require authentication
and/or authorization (role-
based)
▸ Alternative: JSR-250 security
annotations are also
supported: @PermitAll,
@RolesAllowed, @DenyAll
import java.security.Principal;
@Secured("isAuthenticated()")
@Controller("/")
public class HomeController {
@Get("/")
String index(Principal principal) {
return principal.getName();
}
@Secured({"ROLE_ADMIN", "ROLE_X"})
@Get("/classified")
String classified() {
return /* REDACTED */;
}
}
A MICRONAUT WALKS INTO A SPA
‣ Unauthorized request is made to API
‣ Responds with 401
‣ Client POSTs to login endpoint
‣ Server responds with JWT
‣ Client includes access token in the
Authorization header for subsequent
requests
‣ Server validates the incoming token
‣ If authorized, server responds with
resource
MICRONAUT JWT SECURITY
A MICRONAUT WALKS INTO A SPA
‣ POST credentials to the /
login endpoint
‣ Retrieve access token
from JWT and store in
application state, a
cookie, or local storage*
JAVASCRIPT JWT SECURITY const login = (credentials, callback, errorCallback) => {
fetch(`${process.env.SERVER_URL}/login`, {
method: "POST",
headers: new Headers({
Accept: "application/json",
"Content-Type": "application/json",
}),
body: JSON.stringify(credentials)
})
.then(response => {
if (response.ok) {
return response.json();
} else {
throw Error(response.statusText);
}
})
.then(json => callback(json))
.catch(error => errorCallback(error));
};
export default { login };
AUTHCLIENT.JS
import AuthClient from “./AuthClient";
AuthClient.login(
{ username: this.username, password: this.password },
json => /* handle login success */,
error => console.error(error)
);
*Local storage is not inherently secure:
https://www.rdegges.com/2018/please-stop-using-local-storage/
A MICRONAUT WALKS INTO A SPA
‣ Use custom Headers
object to include access
token (if using Bearer)
JAVASCRIPT JWT SECURITY
const securedHeaders = () => {
return new Headers({
Authorization: `Bearer ${token()}`,
"Content-Type": "application/json"
});
};
const token = () => //retrieve token from store;
export default { securedHeaders };
SECURITYUTILS.JS
import { securedHeaders } from "./SecurityUtils";
fetch(`${process.env.SERVER_URL}/home`, {
method: "GET",
headers: securedHeaders()
})
.then(response => response.text())
.then(text => (this.content = text))
.catch(error => {
console.log("Connection failure: ", error);
});
A MICRONAUT WALKS INTO A SPA
MICRONAUT SECURITY GUIDES
https://guides.micronaut.io/tags/security.html
BUILDING SPAS WITH GRADLE
MULTIPROJECT BUILDS
A MICRONAUT WALKS INTO A SPA
JAVASCRIPT APP
BackendFrontend
include "client", “server"
SETTINGS.GRADLE
GRADLE NODE PLUGIN
A MICRONAUT WALKS INTO A SPA
plugins {
id "com.github.node-gradle.node" version "1.3.0"
}
node {
version = '10.15.0' // https://nodejs.org/en/
yarnVersion = '1.13.0' // https://yarnpkg.com/en/
download = true
}
task start(type: YarnTask, dependsOn: 'yarn') {
group = 'application'
description = 'Run the client app'
args = ['run', 'start']
}
task build(type: YarnTask, dependsOn: 'yarn') {
group = 'build'
description = 'Build the client bundle'
args = ['run', 'build']
}
task test(type: YarnTask, dependsOn: 'yarn') {
group = 'verification'
description = 'Run the client tests'
args = ['run', 'test']
}
task eject(type: YarnTask, dependsOn: 'yarn') {
//...
}
{
"name": "client",
"version": "0.1.0",
"private": true,
"dependencies": {
//...
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
~ gradle start //yarn start
Server running on http://localhost:3000
BUILD.GRADLE PACKAGE.JSON
DEPLOYING A SPA IN A JAR
▸ Serve the Single-Page-App from within an executable JAR
file
▸ Removes need for a separate static server
▸ SPA can be packaged with its gateway
▸ Simplifies deployment of small apps and/or IoT
deployments
A MICRONAUT WALKS INTO A SPA
DEPLOYING A SPA IN A JAR
~ gradle shadowJar
BUILD SUCCESSFUL in 1s
DEPLOYMENT
A MICRONAUT WALKS INTO A SPA
JAVASCRIPT APP
~ yarn build
Creating a production build...
Compiled successfully.
DEPLOYMENT
A MICRONAUT WALKS INTO A SPA
JAVASCRIPT APP
BackendFrontend
COMBINED BUILD
A MICRONAUT WALKS INTO A SPA
~ java -jar build/libs/server-all.jar
Server Running: http://localhost:8080
STATIC ASSETS IN MICRONAUT
A MICRONAUT WALKS INTO A SPA
▸ Disabled by default
▸
▸
▸ List of paths, starting with classpath: or file:
▸
▸ The path from which resources should be served
micronaut.router.static-resources.*.enabled
micronaut.router.static-resources.*.paths
micronaut.router.static-resources.*.mapping
STATIC ASSETS IN MICRONAUT
A MICRONAUT WALKS INTO A SPA
micronaut:
router:
static-resources:
default:
enabled: true
mapping: "/**"
paths: "classpath:public"
local:
enabled: true
mapping: “/local/**"
paths: “file:path/to/files“
APPLICATION.YML
COMBINED BUILD
A MICRONAUT WALKS INTO A SPA
//Copy production SPA resources into server build directory
task copyClientResources(dependsOn: ':client:build') {
group = 'build'
description = 'Copy client resources into server'
}
copyClientResources.doFirst {
copy {
from project(':client').buildDir.absolutePath
into "${project(':server').buildDir}/resources/main/public"
}
}
//Build a single executable JAR with embedded SPA resources
task assembleServerAndClient(
dependsOn: ['copyClientResources', ':server:shadowJar']) {
group = 'build'
description = 'Build combined server & client JAR'
}
BUILD.GRADLE
COMBINED BUILD
A MICRONAUT WALKS INTO A SPA
~ java -jar build/libs/server-all.jar
Server Running: http://localhost:8080
MICRONAUT SINGLE-PAGE-APP GUIDE
A MICRONAUT WALKS INTO A SPA
https://guides.micronaut.io/micronaut-spa-react/guide/index.htmlNEW!
A MICRONAUT WALKS INTO A SPA
MICRONAUT PETSTORE
https://github.com/micronaut-projects/micronaut-examples/tree/master/petstore
A MICRONAUT WALKS INTO A SPA
LEARN MORE ABOUT OCI EVENTS AND TRAINING
Events:
‣ objectcomputing.com/events
Training:
‣ objectcomputing.com/training
‣ grailstraining.com
‣ micronauttraining.com
COME SEE US
AT OUR BOOTH!
A MICRONAUT WALKS INTO A SPA
THANK YOU@ZacharyAKlein kleinz@objectcomputing.com

Weitere ähnliche Inhalte

Was ist angesagt?

VMware Tanzu Service Mesh from the Developer’s Perspective
VMware Tanzu Service Mesh from the Developer’s PerspectiveVMware Tanzu Service Mesh from the Developer’s Perspective
VMware Tanzu Service Mesh from the Developer’s PerspectiveVMware Tanzu
 
啟動 Laravel 與環境設定
啟動 Laravel 與環境設定啟動 Laravel 與環境設定
啟動 Laravel 與環境設定Shengyou Fan
 
GlassFish in Production Environments
GlassFish in Production EnvironmentsGlassFish in Production Environments
GlassFish in Production EnvironmentsBruno Borges
 
Emirates Airline - Strategic SWOT Analysis Review- HBR Case
Emirates Airline - Strategic SWOT Analysis Review- HBR CaseEmirates Airline - Strategic SWOT Analysis Review- HBR Case
Emirates Airline - Strategic SWOT Analysis Review- HBR CaseSiddharth Khandelwal
 
Introduction à l’intégration continue avec Jenkins
Introduction à l’intégration continue avec JenkinsIntroduction à l’intégration continue avec Jenkins
Introduction à l’intégration continue avec JenkinsEric Hogue
 
From Brick Mortar To Online Click Organisation
From Brick Mortar To Online Click OrganisationFrom Brick Mortar To Online Click Organisation
From Brick Mortar To Online Click OrganisationKartik Mehta
 
jBPM Overview & Alfresco Workflows
jBPM Overview &  Alfresco WorkflowsjBPM Overview &  Alfresco Workflows
jBPM Overview & Alfresco WorkflowsFrancesco Valente
 
Utilizing JSF Front Ends with Microservices
Utilizing JSF Front Ends with MicroservicesUtilizing JSF Front Ends with Microservices
Utilizing JSF Front Ends with MicroservicesJosh Juneau
 
Easy Jet Case Study - Mis
Easy Jet Case Study   -  MisEasy Jet Case Study   -  Mis
Easy Jet Case Study - MisBERHMANI Samuel
 
Once upon a time The Concorde
Once upon a time The ConcordeOnce upon a time The Concorde
Once upon a time The ConcordeJM G
 
Jetblue airways ppt presentation
Jetblue airways ppt presentationJetblue airways ppt presentation
Jetblue airways ppt presentationMonica Ceasar
 
Hive Authorization
Hive AuthorizationHive Authorization
Hive AuthorizationMinwoo Kim
 
Automating AWS Infrastructure Provisioning Using Concourse and Terraform
Automating AWS Infrastructure Provisioning Using Concourse and TerraformAutomating AWS Infrastructure Provisioning Using Concourse and Terraform
Automating AWS Infrastructure Provisioning Using Concourse and TerraformCesar Rodriguez
 
Homer - Workshop at Kamailio World 2017
Homer - Workshop at Kamailio World 2017Homer - Workshop at Kamailio World 2017
Homer - Workshop at Kamailio World 2017Giacomo Vacca
 
Enable Domino Data Access Services (DAS)
Enable Domino Data Access Services (DAS)Enable Domino Data Access Services (DAS)
Enable Domino Data Access Services (DAS)Slobodan Lohja
 

Was ist angesagt? (20)

VMware Tanzu Service Mesh from the Developer’s Perspective
VMware Tanzu Service Mesh from the Developer’s PerspectiveVMware Tanzu Service Mesh from the Developer’s Perspective
VMware Tanzu Service Mesh from the Developer’s Perspective
 
啟動 Laravel 與環境設定
啟動 Laravel 與環境設定啟動 Laravel 與環境設定
啟動 Laravel 與環境設定
 
GlassFish in Production Environments
GlassFish in Production EnvironmentsGlassFish in Production Environments
GlassFish in Production Environments
 
kubernetes, pourquoi et comment
kubernetes, pourquoi et commentkubernetes, pourquoi et comment
kubernetes, pourquoi et comment
 
Emirates Airline - Strategic SWOT Analysis Review- HBR Case
Emirates Airline - Strategic SWOT Analysis Review- HBR CaseEmirates Airline - Strategic SWOT Analysis Review- HBR Case
Emirates Airline - Strategic SWOT Analysis Review- HBR Case
 
Introduction à l’intégration continue avec Jenkins
Introduction à l’intégration continue avec JenkinsIntroduction à l’intégration continue avec Jenkins
Introduction à l’intégration continue avec Jenkins
 
From Brick Mortar To Online Click Organisation
From Brick Mortar To Online Click OrganisationFrom Brick Mortar To Online Click Organisation
From Brick Mortar To Online Click Organisation
 
jBPM Overview & Alfresco Workflows
jBPM Overview &  Alfresco WorkflowsjBPM Overview &  Alfresco Workflows
jBPM Overview & Alfresco Workflows
 
Ting's Jet Blue case
Ting's Jet Blue caseTing's Jet Blue case
Ting's Jet Blue case
 
Utilizing JSF Front Ends with Microservices
Utilizing JSF Front Ends with MicroservicesUtilizing JSF Front Ends with Microservices
Utilizing JSF Front Ends with Microservices
 
HAProxy
HAProxy HAProxy
HAProxy
 
Easy Jet Case Study - Mis
Easy Jet Case Study   -  MisEasy Jet Case Study   -  Mis
Easy Jet Case Study - Mis
 
Once upon a time The Concorde
Once upon a time The ConcordeOnce upon a time The Concorde
Once upon a time The Concorde
 
Jetblue airways ppt presentation
Jetblue airways ppt presentationJetblue airways ppt presentation
Jetblue airways ppt presentation
 
Hive Authorization
Hive AuthorizationHive Authorization
Hive Authorization
 
Automating AWS Infrastructure Provisioning Using Concourse and Terraform
Automating AWS Infrastructure Provisioning Using Concourse and TerraformAutomating AWS Infrastructure Provisioning Using Concourse and Terraform
Automating AWS Infrastructure Provisioning Using Concourse and Terraform
 
Homer - Workshop at Kamailio World 2017
Homer - Workshop at Kamailio World 2017Homer - Workshop at Kamailio World 2017
Homer - Workshop at Kamailio World 2017
 
Docker on Docker
Docker on DockerDocker on Docker
Docker on Docker
 
DUBAI
DUBAIDUBAI
DUBAI
 
Enable Domino Data Access Services (DAS)
Enable Domino Data Access Services (DAS)Enable Domino Data Access Services (DAS)
Enable Domino Data Access Services (DAS)
 

Ähnlich wie Micronaut For Single Page Apps

10 Excellent Ways to Secure Spring Boot Applications - Okta Webinar 2020
10 Excellent Ways to Secure Spring Boot Applications - Okta Webinar 202010 Excellent Ways to Secure Spring Boot Applications - Okta Webinar 2020
10 Excellent Ways to Secure Spring Boot Applications - Okta Webinar 2020Matt Raible
 
Multi Client Development with Spring
Multi Client Development with SpringMulti Client Development with Spring
Multi Client Development with SpringJoshua Long
 
using Mithril.js + postgREST to build and consume API's
using Mithril.js + postgREST to build and consume API'susing Mithril.js + postgREST to build and consume API's
using Mithril.js + postgREST to build and consume API'sAntônio Roberto Silva
 
TDC2016SP - Construindo Microserviços usando Spring Cloud
TDC2016SP - Construindo Microserviços usando Spring CloudTDC2016SP - Construindo Microserviços usando Spring Cloud
TDC2016SP - Construindo Microserviços usando Spring Cloudtdc-globalcode
 
ASP.NET MVC Internals
ASP.NET MVC InternalsASP.NET MVC Internals
ASP.NET MVC InternalsVitaly Baum
 
Solving anything in VCL
Solving anything in VCLSolving anything in VCL
Solving anything in VCLFastly
 
Dropwizard Introduction
Dropwizard IntroductionDropwizard Introduction
Dropwizard IntroductionAnthony Chen
 
Fun Teaching MongoDB New Tricks
Fun Teaching MongoDB New TricksFun Teaching MongoDB New Tricks
Fun Teaching MongoDB New TricksMongoDB
 
[NDC 2019] Enterprise-Grade Serverless
[NDC 2019] Enterprise-Grade Serverless[NDC 2019] Enterprise-Grade Serverless
[NDC 2019] Enterprise-Grade ServerlessKatyShimizu
 
[NDC 2019] Functions 2.0: Enterprise-Grade Serverless
[NDC 2019] Functions 2.0: Enterprise-Grade Serverless[NDC 2019] Functions 2.0: Enterprise-Grade Serverless
[NDC 2019] Functions 2.0: Enterprise-Grade ServerlessKatyShimizu
 
Backbone js in action
Backbone js in actionBackbone js in action
Backbone js in actionUsha Guduri
 
Java Configuration Deep Dive with Spring
Java Configuration Deep Dive with SpringJava Configuration Deep Dive with Spring
Java Configuration Deep Dive with SpringJoshua Long
 
Hazelcast and MongoDB at Cloud CMS
Hazelcast and MongoDB at Cloud CMSHazelcast and MongoDB at Cloud CMS
Hazelcast and MongoDB at Cloud CMSuzquiano
 
Futures and Rx Observables: powerful abstractions for consuming web services ...
Futures and Rx Observables: powerful abstractions for consuming web services ...Futures and Rx Observables: powerful abstractions for consuming web services ...
Futures and Rx Observables: powerful abstractions for consuming web services ...Chris Richardson
 
Serverless archtiectures
Serverless archtiecturesServerless archtiectures
Serverless archtiecturesIegor Fadieiev
 

Ähnlich wie Micronaut For Single Page Apps (20)

10 Excellent Ways to Secure Spring Boot Applications - Okta Webinar 2020
10 Excellent Ways to Secure Spring Boot Applications - Okta Webinar 202010 Excellent Ways to Secure Spring Boot Applications - Okta Webinar 2020
10 Excellent Ways to Secure Spring Boot Applications - Okta Webinar 2020
 
Micronaut Launchpad
Micronaut LaunchpadMicronaut Launchpad
Micronaut Launchpad
 
Multi Client Development with Spring
Multi Client Development with SpringMulti Client Development with Spring
Multi Client Development with Spring
 
using Mithril.js + postgREST to build and consume API's
using Mithril.js + postgREST to build and consume API'susing Mithril.js + postgREST to build and consume API's
using Mithril.js + postgREST to build and consume API's
 
TDC 2016 - Arquitetura Java - Spring Cloud
TDC 2016 - Arquitetura Java - Spring CloudTDC 2016 - Arquitetura Java - Spring Cloud
TDC 2016 - Arquitetura Java - Spring Cloud
 
TDC2016SP - Construindo Microserviços usando Spring Cloud
TDC2016SP - Construindo Microserviços usando Spring CloudTDC2016SP - Construindo Microserviços usando Spring Cloud
TDC2016SP - Construindo Microserviços usando Spring Cloud
 
ASP.NET MVC Internals
ASP.NET MVC InternalsASP.NET MVC Internals
ASP.NET MVC Internals
 
Solving anything in VCL
Solving anything in VCLSolving anything in VCL
Solving anything in VCL
 
Arquitecturas de microservicios - Medianet Software
Arquitecturas de microservicios   -  Medianet SoftwareArquitecturas de microservicios   -  Medianet Software
Arquitecturas de microservicios - Medianet Software
 
Dropwizard Introduction
Dropwizard IntroductionDropwizard Introduction
Dropwizard Introduction
 
Fun Teaching MongoDB New Tricks
Fun Teaching MongoDB New TricksFun Teaching MongoDB New Tricks
Fun Teaching MongoDB New Tricks
 
[NDC 2019] Enterprise-Grade Serverless
[NDC 2019] Enterprise-Grade Serverless[NDC 2019] Enterprise-Grade Serverless
[NDC 2019] Enterprise-Grade Serverless
 
[NDC 2019] Functions 2.0: Enterprise-Grade Serverless
[NDC 2019] Functions 2.0: Enterprise-Grade Serverless[NDC 2019] Functions 2.0: Enterprise-Grade Serverless
[NDC 2019] Functions 2.0: Enterprise-Grade Serverless
 
Dwr
DwrDwr
Dwr
 
Backbone js in action
Backbone js in actionBackbone js in action
Backbone js in action
 
Java Configuration Deep Dive with Spring
Java Configuration Deep Dive with SpringJava Configuration Deep Dive with Spring
Java Configuration Deep Dive with Spring
 
Hazelcast and MongoDB at Cloud CMS
Hazelcast and MongoDB at Cloud CMSHazelcast and MongoDB at Cloud CMS
Hazelcast and MongoDB at Cloud CMS
 
Futures and Rx Observables: powerful abstractions for consuming web services ...
Futures and Rx Observables: powerful abstractions for consuming web services ...Futures and Rx Observables: powerful abstractions for consuming web services ...
Futures and Rx Observables: powerful abstractions for consuming web services ...
 
Serverless archtiectures
Serverless archtiecturesServerless archtiectures
Serverless archtiectures
 
Introduction to angular js
Introduction to angular jsIntroduction to angular js
Introduction to angular js
 

Mehr von Zachary Klein

Native Cloud-Native: Building Agile Microservices with the Micronaut Framework
Native Cloud-Native: Building Agile Microservices with the Micronaut FrameworkNative Cloud-Native: Building Agile Microservices with the Micronaut Framework
Native Cloud-Native: Building Agile Microservices with the Micronaut FrameworkZachary Klein
 
Groovy-Powered Microservices with Micronaut
Groovy-Powered Microservices with MicronautGroovy-Powered Microservices with Micronaut
Groovy-Powered Microservices with MicronautZachary Klein
 
Micronaut: Changing the Micro Future
Micronaut: Changing the Micro FutureMicronaut: Changing the Micro Future
Micronaut: Changing the Micro FutureZachary Klein
 
Grails 4: Upgrade your Game!
Grails 4: Upgrade your Game!Grails 4: Upgrade your Game!
Grails 4: Upgrade your Game!Zachary Klein
 
Getting Groovy with JHipster and Micronaut
Getting Groovy with JHipster and MicronautGetting Groovy with JHipster and Micronaut
Getting Groovy with JHipster and MicronautZachary Klein
 
Groovy for Java Devs
Groovy for Java DevsGroovy for Java Devs
Groovy for Java DevsZachary Klein
 
Grails Launchpad - From Ground Zero to Orbit
Grails Launchpad - From Ground Zero to OrbitGrails Launchpad - From Ground Zero to Orbit
Grails Launchpad - From Ground Zero to OrbitZachary Klein
 
Room with a Vue - Introduction to Vue.js
Room with a Vue - Introduction to Vue.jsRoom with a Vue - Introduction to Vue.js
Room with a Vue - Introduction to Vue.jsZachary Klein
 
Shields Up! Securing React Apps
Shields Up! Securing React AppsShields Up! Securing React Apps
Shields Up! Securing React AppsZachary Klein
 
Using React with Grails 3
Using React with Grails 3Using React with Grails 3
Using React with Grails 3Zachary Klein
 

Mehr von Zachary Klein (10)

Native Cloud-Native: Building Agile Microservices with the Micronaut Framework
Native Cloud-Native: Building Agile Microservices with the Micronaut FrameworkNative Cloud-Native: Building Agile Microservices with the Micronaut Framework
Native Cloud-Native: Building Agile Microservices with the Micronaut Framework
 
Groovy-Powered Microservices with Micronaut
Groovy-Powered Microservices with MicronautGroovy-Powered Microservices with Micronaut
Groovy-Powered Microservices with Micronaut
 
Micronaut: Changing the Micro Future
Micronaut: Changing the Micro FutureMicronaut: Changing the Micro Future
Micronaut: Changing the Micro Future
 
Grails 4: Upgrade your Game!
Grails 4: Upgrade your Game!Grails 4: Upgrade your Game!
Grails 4: Upgrade your Game!
 
Getting Groovy with JHipster and Micronaut
Getting Groovy with JHipster and MicronautGetting Groovy with JHipster and Micronaut
Getting Groovy with JHipster and Micronaut
 
Groovy for Java Devs
Groovy for Java DevsGroovy for Java Devs
Groovy for Java Devs
 
Grails Launchpad - From Ground Zero to Orbit
Grails Launchpad - From Ground Zero to OrbitGrails Launchpad - From Ground Zero to Orbit
Grails Launchpad - From Ground Zero to Orbit
 
Room with a Vue - Introduction to Vue.js
Room with a Vue - Introduction to Vue.jsRoom with a Vue - Introduction to Vue.js
Room with a Vue - Introduction to Vue.js
 
Shields Up! Securing React Apps
Shields Up! Securing React AppsShields Up! Securing React Apps
Shields Up! Securing React Apps
 
Using React with Grails 3
Using React with Grails 3Using React with Grails 3
Using React with Grails 3
 

Kürzlich hochgeladen

How To Use Server-Side Rendering with Nuxt.js
How To Use Server-Side Rendering with Nuxt.jsHow To Use Server-Side Rendering with Nuxt.js
How To Use Server-Side Rendering with Nuxt.jsAndolasoft Inc
 
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...panagenda
 
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...Steffen Staab
 
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsUnveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsAlberto González Trastoy
 
Diamond Application Development Crafting Solutions with Precision
Diamond Application Development Crafting Solutions with PrecisionDiamond Application Development Crafting Solutions with Precision
Diamond Application Development Crafting Solutions with PrecisionSolGuruz
 
HR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comHR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comFatema Valibhai
 
5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdf5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdfWave PLM
 
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...ICS
 
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️Delhi Call girls
 
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...kellynguyen01
 
Unlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language ModelsUnlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language Modelsaagamshah0812
 
Right Money Management App For Your Financial Goals
Right Money Management App For Your Financial GoalsRight Money Management App For Your Financial Goals
Right Money Management App For Your Financial GoalsJhone kinadey
 
TECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providerTECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providermohitmore19
 
Optimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVOptimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVshikhaohhpro
 
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AI
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AISyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AI
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AIABDERRAOUF MEHENNI
 
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...MyIntelliSource, Inc.
 
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...MyIntelliSource, Inc.
 

Kürzlich hochgeladen (20)

How To Use Server-Side Rendering with Nuxt.js
How To Use Server-Side Rendering with Nuxt.jsHow To Use Server-Side Rendering with Nuxt.js
How To Use Server-Side Rendering with Nuxt.js
 
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
 
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
 
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsUnveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
 
Diamond Application Development Crafting Solutions with Precision
Diamond Application Development Crafting Solutions with PrecisionDiamond Application Development Crafting Solutions with Precision
Diamond Application Development Crafting Solutions with Precision
 
HR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comHR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.com
 
5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdf5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdf
 
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
 
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
 
Microsoft AI Transformation Partner Playbook.pdf
Microsoft AI Transformation Partner Playbook.pdfMicrosoft AI Transformation Partner Playbook.pdf
Microsoft AI Transformation Partner Playbook.pdf
 
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
 
Unlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language ModelsUnlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language Models
 
Right Money Management App For Your Financial Goals
Right Money Management App For Your Financial GoalsRight Money Management App For Your Financial Goals
Right Money Management App For Your Financial Goals
 
TECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providerTECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service provider
 
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICECHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
 
Optimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVOptimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTV
 
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AI
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AISyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AI
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AI
 
Vip Call Girls Noida ➡️ Delhi ➡️ 9999965857 No Advance 24HRS Live
Vip Call Girls Noida ➡️ Delhi ➡️ 9999965857 No Advance 24HRS LiveVip Call Girls Noida ➡️ Delhi ➡️ 9999965857 No Advance 24HRS Live
Vip Call Girls Noida ➡️ Delhi ➡️ 9999965857 No Advance 24HRS Live
 
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
 
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
 

Micronaut For Single Page Apps

  • 1. A MICRONAUT WALKS INTO A SPA MICRONAUT FOR SINGLE-PAGE-APPS
  • 2. A MICRONAUT WALKS INTO A SPA ABOUT ME ▸ Zachary Klein is a Senior Software Engineer at OCI. He has been practicing web development since 2010 and frontend development since 2015. He’s a contributor to both the Grails and Micronaut frameworks, a conference speaker and an occasional instructor in OCI’s training practice. ▸ Zachary’s home base is in St Louis, MO, along with his wife, Beth, and their three children.
  • 3. ▸ Brief Introduction to Micronaut ▸ Restful Backends ▸ Gateways ▸ Security with JWT ▸ Building with Gradle ▸ Deploying a SPA in a JAR A MICRONAUT WALKS INTO A SPA AGENDA AND GRAPHQL?
  • 5. ▸ Designed with Microservices in mind ▸ Reactive HTTP server built on Netty ▸ AOT (Ahead of Time) Compilation for DI, AOP, and configuration ▸ Declarative HTTP Client ▸ “Natively” Cloud-Native: service-discovery, LB, circuit-breakers, tracing, and more ▸ Support for Java, Kotlin and Groovy A MICRONAUT WALKS INTO A SPA MICRONAUT
  • 6. A MICRONAUT WALKS INTO A SPA MICRONAUT: GETTING STARTED ~ curl -s "https://get.sdkman.io" | bash ~ source "$HOME/.sdkman/bin/sdkman-init.sh" ~ sdk install micronaut ~ mn create-app hello-world
  • 7. A MICRONAUT WALKS INTO A SPA MICRONAUT CLI ▸ Language defaults to Java ▸ Use --lang to specify groovy or kotlin ▸ Build tool defaults to Gradle ▸ Use --build to specify maven ▸ Run mn without arguments to enter interactive mode - includes tab-completion
  • 8. A MICRONAUT WALKS INTO A SPA @Controller("/") class HelloController { @Get("/hello/{name}") String hello(String name) { return "Hello " + name; } } MICRONAUT: CONTROLLERS & CLIENTS @Client("/") interface HelloClient { @Get("/hello/{name}") String hello(String name); // Implementation generated // at compile time }
  • 9. A MICRONAUT WALKS INTO A SPA MICRONAUT: DEPENDENCY INJECTION @Singleton //Bean definition generated at compile time class WeatherService { Integer currentTemp() { //... } } @Controller('/weather') class WeatherController { @Inject WeatherService weatherService //DI computed at compile time @Get("/") HttpResponse<Integer> currentTemp() { HttpResponse.ok(weatherService.currentTemp()) } }
  • 10. A MICRONAUT WALKS INTO A SPA MICRONAUT: CLOUD NATIVE //Lookup client from service-discovery registry @Client(id="billing", path=“/billing") interface BillingClient { ... } //Automatically retry failing calls @Client("https://api.external.service") @Retryable(attempts = '3', delay = '5ms') interface ExternalApiClient { ... } //Immediately fail after set number of failures //Begin accepting calls after `reset` interval @Singleton @CircuitBreaker(attempts = '5', reset = '300ms') class MyService { ... } SERVICE DISCOVERY RETRYABLE CIRCUIT BREAKERS
  • 11. A MICRONAUT WALKS INTO A SPA MICRONAUT: CLOUD NATIVE ▸ Cloud-Aware Environment Detection ▸ Cloud Provider Integration - AWS, GCP, Spring Cloud ▸ Metrics & Monitoring ▸ Distributed Configuration ▸ Distributed Tracing
  • 12.
  • 13. https://angular.io https://vuejs.org https://reactjs.org ~ vue create my-project~ ng new my-dream-app ~ npx create-react-app my-app
  • 17. ▸ Declarative Routes via method annotations: ▸ @Get, @Put, @Post, @Delete ▸ JSON binding/rendering via Jackson ▸ Request Arguments via annotations: ▸ @Header, @Body, @CookieValue, @QueryValue A MICRONAUT WALKS INTO A SPA MICRONAUT & REST
  • 18. A MICRONAUT WALKS INTO A SPA JACKSON: JSON BINDING public class Author { private String name; @JsonSerialize(MySerializer.class) private Date birthday; } @Post(“/") public HttpResponse<Author> save( @Body Author author) { if(bookRepository.save(author)) { return HttpResponse.ok(); } else { /* handle error */ } } https://www.baeldung.com/jackson-annotations fetch("http://localhost:8080/ author/", { method: "POST", headers: new Headers({ "Content-Type": "application/json" }), body: JSON.stringify({ name: "Author's Name", birthday: "01/31/1985" }) }) JAVASCRIPT
  • 19. A MICRONAUT WALKS INTO A SPA JACKSON: JSON RENDERING { “name": "Title Here”, "author": { "name": "Author" }, "pages": 150, "tags": [ "tech", "bestseller" ] } @JsonIgnoreProperties({"id", "version"}) public class Book { private Long id; private Long version; @JsonProperty(“name") private String title; private Author author; private Integer pages; private List<String> tags; } @Get("/{id}") public Book show(Serializable id) { return bookRepository.get(id); } https://www.baeldung.com/jackson-annotations JSON
  • 20. A MICRONAUT WALKS INTO A SPA @Controller("/book") class BookController { @Post HttpResponse<BookDetails> save(@Valid @Body BookDetails bookDetails) { /* .. */} @Put HttpResponse<BookDetails> update(@Valid @Body BookDetails bookDetails) { /* .. */} @Delete("/{id}") HttpResponse delete(Serializable id) { /* .. */} @Get(“{?max,offset}") @Transactional(readOnly = false) HttpResponse<List<Book>> list(@Nullable Integer max, @Nullable Integer offset) { /* .. */} @Get("/{id}") @Transactional(readOnly = true) HttpResponse<BookDetails> get(Serializable id) { /* .. */} HttpResponse<Integer> count() { /* .. */} } REST CONTROLLER BOOKCONTROLLER.JAVA
  • 21. A MICRONAUT WALKS INTO A SPA import { customHeaders } from "../security/SecurityUtils"; import { composeResourceURL } from "../rest/ClientUtils"; const list = (max, offset, callback, errorCallback) => { fetch(composeResourceURL(“book","/", { max, offset }), { method: "GET", headers: customHeaders() }) .then(response => response.json()) .then(json => callback(json)) .catch(error => errorCallback(error)); }; const get = (id, callback, errorCallback) => { /* .. */ }; const save = (resource, callback, errorCallback) => { /* .. */ }; const update = (resource, callback, errorCallback) => { /* .. */ }; const remove = (id, callback, errorCallback) => { /* .. */ }; export default { list, count, get, save, update, remove }; JAVASCRIPT CLIENT BOOKCLIENT.JS ▸ Framework-agnostic client ▸ Using the fetch API (axios is another popular option) ▸ Based on callback functions (async/await is another option) ▸ customHeaders() function could return Authorization headers, tenantId for multi-tenancy, etc)
  • 22. A MICRONAUT WALKS INTO A SPA JAVASCRIPT CLIENT const composeResourceURL = (resource, append, params) => { if (params !== null) { append = `${append}${composeParams(params)}`; } return `${process.env.SERVER_URL}/${resource}/${append}`; }; const composeParams = params => { let paramString = ""; const paramKeys = Object.keys(params); if (paramKeys.length > 0) { paramString = "?"; paramKeys.map(key => { const paramValue = params[key]; if (paramValue !== null && paramValue !== undefined) { if (paramString !== "?") { paramString = `${paramString}&`; } paramString = `${paramString}${key}=${params[key]}`; } }); } return paramString; }; export default { composeResourceURL }; CLIENTUTILS.JS ▸ General purpose REST client functions ▸ Compose restful URL with resource name, path, parameters ▸ Compose URL parameters from object ▸ Resolve Gateway URL via Node environment variable (e.g, SERVER_URL)
  • 23. A MICRONAUT WALKS INTO A SPA ENABLING CORS ▸ CORS support included in Micronaut ▸ Disabled by default ▸ Can specify allowed origins, methods, headers, max age, and more. micronaut: application: name: my-app server: cors: enabled: true APPLICATION.YML
  • 24. ▸ An alternative to REST ▸ Server provides a schema that describes exposed resources ▸ Schema defines queries and mutations ▸ Clients can request only the resources & fields they want ▸ Client libraries can intelligently merge queries for efficiency A MICRONAUT WALKS INTO A SPA GRAPHQL https://medium.freecodecamp.org/so-whats-this-graphql-thing-i-keep-hearing-about-baf4d36c20cf?gi=e256cd305c64
  • 25. A MICRONAUT WALKS INTO A SPA MICRONAUT & GRAPHQL
  • 26. ▸ micronaut-graphql library - contributed by Marcel Overdijk ▸ Wraps graphql-java and provides a default controller for accepting queries & mutations ▸ The GraphQL schema still needs to be created, either manually via the graphql-java API, or an integration library such as GORM for GraphQL ▸ Packages the GraphiQL in-browser IDE for exploring the GraphQL schema ▸ Example Projects: https://github.com/micronaut-projects/micronaut- graphql/tree/master/examples/ A MICRONAUT WALKS INTO A SPA MICRONAUT & GRAPHQL dependencies { compile “io.micronaut.graphql:micronaut-graphql” } BUILD.GRADLE
  • 28. ▸ Architectural pattern for microservice-based systems ▸ Expose a single client-facing API (for SPA, mobile, etc) ▸ Minimizing integration points - decoupling ▸ https://microservices.io/patterns/apigateway.html A MICRONAUT WALKS INTO A SPA GATEWAYS
  • 33. ▸ Version by URL: @Get("/v1/user/profile") ▸ Using config property: @Value("${core.api.version}") String version @Get("/${version}/user/profile") ‣ Client-facing versioning can be separate from versioning within the microservice architecture A MICRONAUT WALKS INTO A SPA VERSIONING AN API core: api: version: v1 APPLICATION.YML
  • 36. ▸ Partition your API ▸ Support different client experiences/ functions (e.g, admin vs customer) A MICRONAUT WALKS INTO A SPA MULTIPLE GATEWAYS Billing Web MailAnalyticsInventory Gateway Admin Web Admin Gateway Mobile Mobile Gateway
  • 37. A MICRONAUT WALKS INTO A SPA MICRONAUT PETSTORE https://github.com/micronaut-projects/micronaut-examples/tree/master/petstore
  • 39. A MICRONAUT WALKS INTO A SPA JWTI: JSON WEB TOKEN ‣ Open standard for representing claims securely between two parties ‣ Tokens can be signed with either a secret or public/private key ‣ Standard approach for stateless authentication ‣ Ideal for transmitting authentication & authorization data between microservices and single-page-apps
  • 40. A MICRONAUT WALKS INTO A SPA MICRONAUT SECURITY ▸ Core Micronaut Library - supports JWT, Session, Basic Auth ▸ Annotation-based API & config-based URL mappings ▸ Support for token propagation ▸ Supports RFC 6750 Bearer Token  ▸ JWTs can be read from cookie dependencies { compile "io.micronaut:micronaut-security-jwt" } micronaut: security: enabled: true token: jwt: enabled: true signatures: secret: generator: secret: changeMe APPLICATION.YML BUILD.GRADLE
  • 41. A MICRONAUT WALKS INTO A SPA @SECURED ANNOTATION ▸ @Secured annotation applied to controllers and methods ▸ All routes blocked by default ▸ Can require authentication and/or authorization (role- based) ▸ Alternative: JSR-250 security annotations are also supported: @PermitAll, @RolesAllowed, @DenyAll import java.security.Principal; @Secured("isAuthenticated()") @Controller("/") public class HomeController { @Get("/") String index(Principal principal) { return principal.getName(); } @Secured({"ROLE_ADMIN", "ROLE_X"}) @Get("/classified") String classified() { return /* REDACTED */; } }
  • 42. A MICRONAUT WALKS INTO A SPA ‣ Unauthorized request is made to API ‣ Responds with 401 ‣ Client POSTs to login endpoint ‣ Server responds with JWT ‣ Client includes access token in the Authorization header for subsequent requests ‣ Server validates the incoming token ‣ If authorized, server responds with resource MICRONAUT JWT SECURITY
  • 43. A MICRONAUT WALKS INTO A SPA ‣ POST credentials to the / login endpoint ‣ Retrieve access token from JWT and store in application state, a cookie, or local storage* JAVASCRIPT JWT SECURITY const login = (credentials, callback, errorCallback) => { fetch(`${process.env.SERVER_URL}/login`, { method: "POST", headers: new Headers({ Accept: "application/json", "Content-Type": "application/json", }), body: JSON.stringify(credentials) }) .then(response => { if (response.ok) { return response.json(); } else { throw Error(response.statusText); } }) .then(json => callback(json)) .catch(error => errorCallback(error)); }; export default { login }; AUTHCLIENT.JS import AuthClient from “./AuthClient"; AuthClient.login( { username: this.username, password: this.password }, json => /* handle login success */, error => console.error(error) ); *Local storage is not inherently secure: https://www.rdegges.com/2018/please-stop-using-local-storage/
  • 44. A MICRONAUT WALKS INTO A SPA ‣ Use custom Headers object to include access token (if using Bearer) JAVASCRIPT JWT SECURITY const securedHeaders = () => { return new Headers({ Authorization: `Bearer ${token()}`, "Content-Type": "application/json" }); }; const token = () => //retrieve token from store; export default { securedHeaders }; SECURITYUTILS.JS import { securedHeaders } from "./SecurityUtils"; fetch(`${process.env.SERVER_URL}/home`, { method: "GET", headers: securedHeaders() }) .then(response => response.text()) .then(text => (this.content = text)) .catch(error => { console.log("Connection failure: ", error); });
  • 45. A MICRONAUT WALKS INTO A SPA MICRONAUT SECURITY GUIDES https://guides.micronaut.io/tags/security.html
  • 47. MULTIPROJECT BUILDS A MICRONAUT WALKS INTO A SPA JAVASCRIPT APP BackendFrontend include "client", “server" SETTINGS.GRADLE
  • 48. GRADLE NODE PLUGIN A MICRONAUT WALKS INTO A SPA plugins { id "com.github.node-gradle.node" version "1.3.0" } node { version = '10.15.0' // https://nodejs.org/en/ yarnVersion = '1.13.0' // https://yarnpkg.com/en/ download = true } task start(type: YarnTask, dependsOn: 'yarn') { group = 'application' description = 'Run the client app' args = ['run', 'start'] } task build(type: YarnTask, dependsOn: 'yarn') { group = 'build' description = 'Build the client bundle' args = ['run', 'build'] } task test(type: YarnTask, dependsOn: 'yarn') { group = 'verification' description = 'Run the client tests' args = ['run', 'test'] } task eject(type: YarnTask, dependsOn: 'yarn') { //... } { "name": "client", "version": "0.1.0", "private": true, "dependencies": { //... }, "scripts": { "start": "react-scripts start", "build": "react-scripts build", "test": "react-scripts test", "eject": "react-scripts eject" }, ~ gradle start //yarn start Server running on http://localhost:3000 BUILD.GRADLE PACKAGE.JSON
  • 49. DEPLOYING A SPA IN A JAR
  • 50. ▸ Serve the Single-Page-App from within an executable JAR file ▸ Removes need for a separate static server ▸ SPA can be packaged with its gateway ▸ Simplifies deployment of small apps and/or IoT deployments A MICRONAUT WALKS INTO A SPA DEPLOYING A SPA IN A JAR
  • 51. ~ gradle shadowJar BUILD SUCCESSFUL in 1s DEPLOYMENT A MICRONAUT WALKS INTO A SPA JAVASCRIPT APP ~ yarn build Creating a production build... Compiled successfully.
  • 52. DEPLOYMENT A MICRONAUT WALKS INTO A SPA JAVASCRIPT APP BackendFrontend
  • 53. COMBINED BUILD A MICRONAUT WALKS INTO A SPA ~ java -jar build/libs/server-all.jar Server Running: http://localhost:8080
  • 54. STATIC ASSETS IN MICRONAUT A MICRONAUT WALKS INTO A SPA ▸ Disabled by default ▸ ▸ ▸ List of paths, starting with classpath: or file: ▸ ▸ The path from which resources should be served micronaut.router.static-resources.*.enabled micronaut.router.static-resources.*.paths micronaut.router.static-resources.*.mapping
  • 55. STATIC ASSETS IN MICRONAUT A MICRONAUT WALKS INTO A SPA micronaut: router: static-resources: default: enabled: true mapping: "/**" paths: "classpath:public" local: enabled: true mapping: “/local/**" paths: “file:path/to/files“ APPLICATION.YML
  • 56. COMBINED BUILD A MICRONAUT WALKS INTO A SPA //Copy production SPA resources into server build directory task copyClientResources(dependsOn: ':client:build') { group = 'build' description = 'Copy client resources into server' } copyClientResources.doFirst { copy { from project(':client').buildDir.absolutePath into "${project(':server').buildDir}/resources/main/public" } } //Build a single executable JAR with embedded SPA resources task assembleServerAndClient( dependsOn: ['copyClientResources', ':server:shadowJar']) { group = 'build' description = 'Build combined server & client JAR' } BUILD.GRADLE
  • 57. COMBINED BUILD A MICRONAUT WALKS INTO A SPA ~ java -jar build/libs/server-all.jar Server Running: http://localhost:8080
  • 58. MICRONAUT SINGLE-PAGE-APP GUIDE A MICRONAUT WALKS INTO A SPA https://guides.micronaut.io/micronaut-spa-react/guide/index.htmlNEW!
  • 59. A MICRONAUT WALKS INTO A SPA MICRONAUT PETSTORE https://github.com/micronaut-projects/micronaut-examples/tree/master/petstore
  • 60. A MICRONAUT WALKS INTO A SPA LEARN MORE ABOUT OCI EVENTS AND TRAINING Events: ‣ objectcomputing.com/events Training: ‣ objectcomputing.com/training ‣ grailstraining.com ‣ micronauttraining.com COME SEE US AT OUR BOOTH!
  • 61. A MICRONAUT WALKS INTO A SPA THANK YOU@ZacharyAKlein kleinz@objectcomputing.com