Slide 1

Slide 1 text

Six Polite Ways to Design a RESTful API for your Domino Application! Serdar Basegmez Developi Informa/on Systems @serdar_basegmez

Slide 2

Slide 2 text

• Developi Information Systems, London • Notes/Domino/XPages/Java Developer, half-blooded admin! • Member Director at OpenNTF Board • HCL Ambassador (2020) • IBM Champion Alumni (2011 - 2018) • Blog: LotusNotus.com / Twitter: @serdar_basegmez • Also blogging/speaking/podcasting on scientific skepticism / critical thinking Serdar Basegmez 2

Slide 3

Slide 3 text

• Why should you care? • RESTful APIs • Practical Implications of RESTful Architectures • Designing an API • Ways to Provide REST Services for HCL Domino • Tools • Wrap-up 3 Agenda

Slide 4

Slide 4 text

• New Front-ends and Enhanced UX – Facelifting, but keeping data and business logic in NSF. – JS Frameworks (e.g. Angular, React), Mobile Apps, etc. – Richer experiences with chatbots, AI, etc. • Integration for third party sites/applications – IT becomes a huge jungle, we can’t walk alone! – Financial Systems, AI Systems, CRM, S/M Automation – Collaborative Apps, Office 365 • Automating processes using APIs – Domino Apps not independent from Business Processes – Accounting/Sales/Marketing/ERP Processes 4 Why Should You Care? User Experience Business Processes Integration

Slide 5

Slide 5 text

RESTful Web Services Representational state transfer (REST) is an architectural style used for web development. Systems and sites designed using this style aim for fast performance, reliability and the ability to scale (to grow and easily support extra users). To achieve these goals, developers work with reusable components that can be managed and updated without affecting the system as a whole while it is running. 5 Source: https://en.wikipedia.org/wiki/Representational_state_transfer

Slide 6

Slide 6 text

History

Slide 7

Slide 7 text

Source: https://speakerdeck.com/jeffschenck/rest-easy-api-security-done-right User Interface Business Logic Datastore Front-end Back-end ASP, PHP, CGI, Web Agents, JSP, etc. ← HTML, CSS, JavaScript Forms → Old School Web Applications 7

Slide 8

Slide 8 text

8 User Interface Business Logic Datastore Front-end Back-end Async web apps, Ruby on Rails, Django, JSF, XPages, etc. ← HTML, CSS, JavaScript Forms, AJAX → Web Applications Evolving

Slide 9

Slide 9 text

9 User Interface Business Logic Datastore Front-end Back-end Modern Web frameworks, Angular.js, React.js, etc. ← HTML, CSS, JavaScript ← REST → Web Applications Evolving

Slide 10

Slide 10 text

10 User Interface Business Logic Datastore Mobile Applications Back-end Modern Web frameworks, Angular.js, React.js, etc. ← HTML, CSS, JavaScript ← REST → Front-end [Web] Applications Evolving

Slide 11

Slide 11 text

11 User Interface Business Logic Datastore Mobile Applications Back-end Modern Web frameworks, Angular.js, React.js, etc. ← HTML, CSS, JavaScript ← REST → Front-end Microservice Microservice Microservice [Web] Applications Evolving

Slide 12

Slide 12 text

12 Back-end Modern Web frameworks, Angular.js, React.js, etc. ← HTML, CSS, JavaScript ← REST → User Interface Business Logic Datastore Mobile Applications Front-end External Apps Microservice Microservice Microservice Integration [Web] Applications Evolving

Slide 13

Slide 13 text

RESTful, Everywhere! Solid Architecture Well-defined practices Widespread use Easily consumable Scalable

Slide 14

Slide 14 text

The Conversation Makes Sense! Source: http://www.bizcoder.com/a-fresh-coat-of-rest-paint-on-a-soap-stack

Slide 15

Slide 15 text

