APACHE SLING & FRIENDS TECH MEETUP
2 - 4 SEPTEMBER 2019
Swagger AEM - An OpenAPI Specification For AEM
Cliffano Subagio and Michael Bloch, Shine Solutions Australia
About
2
▪ Cliffano Subagio and Michael Bloch

Consultants at Shine Solutions, Australia

AEM OpenCloud Core Contributors
3
Early challenges with AEM provisioning
Our first ‘AEM on the cloud’ project
4
▪ AEM 5.6 on AWS circa 2013-2014
▪ Infrastructure as code
▪ Cloud: auto-provisioning, auto-recoverable
▪ AEM tooling largely ‘Java-focused’
▪ Sysops teams use of non-Java tools
We were advised to use cURL
5
Integrate this harmless shell script with cURL!
6
set -o errexit
result=$(curl …)
if [[$result = *“error” ]]; then
exit 123
fi
Is it really harmless?
7
set -o errexit
result=$(curl …)
if [[$result = *“error” ]]; then
exit 123
fi
<- Unreliable exit code
<- Fragile error checking
<- Uninformative error result
<- No success result
Problems with AEM Web ‘API’
8
▪ cURL is not always available everywhere
▪ Inconsistent response payload types

JSON, XML, HTML
▪ Unreliable status code

Response 200 on change password error
▪ Lack of integration with various tech stacks

The world has been polyglot for a while
9
What did we do to solve this?
10
We built Swagger AEM
What is Swagger AEM?
11
▪ API specification for AEM endpoints
▪ OpenAPI version 3
▪ OpenAPI Generator
▪ API clients for 30+ languages
OpenAPI specification - metadata
12
OpenAPI specification - path
13
API Clients Generation
14
OpenAPI
Specification

swagger_aem
Ruby API Client

ruby_aem
Resource-oriented

Ruby API Client
Other languages

API Clients…
Python API Client
node.js API Client
Go API Client
What is Ruby AEM?
15
▪ Resource-oriented design Ruby API
▪ Further abstraction from AEM endpoints
▪ Error and response objects
Result handling
16
package = aem.package(‘mygroup’, ‘mypkg’, ‘1.2.3’)

opts = { force: true }

result = package.upload(‘/tmp’, opts)


puts result.message
puts result.response.status_code
puts result.response.body

puts result.response.headers
Error handling
17
begin

package = aem.package(‘mygroup’, ‘mypkg’, ‘1.2.3’)
opts = { force: true }

result = package.upload(‘/tmp’, opts)
rescue RubyAem::Error => err

puts err.message
puts err.result.response.status_code
puts err.result.response.body

puts err.result.response.headers
end
What else can Swagger AEM and Ruby AEM do?
18
▪ Replication, flush, reverse replication agents
▪ Packages, users, groups, paths, nodes
▪ Certificates, truststores, keystores
▪ Resource readiness checks with retries
▪ Many more to add in the future!
19
We also built Swagger AEM OSGI
SAML config with AEM package
20


AEM Developer



System Engineer

