%in ivory park+277-882-255-28 abortion pills for sale in ivory park
ICONUK 2016: REST Assured, Freeing Your Domino Data Has Never Been That Easy!
1. REST Assured, Freeing Your Domino Data
Has Never Been That Easy!
Serdar Basegmez, Developi Information Systems
16th September 2016
2. • IBM Champion (2011 - 2016)
• Developi Information Systems, Istanbul
• Contributing…
• OpenNTF / LUGTR / LotusNotus.com
• Featured on…
• Engage UG, IBM Connect, ICON UK, NotesIn9…
• Also…
• Blogger and Podcaster on Scientific Skepticism
Serdar Başeğmez
3. 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.
Source: https://en.wikipedia.org/wiki/Representational_state_transfer
5. Old School Web Applications
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 →
6. Web Applications Evolving
User Interface Business Logic Datastore
Front-end Back-end
Async web apps, Ruby on Rails, Django, JSF, XPages, etc.
← HTML, CSS, JavaScript
Forms, AJAX →
7. Web Applications Evolving
User Interface Business Logic Datastore
Front-end Back-end
Modern Web frameworks, Angular.js, React.js, etc.
← HTML, CSS, JavaScript
← REST →
8. Web Applications Evolving
User Interface Business Logic Datastore
Mobile Applications
Back-end
Modern Web frameworks, Angular.js, React.js, etc.
← HTML, CSS, JavaScript
← REST →
Front-end
9. Web Applications Evolving
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
11. Stateless / Cacheable / Layered
Every request processed independently
Everything cacheable
Client does not care who cooked the meal in the kitchen
⇣
Scalable, Robust, Resilient
12. The Conversation Makes Sense!
Source: http://www.bizcoder.com/a-fresh-coat-of-rest-paint-on-a-soap-stack
14. The Conversation Makes Sense!
http://appserver.company.com/apps/contacts.nsf/
GiveMeTheContactWeNeedPleaseAgent?OpenAgent&id=1522
or…
http://appserver.company.com/api/contacts/1522
15. 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…
16. 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…
17. URI GET PUT POST DELETE
/contacts/ List Contacts Replace Contacts Create New Contact Delete Contacts
/contacts/id Retrieve a Contact Replace a Contact N/A (generally) Delete a Contact
Source: https://en.wikipedia.org/wiki/Representational_state_transfer
Conventions on URLs
18. Unconventional uses in URLs
GET https://api.twitter.com/1.1/statuses/show.json?id=1234567890
Retrieve the Tweet with id=1234567890…
20. Motivation
Putting stuff into a small device!
Socializing with other developers!
Opening to the wild… New animals out there!
Enough! We are moving…
All / Some / None of the above
21. Options
Domino Access Services (DAS)
Extension Library Components for REST
Hardcoding (XAgents, Web agents)
Apache Wink Servlets
22. RESTful Options on Domino
Benefits Challenges Suggested When?
Domino Access Services
(DAS)
No Backend Code
Zero-setup
Limited Control
No Business Logic
Exposes the Internals
Simple internal integrations
ExtLib Components
for REST
Less Backend Code
Minimal Setup
Partial/Full Customization
Error Handling
Spaghetti Code
URL Conventions
Simple needs for a limited
scope
Hardcoding
(XAgents, Web agents)
Tailor-made
No Learning Curve
Hardcoding Everything
Spaghetti Code
URL Conventions
Very specific needs for a
limited scope
Apache Wink Servlets
Tailor-made
Based on JAX-RS
OSGi Benefits
Learning Curve
Barrier to Entry
Large scope
implementations, API
Design
23. Apache Wink Project
Complete implementation of JAX-RS v1.1 Specification
Also includes RESTful Client module
Extension Library comes with Apache Wink 1.1.2
Open Source
Spring integration, WebDAV support
25. Resource and Resource Representation
Collection
ResourceResourceResource
SubresourceSubresourceSubresource
Resource
• Any addressable object is a resource.
• A resource class is;
• Implements RESTful interactions (GET, POST, etc.)
• A pure Java object decorated with annotations
• Do not confuse with Model class.
Resource Representation
• The content of an object is called as Representation
• JSON, XML, Text, Form data, etc.
26. @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<Contact> 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
27. Resources
@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<Contact> 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();
}
}
}
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/*
29. Resources
@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<Contact> 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();
}
}
}
This method responds to
GET requests.
No path defined, so this is
the default responder.
30. Resources
@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<Contact> 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();
}
}
}
This method also responds
to GET requests.
But it the request path will
be elected based on this
format.
31. Resources
@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<Contact> 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();
}
}
}
Parameters will be injected
into methods.
/contacts?start=X&count=Y
/contacts/someId
Wink servlet will handle type
conversion.
It supports ordinary java
objects, enums, primitives,
etc.
32. Resources
@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<Contact> 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();
}
}
}
There are lots of options of
returning response.
ResponseBuilders and
some other helpers make it
quite easy.
33. Resources
@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<Contact> 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();
}
}
}
Wink handles much of the
error handling.
Still you can inject your own
errors.
34. Resources
@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();
}
}
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 Wink will select the
appropriate method here.
35. Resources
@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();
}
}
Wink injects the incoming
data into the method
automatically.
Apache Wink also provides
several classes to process
different data formats
(Multipart, Atom, XML,
JSON, etc.)
37. What is your purpose?
Quick and narrow-scoped services
Moving your app to a different web framework
Enable applications for native mobile access
Create a REST API for your apps
38. Plan first!
Determine resource types and capabilities to be allowed
(Resources, Representations, actions, etc.)
The distribution of tasks
(Front-end and Back-end) responsibilities
Collaborate with consumers, if you can
Versioning / Test API
39. Sketch an architecture
Keep your architecture layered
Let your luggage be history
Design as if the consumer will exploit your application, even you!
40. A sample architecture
RESTful Resources
ResourceResourceResource
SubresourceSubresourceSubresource
Model Classes
Data Objects
Conversion
Resource Representation ←→ Model
Data Access
Model ←→ Documents
Business Logic
Actions (CRUD, etc.)
Rules, validations, etc.
Databases
ResourceResourceDocuments
ResourceResourceViews
ResourceResourceetc.
Security Utilities
42. Getting hands dirty
Test and Development
Local Domino Server
Domino Designer Client
Eclipse / XPages SDK / Debug Plugin
REST testing utility (e.g. Postman)
Plugin Development
Guides / Demos / Blogs
Configure Eclipse
Plugin template for Wink project
Add Libraries to your project
(See Resources section)
43. Annotations
• @Path
Specifies the relative path for a resource class or method
• @GET, @PUT, @POST, @DELETE, @HEAD
Specify the HTTP request type of a resource
• @Produces
Specifies the response Internet media types (content negotiation)
• @Consumes
Specifies the accepted request Internet media types.
44. Annotations
• @PathParam
Binds the method parameter to a path segment
• @QueryParam, @MatrixParam, @FormParam
Binds the method parameter to a query/matrix/form parameter
• @HeaderParam, @CookieParam
Binds the method parameter to a HTTP header/cookie parameter
• @Context
Returns the entire context of the object
@Context HttpServletRequest request
• @DefaultValue
Specifies a default value for the above bindings when the key is not found.
@Default(“1”) @QueryParam(“start”) int start
45. Annotations
• @Provider
Providers are used for transformation between entities and representations.
Wink comes with several providers and more can be developed for special
purposes.
• @Asset
More advanced implementation of providers. Especially suitable for automatic
transformation between data objects and representations.
• @Parent
Defines a parent resource that has a base URI. (See Versioning)
• @Scope
By default, every resource class instantiated per request. Scope can define
longer life cycles for resource instances (e.g. singletons).
46. JSON Handling
• Wink and IBM Commons provide JSON Object helpers
• A library for JSON processing strongly suggested
• Hardcoding JSON data structure becomes more and more difficult.
• Automatic Serialization / Deserialization is life saving
• Tip: Look into Jackson and GSON libraries
48. Notes Session
• NotesSession related to the authenticated user:
• ContextInfo.getUserSession()
• At the servlet level,
• No SessionAsSigner
• No SessionAsSignerWithFullAccess
• No CurrentDatabase
• Elevated level of access is a bit tricky.
• Refer to DominoRunner XSnippet
49. OpenNTF Domino API
• OpenNTF Domino API is compatible with Apache Wink
• One trick: You need to customize the servlet
• Refer to the blog post by Paul Withers
• Advantages
• No recycle!
• Modern Java practices (Maps, generics, etc.)
• Much better development experience
• Ability to use elevated session
• Refer to the OpenNTF Domino API Project page for more
51. Summary
RESTful Services Architecture
Designing RESTful services for Domino Applications
Basic Concepts around RESTful Services
Architecture Examples
Annotations used by Apache Wink
Some tricks for Domino developers
52. Takeaway
Download and play with the template and demo plugins
Experiment JAX-RS annotations
Get yourself familiar with Plugin development
Download Extension Library source code and look its design
Study on RESTful design practices and JAX-RS concepts
53. Resources
• Serdar Başeğmez: Demo Plugin and Apache Wink Template
https://github.com/sbasegmez/RestAssuredDemo
• Apache Wink Project
https://wink.apache.org/
• Paul Withers: From XPages Hero To OSGi Guru: Taking The Scary Out Of Building Extension Libraries
http://www.slideshare.net/paulswithers1/ibm-connected-2015-mas103-xpages-performance-and-scalability
• 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
• John Dalsgaard: Wrap An Existing Jar File Into A Plug-in
https://www.dalsgaard-data.eu/blog/wrap-an-existing-jar-file-into-a-plug-in/
• 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