The Conversation Makes Sense! GET /twink/contacts/DLEY-ACLH6Y HTTP/1.1 Host: homer.developi.info Cache-Control: no-cache { "zip": "13202", "state": "NY", "lastName": "Abbate", "middle": "J", "country": "US", "emailAddress": "Jessica.J.Abbate@trashymail.com", "number": "DLEY-ACLH6Y", "city": "Syracuse", "firstName": "Jessica" }

Slide 16

Slide 16 text

The Conversation Makes Sense! http://appserver.company.com/apps/contacts.nsf/ GiveMeTheContactWeNeedPleaseAgent?OpenAgent&id=1522 vs. http://appserver.company.com/api/contacts/1522

Slide 17

Slide 17 text

Conventions on URLs GET http://appserver.company.com/api/contacts GET http://appserver.company.com/api/contacts/UK/London POST http://appserver.company.com/api/contacts Retrieve Contacts / Create a new Contact…

Slide 18

Slide 18 text

Conventions on URLs GET http://appserver.company.com/api/contacts/1522 PUT http://appserver.company.com/api/contacts/1522 DELETE http://appserver.company.com/api/contacts/1522 Retrieve/Update/Delete the Contact resource with id=1522…

Slide 19

Slide 19 text

Designing RESTful APIs… Design-first vs Code-first?

Slide 20

Slide 20 text

• Collaboration Today API – Alternative front-end – Integrate to different consumers – Keep the data in NSF – Reuse current implementation • Three Sections: – Presentation (Reading News) – Curation (Adding/Publishing News) – RSS Feeding (DOTS FeedMonster) 20 Example: Collaboration Today API

Slide 21

Slide 21 text

21 CollaborationToday API Recent Stories Stories By Author Story fields needed List Tags/Categories Stories By Tag

Slide 22

Slide 22 text

22 CollaborationToday API

Slide 23

Slide 23 text

23 CollaborationToday API

Slide 24

Slide 24 text

• Contract Design – URLs (Resources + Verbs) – Data formats – Rules, Success and Error Responses • Tip: – Start with the end product. – Write a documentation first, before coding. – No “correct way”, only “best practices” – Follow Conventions 24 Designing RESTful API * Icons made by Flat Icons from www.flaticon.com

Slide 25

Slide 25 text

• Security Design – Authentication / Authorization – Administration Lifecycle – Application Security • Tips – The scope of the implementation is the key. – Managing security is often overlooked. – Security starts with the design phase. 25 Designing RESTful API * Icons made by Flat Icons from www.flaticon.com

Slide 26

Slide 26 text

• Versioning – Enumeration, Lifecycle • Documentation – OpenAPI Specs (a.k.a. Swagger) – Generate Server stubs, client libraries – Interactive documentation • Testing – Automated testing 26 Designing RESTful API * Icons made by Flat Icons from www.flaticon.com /v1/api/xyz /v2/api/xyz /api1/xyz /api2/xyz

Slide 27

Slide 27 text

RESTful Services for HCL Domino Applications Review of our options…

Slide 28

Slide 28 text

1. Domino Access Services 2. Using Extension Library Components 3. Hardcoding Services (Web Agents, XAgents, Servlets) 4. OSGi Plugins to implement JAX-RS 5. Node.js Applications with App.Dev.Pack 6. Unconventional implementations – SmartNSF, JAX-RS inside NSF, JAX-RS outside Domino – Hybrid Methods 28 6 Polite Ways of RESTful Domino

Slide 29

Slide 29 text

Domino Access Services 29 HCL Supported Fully Func8onal REST API Access to Data / Calendar / Mail* / Freebusy* / Directory** * Mail and Freebusy access is part of the core product since 9.0.1FP10 / ** Directory access is enabled with the ExtLib version of OpenNTF Caching / Na8ve Security (ACL, Reader/Author fields, etc.) Server-level / Database-level / Design-level control Enable on Server Enable For Database Enable For Views

Slide 30

Slide 30 text

• OpenAPI definitions (Swagger) are hosted on OpenNTF! –https://github.com/OpenNTF/das-api-specs 30 Domino Access Services

Slide 31

Slide 31 text