Please update SAML provider.
What’s the provider name?
It’s sso-provider-123.
Done. Please test.
Doesn’t work. Any typo?
How about cURL?
21
▪ curl -v -u admin:admin -F 'jcr:primaryType=sling:OsgiConfig' -F
'keyStorePassword="password"' -F 'service.ranking=I"5002"' -F 'idpHttpRedirect=B"true"' -
F 'createUser=B"true"' -F 'defaultRedirectUrl="/sites.html"' -F 'userIDAttribute="NameID"'
-F 'defaultGroups=["content-authors"]' -F 'idpCertAlias="certalias___1471833774937"' -F
'addGroupMemberships=B"true"' -F 'path=["/"]' -F
'synchronizeAttributes=["givenName=profile/givenName,familyName=profile/
familyName,mail=profile/email"]' -F 'clockTolerance=I"60"' -F
'groupMembershipAttribute="http://temp/variable/aem-groups"' -F 'idpUrl="https://
accounts.google.com/o/saml2/idp?idpid=xyz"' -F 'logoutUrl="https://
accounts.google.com/logout"' -F ‘serviceProviderEntityId="AEMSSO"' -F
'handleLogout=B"true"' -F 'spPrivateKeyAlias=""' -F 'useEncryption=B"false"' -F
'nameIdFormat="urn:oasis:names:tc:SAML:2.0:nameid-format:transient"'
What is Swagger AEM OSGI?
22
▪ API specification for AEM OSGI configurations
▪ Converted from Configuration Admin Service
▪ 71k+ lines of generated OpenAPI v3 spec
▪ 12m+ lines of generated API clients
▪ Regenerated for each AEM version
API Clients Generation
23
Configuration
Admin
Service
swagger_aem_osgi
OpenAPI Specification

swagger_aem_osgi
API Clients
In 30+ Languages

Apache Felix Web Console
24
Converted into OpenAPI specification
25
paths:
"/system/console/configMgr/Adaptive Form
post:
parameters:
- name: showPlaceholder
in: query
schema:
type: boolean
- name: maximumCacheEntries
in: query
schema:
type: integer
- name: af.scripting.compatversion
in: query
schema:
type: string
- name: makeFileNameUnique
in: query
schema:
type: boolean
- name: generatingCompliantData
in: query
schema:
type: boolean
operationId: adaptiveFormAndInteractiveCommunicationWebChannelConfigura
tags:
- configmgr
responses:
'200':
description: Successfully retrieved configuration parameters
content:
application/json:
schema:
"$ref": "#/components/schemas/adaptiveFormAndInteractiveCommu
'302':
description: Default response
content:
text/plain:
schema:
type: string
default:
description: Default response
content:
application/json:
schema:
type: string
Converted into Ruby API client code
26
27
Demo: SAML provisioning
Demo
Code flow
28
puppet-aem-resources
ruby_aem
swagger_aem_osgi
OSGI configuration
Provisioning tool
API client
AEM
29
Demo: AEM package installation via voice
Demo
Data flow
30
Install package ABC”
{ “inputs”: [
{ “intent”: “actions.intent.TEXT”,
“rawInputs”: [ {
“inputType”: “VOICE”,
“queryType”: “Install package ABC”
}]}]}
{ "queryText": “Install package ABC",
"parameters": {
"packageName": "ABC"
},
"intent": {
"displayName": “install-package"
}}
/crx/packmgr/service/.json/{path}
200 OK
{
"fulfllmentText”: "Package ABC has been installed”,
"payload”: { "google”: { "richResponse”: { "items”: [
"simpleResponse”: {
"textToSpeech”: "Package ABC has been installed”,
"displayText”: "Package ABC has been installed”,
}]}}}}
"expectedInputs": [
{
"inputPrompt": {
"richInitialPrompt": {
"items": [ { "simpleResponse": {
"textToSpeech": "Package ABC has been installed”
}}]}}}]}
“Package ABC has been installed”
31
In conclusion…
What have we learned?
32
▪ API specifications enable API clients
▪ API clients enable richer integration
▪ AEM provisioning doesn’t have to be

Java-focused
▪ Think outside the box!

Lots of DevOps tools to integrate
Most important of all…
33
You are welcome to join this effort

and contribute to benefit

the wider AEM community!
34
Thank you and any questions ?
Links
35
- https://github.com/shinesolutions/swagger-aem
- https://github.com/shinesolutions/ruby_aem
- https://github.com/shinesolutions/swagger-aem-osgi
- https://github.com/shinesolutions/adaptto-2019-demo
- https://aemopencloud.io/
- https://www.openapis.org/
- https://openapi-generator.tech/

Swagger AEM - An OpenAPI Specification for AEM

  • 1.
    APACHE SLING &FRIENDS TECH MEETUP 2 - 4 SEPTEMBER 2019 Swagger AEM - An OpenAPI Specification For AEM Cliffano Subagio and Michael Bloch, Shine Solutions Australia
  • 2.
    About 2 ▪ Cliffano Subagioand Michael Bloch
 Consultants at Shine Solutions, Australia
 AEM OpenCloud Core Contributors
  • 3.
    3 Early challenges withAEM provisioning
  • 4.
    Our first ‘AEMon the cloud’ project 4 ▪ AEM 5.6 on AWS circa 2013-2014 ▪ Infrastructure as code ▪ Cloud: auto-provisioning, auto-recoverable ▪ AEM tooling largely ‘Java-focused’ ▪ Sysops teams use of non-Java tools
  • 5.
    We were advisedto use cURL 5
  • 6.
    Integrate this harmlessshell script with cURL! 6 set -o errexit result=$(curl …) if [[$result = *“error” ]]; then exit 123 fi
  • 7.
    Is it reallyharmless? 7 set -o errexit result=$(curl …) if [[$result = *“error” ]]; then exit 123 fi <- Unreliable exit code <- Fragile error checking <- Uninformative error result <- No success result
  • 8.
    Problems with AEMWeb ‘API’ 8 ▪ cURL is not always available everywhere ▪ Inconsistent response payload types
 JSON, XML, HTML ▪ Unreliable status code
 Response 200 on change password error ▪ Lack of integration with various tech stacks
 The world has been polyglot for a while
  • 9.
    9 What did wedo to solve this?
  • 10.
  • 11.
    What is SwaggerAEM? 11 ▪ API specification for AEM endpoints ▪ OpenAPI version 3 ▪ OpenAPI Generator ▪ API clients for 30+ languages
  • 12.
  • 13.
  • 14.
    API Clients Generation 14 OpenAPI Specification
 swagger_aem RubyAPI Client
 ruby_aem Resource-oriented
 Ruby API Client Other languages
 API Clients… Python API Client node.js API Client Go API Client
  • 15.
    What is RubyAEM? 15 ▪ Resource-oriented design Ruby API ▪ Further abstraction from AEM endpoints ▪ Error and response objects
  • 16.
    Result handling 16 package =aem.package(‘mygroup’, ‘mypkg’, ‘1.2.3’)
 opts = { force: true }
 result = package.upload(‘/tmp’, opts) 
 puts result.message puts result.response.status_code puts result.response.body
 puts result.response.headers
  • 17.
    Error handling 17 begin
 package =aem.package(‘mygroup’, ‘mypkg’, ‘1.2.3’) opts = { force: true }
 result = package.upload(‘/tmp’, opts) rescue RubyAem::Error => err
 puts err.message puts err.result.response.status_code puts err.result.response.body
 puts err.result.response.headers end
  • 18.
    What else canSwagger AEM and Ruby AEM do? 18 ▪ Replication, flush, reverse replication agents ▪ Packages, users, groups, paths, nodes ▪ Certificates, truststores, keystores ▪ Resource readiness checks with retries ▪ Many more to add in the future!
  • 19.
    19 We also builtSwagger AEM OSGI
  • 20.
    SAML config withAEM package 20 
 AEM Developer
 
 System Engineer
 Please update SAML provider. What’s the provider name? It’s sso-provider-123. Done. Please test. Doesn’t work. Any typo?
  • 21.
    How about cURL? 21 ▪curl -v -u admin:admin -F 'jcr:primaryType=sling:OsgiConfig' -F 'keyStorePassword="password"' -F 'service.ranking=I"5002"' -F 'idpHttpRedirect=B"true"' - F 'createUser=B"true"' -F 'defaultRedirectUrl="/sites.html"' -F 'userIDAttribute="NameID"' -F 'defaultGroups=["content-authors"]' -F 'idpCertAlias="certalias___1471833774937"' -F 'addGroupMemberships=B"true"' -F 'path=["/"]' -F 'synchronizeAttributes=["givenName=profile/givenName,familyName=profile/ familyName,mail=profile/email"]' -F 'clockTolerance=I"60"' -F 'groupMembershipAttribute="http://temp/variable/aem-groups"' -F 'idpUrl="https:// accounts.google.com/o/saml2/idp?idpid=xyz"' -F 'logoutUrl="https:// accounts.google.com/logout"' -F ‘serviceProviderEntityId="AEMSSO"' -F 'handleLogout=B"true"' -F 'spPrivateKeyAlias=""' -F 'useEncryption=B"false"' -F 'nameIdFormat="urn:oasis:names:tc:SAML:2.0:nameid-format:transient"'
  • 22.
    What is SwaggerAEM OSGI? 22 ▪ API specification for AEM OSGI configurations ▪ Converted from Configuration Admin Service ▪ 71k+ lines of generated OpenAPI v3 spec ▪ 12m+ lines of generated API clients ▪ Regenerated for each AEM version
  • 23.
    API Clients Generation 23 Configuration Admin Service swagger_aem_osgi OpenAPISpecification
 swagger_aem_osgi API Clients In 30+ Languages

  • 24.
    Apache Felix WebConsole 24
  • 25.
    Converted into OpenAPIspecification 25 paths: "/system/console/configMgr/Adaptive Form post: parameters: - name: showPlaceholder in: query schema: type: boolean - name: maximumCacheEntries in: query schema: type: integer - name: af.scripting.compatversion in: query schema: type: string - name: makeFileNameUnique in: query schema: type: boolean - name: generatingCompliantData in: query schema: type: boolean operationId: adaptiveFormAndInteractiveCommunicationWebChannelConfigura tags: - configmgr responses: '200': description: Successfully retrieved configuration parameters content: application/json: schema: "$ref": "#/components/schemas/adaptiveFormAndInteractiveCommu '302': description: Default response content: text/plain: schema: type: string default: description: Default response content: application/json: schema: type: string
  • 26.
    Converted into RubyAPI client code 26
  • 27.
  • 28.
  • 29.
    29 Demo: AEM packageinstallation via voice Demo
  • 30.
    Data flow 30 Install packageABC” { “inputs”: [ { “intent”: “actions.intent.TEXT”, “rawInputs”: [ { “inputType”: “VOICE”, “queryType”: “Install package ABC” }]}]} { "queryText": “Install package ABC", "parameters": { "packageName": "ABC" }, "intent": { "displayName": “install-package" }} /crx/packmgr/service/.json/{path} 200 OK { "fulfllmentText”: "Package ABC has been installed”, "payload”: { "google”: { "richResponse”: { "items”: [ "simpleResponse”: { "textToSpeech”: "Package ABC has been installed”, "displayText”: "Package ABC has been installed”, }]}}}} "expectedInputs": [ { "inputPrompt": { "richInitialPrompt": { "items": [ { "simpleResponse": { "textToSpeech": "Package ABC has been installed” }}]}}}]} “Package ABC has been installed”
  • 31.
  • 32.
    What have welearned? 32 ▪ API specifications enable API clients ▪ API clients enable richer integration ▪ AEM provisioning doesn’t have to be
 Java-focused ▪ Think outside the box!
 Lots of DevOps tools to integrate
  • 33.
    Most important ofall… 33 You are welcome to join this effort
 and contribute to benefit
 the wider AEM community!
  • 34.
    34 Thank you andany questions ?
  • 35.
    Links 35 - https://github.com/shinesolutions/swagger-aem - https://github.com/shinesolutions/ruby_aem -https://github.com/shinesolutions/swagger-aem-osgi - https://github.com/shinesolutions/adaptto-2019-demo - https://aemopencloud.io/ - https://www.openapis.org/ - https://openapi-generator.tech/