– Drawbacks – Weak control over the data! • No checkpoints on CRUD, No coding involved… – No place for business logic! – Exposes internals – Not optimized for some use cases – Trust is the key! 31 Domino Access Services

Slide 32

Slide 32 text

• Provided and Supported by HCL • Customizable component version of the DAS – Computed/Filtered columns, Custom search, etc. – Event model helps building business logic on top of REST model • Custom REST Service – Write your own SSJS or Java bean • Write your CSJS routines for async access – Remote Service / JSON-RPC – Dojo support for single page model 32 REST Components (ExtLib)

Slide 33

Slide 33 text

• Setup REST component(s) on your page. • Minimal coding, no administrator needed. 33 REST Components (ExtLib) Add to your XPage Add a Service Configure Options

Slide 34

Slide 34 text

• Drawbacks: – Easy to slip into a spagetti code! – Not optimized for performance and scalability – Difficult to follow RESTful URL Convention 34 REST Components (ExtLib) https://someserver.domain.com/database.nsf/somepage.xsp/service/…

Slide 35

Slide 35 text

• Old school way; still quite useful for some cases. • Great if you have pre-existing code (e.g. Lotusscript libraries, etc.) • Also, useful to prototype quick ideas. • Customizable, flexible and simple way to create any service. 35 Hardcoding (Web agents, XAgents, Servlets…)

Slide 36

Slide 36 text

• Drawbacks: – Hardcode everything… • e.g. Header/parameter extraction – Very easy to slip into a spagetti code! • Error handling / proper testing needed – Difficult to follow RESTful URL Convention 36 Hardcoding (Web agents, XAgents, Servlets…) https://someserver.domain.com/database.nsf/xagent.xsp?… https://someserver.domain.com/database.nsf/someagent?OpenAgent&…

Slide 37

Slide 37 text

• JAX-RS: ‘Java-ish’ way to define RESTful services – Create JAX-RS based REST services on top of OSGi plugins. – Complete Java solution, extensible with custom providers • Options – Apache Wink 1.1.2 (DAS uses!) – Jakarta EE (Official Java) – RestEasy, Apache CXF, Jersey, etc. • Code reusability outside HCL Domino world. 37 Java (JAX-RS) with OSGi Plugins

Slide 38

Slide 38 text

38 JAX-RS Architecture JAX-RS Runtime Application Code Servlet (Customizable) HTTP/HTTPS Client Datastore(s) Resource Resource Resource Resource Controllers Data Accessors Tools/Utilities Request/Response Wrappers Context Helpers /BaseURI/* /BaseURI/Path-Patterns

Slide 39

Slide 39 text

39 JAX-RS Development @Path("/contacts") public class ContactResource { private DominoAccessor accessor = new DominoAccessor(ContextInfo.getUserSession()); @GET() public Response getContactList( @QueryParam("start") int start, @QueryParam("count") int count) { List contactList = accessor.pullContacts(start, count); String result = ModelUtils.toJson(contactList).toString(); return Response.ok(result, MediaType.APPLICATION_JSON).build(); } @Path("/{id}") @GET() public Response getContact(@PathParam("id") String id) { Contact contact = accessor.findContact(id); if(null == contact) { throw new WebApplicationException(Response.Status.NOT_FOUND); } else { String result = ModelUtils.toJson(contact).toString(); return Response.ok(result, MediaType.APPLICATION_JSON).build(); } } } { "zip": "13202", "state": "NY", "lastName": "Abbate", "middle": "J", "country": "US", "emailAddress": "Jessica.J.Abbate@trashymail.com", "number": "DLEY-ACLH6Y", "city": "Syracuse", "firstName": "Jessica" } Contact Resource Class Contact Resource Short JSON Representation

Slide 40

Slide 40 text

@Path("/contacts") public class ContactResource { private DominoAccessor accessor = new DominoAccessor(ContextInfo.getUserSession()); @GET() public Response getContactList( @QueryParam("start") int start, @QueryParam("count") int count) { List contactList = accessor.pullContacts(start, count); String result = ModelUtils.toJson(contactList).toString(); return Response.ok(result, MediaType.APPLICATION_JSON).build(); } @Path("/{id}") @GET() public Response getContact(@PathParam("id") String id) { Contact contact = accessor.findContact(id); if(null == contact) { throw new WebApplicationException(Response.Status.NOT_FOUND); } else { String result = ModelUtils.toJson(contact).toString(); return Response.ok(result, MediaType.APPLICATION_JSON).build(); } } } 40 The base URI for the resource In the demo, the root path of the plugin is “/twink”. So this class is enabled for requests made to: /twink/contacts/* JAX-RS Development

Slide 41

Slide 41 text

@Path("/contacts") public class ContactResource { private DominoAccessor accessor = new DominoAccessor(ContextInfo.getUserSession()); @GET() public Response getContactList( @QueryParam("start") int start, @QueryParam("count") int count) { List contactList = accessor.pullContacts(start, count); String result = ModelUtils.toJson(contactList).toString(); return Response.ok(result, MediaType.APPLICATION_JSON).build(); } @Path("/{id}") @GET() public Response getContact(@PathParam("id") String id) { Contact contact = accessor.findContact(id); if(null == contact) { throw new WebApplicationException(Response.Status.NOT_FOUND); } else { String result = ModelUtils.toJson(contact).toString(); return Response.ok(result, MediaType.APPLICATION_JSON).build(); } } } 41 This method responds to GET requests. No path defined, so this is the default responder. JAX-RS Development

Slide 42

Slide 42 text

@Path("/contacts") public class ContactResource { private DominoAccessor accessor = new DominoAccessor(ContextInfo.getUserSession()); @GET() public Response getContactList( @QueryParam("start") int start, @QueryParam("count") int count) { List contactList = accessor.pullContacts(start, count); String result = ModelUtils.toJson(contactList).toString(); return Response.ok(result, MediaType.APPLICATION_JSON).build(); } @Path("/{id}") @GET() public Response getContact(@PathParam("id") String id) { Contact contact = accessor.findContact(id); if(null == contact) { throw new WebApplicationException(Response.Status.NOT_FOUND); } else { String result = ModelUtils.toJson(contact).toString(); return Response.ok(result, MediaType.APPLICATION_JSON).build(); } } } 42 This method also responds to GET requests. But it the request path will be elected based on this format. JAX-RS Development

Slide 43

Slide 43 text

@Path("/contacts") public class ContactResource { private DominoAccessor accessor = new DominoAccessor(ContextInfo.getUserSession()); @GET() public Response getContactList( @QueryParam("start") int start, @QueryParam("count") int count) { List contactList = accessor.pullContacts(start, count); String result = ModelUtils.toJson(contactList).toString(); return Response.ok(result, MediaType.APPLICATION_JSON).build(); } @Path("/{id}") @GET() public Response getContact(@PathParam("id") String id) { Contact contact = accessor.findContact(id); if(null == contact) { throw new WebApplicationException(Response.Status.NOT_FOUND); } else { String result = ModelUtils.toJson(contact).toString(); return Response.ok(result, MediaType.APPLICATION_JSON).build(); } } } 43 Parameters will be injected into methods. /contacts?start=X&count=Y /contacts/someId JAX-RS servlet will handle type conversion. It supports ordinary java objects, enums, primitives, etc. JAX-RS Development

Slide 44

Slide 44 text

@Path("/contacts") public class ContactResource { private DominoAccessor accessor = new DominoAccessor(ContextInfo.getUserSession()); @GET() public Response getContactList( @QueryParam("start") int start, @QueryParam("count") int count) { List contactList = accessor.pullContacts(start, count); String result = ModelUtils.toJson(contactList).toString(); return Response.ok(result, MediaType.APPLICATION_JSON).build(); } @Path("/{id}") @GET() public Response getContact(@PathParam("id") String id) { Contact contact = accessor.findContact(id); if(null == contact) { throw new WebApplicationException(Response.Status.NOT_FOUND); } else { String result = ModelUtils.toJson(contact).toString(); return Response.ok(result, MediaType.APPLICATION_JSON).build(); } } } 44 There are lots of options of returning response. ResponseBuilders and some other helpers make it quite easy. JAX-RS Development

Slide 45

Slide 45 text

@Path("/contacts") public class ContactResource { private DominoAccessor accessor = new DominoAccessor(ContextInfo.getUserSession()); @GET() public Response getContactList( @QueryParam("start") int start, @QueryParam("count") int count) { List contactList = accessor.pullContacts(start, count); String result = ModelUtils.toJson(contactList).toString(); return Response.ok(result, MediaType.APPLICATION_JSON).build(); } @Path("/{id}") @GET() public Response getContact(@PathParam("id") String id) { Contact contact = accessor.findContact(id); if(null == contact) { throw new WebApplicationException(Response.Status.NOT_FOUND); } else { String result = ModelUtils.toJson(contact).toString(); return Response.ok(result, MediaType.APPLICATION_JSON).build(); } } } 45 Error handling is handled by the JAX-RS engine as well. You can inject your own errors. JAX-RS Development

Slide 46

Slide 46 text

@Path("/contacts") public class ContactResource { ………… @POST() @Consumes(MediaType.APPLICATION_JSON) public Response postContactJson(String body) { Contact contact = ModelUtils.buildContactfromJson(body); accessor.saveNewContact(contact); String result = ModelUtils.toJson(contact).toString(); return Response.ok(result, MediaType.APPLICATION_JSON).build(); } @POST() @Consumes(MediaType.MULTIPART_FORM_DATA) public Response postContactForm(BufferedInMultiPart formData) { Contact contact = ModelUtils.buildContactfromMultipart(formData); accessor.saveNewContact(contact); String result = ModelUtils.toJson(contact).toString(); return Response.ok(result, MediaType.APPLICATION_JSON).build(); } } 46 This methods respond to POST requests. This time the selection depends on the incoming data type. Client marks the request with Content-Type header and Request processor will select the appropriate method here. JAX-RS Development

Slide 47

Slide 47 text

@Path("/contacts") public class ContactResource { ………… @POST() @Consumes(MediaType.APPLICATION_JSON) public Response postContactJson(String body) { Contact contact = ModelUtils.buildContactfromJson(body); accessor.saveNewContact(contact); String result = ModelUtils.toJson(contact).toString(); return Response.ok(result, MediaType.APPLICATION_JSON).build(); } @POST() @Consumes(MediaType.MULTIPART_FORM_DATA) public Response postContactForm(BufferedInMultiPart formData) { Contact contact = ModelUtils.buildContactfromMultipart(formData); accessor.saveNewContact(contact); String result = ModelUtils.toJson(contact).toString(); return Response.ok(result, MediaType.APPLICATION_JSON).build(); } } 47 Wink injects the incoming data into the method automatically. JAX-RS libraries provide their own implementation to process different data formats (Multipart, Atom, XML, JSON, etc.) JAX-RS Development

Slide 48

Slide 48 text

48 On Apache Wink… h.ps://speakerdeck.com/sbasegmez/iconuk-2016-rest-assured... On Jakarta EE… (by Jesse Gallagher) h.ps://github.com/OpenNTF/org.opennC.xsp.jakartaee For More Detail on JAX-RS…

Slide 49

Slide 49 text

• Drawbacks: – Plugin only • Difficult if you are not familiar, Takes time to learn – Overkill? • Not suitable for small projects and simple needs – Tool selection is critical. • Apache Wink is old school • Integrating alternatives might be difficult 49 JAX-RS Methods

Slide 50

Slide 50 text

• DQL + Domino AppDev Pack: – Domino Query Language – AppDev Pack: Proton Task / domino-db.js • Countless opportunities in the most popular framework • Different possibilities for the architecture • Wide range of options for tooling 50 Node.js https://insights.stackoverflow.com/survey/2019

Slide 51

Slide 51 text

51 Node.js Support for Domino Apps HCL Domino Server Proton Node.js Layer domino-db.js GRPC Application ……… Application REST New Add-on Domino v10 Routers for the RESTful service Might be on the same box or not MyRoutes.js NSF

Slide 52

Slide 52 text

52 Node.js Support for Domino Apps Node.js Layer domino-db.js Routers for the RESTful service MyRoutes.js https://github.com/sbasegmez/Engage19Demo/

Slide 53

Slide 53 text

• Available since Domino V10 • Optimized query access to NSF data • Server extracts and optimizes data for DQL access • Evolving fast! • Watch for next sessions! 53 DQL: Domino Query Language John Curtis, “Factory Tour DQL Performance Explanation”, https://jdcurtis.blog/2019/07/17/factory-tour-dql-performance-explanation/

Slide 54

Slide 54 text

54 IAM: Identity and Access Management * IAM Setup documentation - https://doc.cwpcollaboration.com/appdevpack/docs/en/iam_setup.html

Slide 55

Slide 55 text

• Unconventional implementations • Why? – Specific needs – Matching skills – Prefer solutions with less effort • Why not? – No support – Version lock-in – Expertise needed 55 Other Implementations

Slide 56

Slide 56 text

SmartNSF • OpenNTF Plugin – Beta-7 version (2018). • Developers: – Christian Güdemann – Martin Jinoch • Define your REST Services from DDE! – Uses Groovy • Auto-generate OpenAPI definitions 56 Looking for Contributors!

Slide 57

Slide 57 text

JAX-RS inside NSF • Initial work: Martin Pradny • Included in Jakarta EE by Jesse Gallagher • JAX-RS 2.1 support (Apache Wink uses 1.1) • No need to deal with OSGi • Directly create annotated classes inside NSF • OpenAPI specs annotations supported! 57 https://www.pradny.com/2019/05/using-jax-rs-inside-nsf-follow-up.html

Slide 58

Slide 58 text

• Implementation: Jesse Gallagher – Inspired by Sven Hasselbach • Run Java EE server – e.g. Open Liberty, open source variant of Websphere Liberty • Run Domino HTTP Stack side by side • Deploy Java EE projects connecting to Domino data natively. • HTTP/2, Servlet 4, Websockets, etc. • High performance, scalability 58 Integrate Domino into Open Liberty https://frostillic.us/blog/posts/2019/1/3/be9501a07279b40d85258377007b0dfd

Slide 59

Slide 59 text

Hybrid Approaches • Wrap services using a suitable front-end – e.g. Express, Node-RED, etc. • Add some magic – Extra processing, computation, security, etc. • Wrap missing parts from existing assets • Combine best of all worlds • Consistency across the solution • Optimized Implementation 59 Internal Network Domino Server Node.js JAX-RS Service ExtLib REST Service DAS - Data API Proton domino-db.js JavaScript Services Wrapped Services Data / Application Layer Non-Domino Services API Clients API Clients API Clients DMZ

Slide 60

Slide 60 text

Tools… Documentation and Testing

Slide 61

Slide 61 text

• OpenAPI Specifications / Documentation – Swagger Tools - swagger.io – Stoplight Studio - stoplight.io – Apicurio - apicur.io 61 Tooling - OpenAPI

Slide 62

Slide 62 text

• Testing – Postman - postman.com – Paw - paw.cloud [Mac only] – SoapUI - soapui.org 62 Tooling - Testing

Slide 63

Slide 63 text

Thank you! Serdar Basegmez Developi Information Systems, London serdar_basegmez lotusnotus.com

Slide 64

Slide 64 text

• Serdar Başeğmez: Node.js demo for this session
 https://github.com/sbasegmez/Engage19Demo • Tom Van Aken: Rest calls and JSON Parsing in LotusScript
 https://vanakentom.wordpress.com/2019/01/15/rest-calls-and-json-parsing-in-lotusscript/ • Serdar Başeğmez: Demo for IBM Connect 2017 session
 https://github.com/sbasegmez/IC17RestDemo • Serdar Başeğmez: Apache Wink Template and Demo for Icon UK 2016
 https://github.com/sbasegmez/RestAssuredDemo • Graham Acres / Serdar Başeğmez: The Journey to Becoming a Social Application Developer (IBM Connect 2014)
 https://speakerdeck.com/sbasegmez/bp308-the-journey-to-becoming-a-social-application-developer • Stephan H. Wissel: Custom REST service in XPages using a service bean
 https://wissel.net/blog/d6plinks/SHWL-9Q55QL 64 Resources

Slide 65

Slide 65 text

• Eric McCormick: Series on JSON Data with Java in XPages
 https://edm00se.io/json-with-java-in-xpages • Thomas Ladehoff: REST Services with the XPages Extension Library
 https://www.assono.de/blog/d6plinks/REST-Services-with-the-XPages-Extension-Library • Paul Withers: XPages OSGi Plugins series
 http://www.intec.co.uk/xpages-osgi-plugins-1-an-introduction/ • John Cooper: Domino OSGI (Part 1) - Configuring Eclipse for XPages OSGI Plugins
 http://developmentblog.johnmcooper.co.uk/2014/05/configuring-eclipse-for-xpages-osgi-plugins- part1.html • Toby Samples: JAX-RS or THE way to do REST in Domino series
 https://tobysamples.wordpress.com/2015/04/28/jax-rs-or-the-way-to-do-rest-in-domino-part-1/ • Jesse Gallagher: Eclipse Tutorial for Domino Developers
 https://github.com/jesse-gallagher/eclipse-tutorial-oct2015/wiki/Java 65 Resources (cont.)

Slide 66

Slide 66 text

• Ulrich Krause: NotesJsonNavigator, NotesJsonElement, NotesJsonArray, NotesJsonObject example
 https://www.eknori.de/2019-01-01/notesjsonnavigator-notesjsonelement-notesjsonarray- notesjsonobject-example/ • John Dalsgaard: REST Services in IBM Domino/XWork
 https://www.dalsgaard-data.eu/blog/rest-services-in-ibm-dominoxwork • Oliver Busse: First dive into Domino and Node.js
 http://oliverbusse.notesx.net/hp.nsf/blogpost.xsp?documentId=2E52 • Oliver Busse: Domino, Proton, IAM, OAuth (Series)
 http://oliverbusse.notesx.net/hp.nsf/blogpost.xsp?documentId=2FEA • Sven Hasselbach: node.js, domino-db & Docker
 http://hasselba.ch/blog/?p=2670 • Jesse Gallagher: That Java Thing, Part 1: The Java Problem in the Community
 https://frostillic.us/blog/thread.xsp?thread=That+Java+Thing 66 Resources (cont.)

Slide 67

Slide 67 text

• Graham Acres / Heiko Voigt: Engage 2019 Demo of Domino v10, Proton and Node.js session 
 https://github.com/c3ug/engage2019democode • Troy Reimer: OpenNTF Project: LotusScript implementation of a reader and writer for JSON
 https://openntf.org/main.nsf/project.xsp?r=project/JSON%20LotusScript%20Classes • Bansilal Haudakari: Effective API Design 
 https://www.slideshare.net/BansilalHaudakari/effective-api-design • Heiko Voigt: How to set up the Domino 10 OAUTH2 Provider - IAM Basics 
 https://www.harbour-light.org/2019/02/18/how-to-set-up-the-domino-10-oauth2-provider-iam-basics/ • Martin Pradny: Using JAX-RS inside NSF follow-up - Swagger UI 
 https://www.pradny.com/2019/05/using-jax-rs-inside-nsf-follow-up.html • Cross Canada Collaboration User Group: John Curtis - Domino Query Language with John Curtis Part 1
 https://www.youtube.com/watch?v=qm_LJ9-6OTE 67 Resources (cont.)

Slide 68

Slide 68 text

DNUG e.V. Pappelallee 78/79 10437 Berlin Telefon: +49 30 20898805 0 Telefax: +49 30 20898805 1 E-Mail: info@dnug.de Web: http://www.dnug.de 68