Showing posts with label Webservice. Show all posts
Showing posts with label Webservice. Show all posts

Friday, 29 June 2018

Part 1 - REST API Best practices and implementing them with Spring Boot

This article describes the best practices of implementing REST API.

Before we jump into the actual implementation, lets first understand the design principles involved in API design.


API Design principles

  1. Present APIs as products
    • APIs are not integration services that happen to use HTTP and JSON
    • They are business products that must be managed as a complete product offering
    • And although created and managed by different teams they should have a similar look and feel
  2. Design APIs with the consumer in mind
    • Develop APIs as though you consumers are your customers
    • APIs should be more developer-friendly and Easy to Consume
    • Simple to Expose to external third-parties in future
    • Don't leak internal context to the consumer
    • Make APIs easy to learn, hard to misuse, audience-oriented
  3. Prefer REST-based services over SOAP

REST API Design principles

  1. Use RESTful URIs and actions
    • /policies - refers to a policy resource collection
    • /policies/7895544 - refers to a policy resource collection
  2. Use HTTP verbs to act on you resources
    • Resources should be acted on using HTTP methods GET, PUT, POST, PATCH, DELETE for example GET /policies/789554
    • HTTP methods should perform predictable actions on the resource. For example, don't use POST to retrieve a resource, and don't use DELETE to create a resource.
  3. Nouns are good, verbs are bad
    • Resources must use plural nouns, such as accounts and not account
    • Do not use verbs in URI, /getaccount or createcar
    • The method exposing the webservice should be verb not the associated URI
  4. Use sub-resources to represent relationships
    • For e.g if a Department has many Employees and you need to get the list of employees in a department, the URI should be 
      GET /departments/  - Get all Departments
      POST /departments/  - Create a Department
      GET /departments/1234  - Get a Department
      GET /departments/1234/employees - Get all Employees in a Department
      POST /departments/1234/employees - Create an Employees in a Department
      GET /departments/1234/employees/2 - Get a Employee in a Department

  5. Version your API
    • All APIs should be versiones
    • Use only a major version number prefixed with a "v", eg /v1
  6. HATEOUS compliant
    • The API should be HATEOUS compliant. All future actions the client may take are discovered within resource representations returned from the server. The media types used for these representations, and the link relations they may contain, are standardized.
    • For e.g for a GET /departments/
    • {
      "id" : 1,
      "name" : "Head Office",
      "Address" : "In a far galazy",
      "links" : [
         {
             "rel" : "self",
             "href" : "http//abc.com/api/v1/departments/"
         },
         {
             "rel" : "find",
             "href" : "http//abc.com/api/v1/departments/{id}",
             "type" : "GET"
         },
         {
             "rel" : "delete",
             "href" : "http//abc.com/api/v1/departments/{id}",
             "type" : "DELETE"
         }
         
      }
    • As seen above the response has a link to self and also other possible resources the client can use

  7. API must be secured
    • APIs must be secured and there are no exceptions
    • OAuth2.0 can be used for securing APIs.
    • Choose the best grant type e.g authorization code/password/client credential
  8. Error Handling
    1. Use descriptive error messages and status code
    2. For e.g if the request is to find a employee and the employee id provided is not correct, return a 404 Resource Not Found status code and not a 200 OK
    3. Trap all errors and always return a valid JSON response

    4. {
          "timestamp": "2018-06-27T12:42:39.238+0000",
          "status": 400,
          "error": "Bad Request",
          "message": "Do not send ‘id’ as part of request",
          "path": "/spring-security-oauth-resource/rest/v1/employees"
      }
      
      

      Another example for multiple errors would be like below:
      {
          "status": 405,
          "timestamp": "02-07-2018 03:16:55",
          "path": "/spring-security-oauth-resource/rest/v1/departments",
          "message": "Validation failed for object='department'. Error count: 3",
          "sub_errors": [
              {
                  "field": "name",
                  "message": "name cannot be Blank"
              },
              {
                  "field": "id",
                  "rejectedValue": 1111,
                  "message": "must be null"
              },
              {
                  "field": "knownName",
                  "message": "known_name cannot be Blank"
              }
          ]
      }
      
  9. Things to avoid
    • Dont use querystring argumets to retrieve by primary key:
    • For eg : dont use /policies/?policy_number=32323
      Rather Use /policies/12333
    • Dont use mixed-case in URLs:
    • For eg : dont use /Policies/32323
      Rather Use /policies/12333

Wednesday, 16 April 2014

REST webservice using jax-rs

In the previous post of SOAP webservice using JAX-WS we explored how to host a SOAP webservice and test it using JAX-WS, here we will host a REST webservice.

Tuesday, 15 April 2014

SOAP spring-ws with username authentication security

Their are different ways to secure SOAP based webservices.
1. Username/Password
2. Timestamp
3. Encryption/ Decryption
4. Digital Signature

Among these the most common and easy type of security is username/password. This security is very similar to a web application having a login page at the start for Authentication.

Spring-ws provides API to do this kind of security.
Extending our example in the previous post to host a SOAP based webservice, here we apply username security

Following tag is needed to be added in *-servlet.xml.

<sws:interceptors>
  <bean
   class="org.springframework.ws.soap.server.endpoint.interceptor.PayloadValidatingInterceptor">
   <property name="schema" value="/WEB-INF/login.xsd" />
   <property name="validateRequest" value="true" />
   <property name="validateResponse" value="true" />
  </bean>
  <bean
   class="org.springframework.ws.server.endpoint.interceptor.PayloadLoggingInterceptor">
  </bean>
  <bean
   class="org.springframework.ws.soap.security.xwss.XwsSecurityInterceptor">
   <property name="policyConfiguration" value="/WEB-INF/securityPolicy.xml" />
   <property name="callbackHandlers">
    <list>

    <!--  <ref bean="keyStoreHandler" /> -->
     <ref bean="callbackHandler" />
     
    </list>
   </property>
 </bean>
 </sws:interceptors>
 <bean id="callbackHandler"
  class="org.springframework.ws.soap.security.xwss.callback.SimplePasswordValidationCallbackHandler">
  <property name="users">
   <props>
    <prop key="admin">secret</prop>
    <prop key="clinetUser">pass</prop>
   </props>
  </property>
 </bean>

Here XwsSecurityInterceptor is used as a interceptor to apply security. The Interceptor refers securityPolicy.xml mentioned below to apply security. The additional parameters used for security are mentioned in the callbackHandler bean tag.

securityPolicy.xml
The securityPolicy.xml below mentions that the request to the service should contain username/password parameters. If not then the response would be a FAULT


<xwss:SecurityConfiguration xmlns:xwss="http://java.sun.com/xml/ns/xwss/config">

 <xwss:RequireUsernameToken
  passwordDigestRequired="true" nonceRequired="true" />

</xwss:SecurityConfiguration>

Once deployed the service can be tested using SOAP UI. The complete description is provided here.

For Web Service Introduction click here

Below are some posts that explain how to implement and test SOAP/REST Webservices

Host
SOAP REST
JAX-WS JAX-RS
Spring-ws Spring-MVC-REST
Client
SOAP REST
JAX-WS(wsimport) Google REST APP
SOAP UI Apache REST

Monday, 7 April 2014

SOAP UI with username - digest security

SOAP UI can be used to test a SOAP based webservice with added security like username.
Below screen shots show this can be done.

Saturday, 5 April 2014

SOAP webservice using Spring-ws

Spring-ws API works on the principal of contract first SOAP webservice. In this type of webservice implementation the wsdl is created first. In contract last SOAP webservice the JAVA code is created first which inturns creates the wsdl. The contract first webservice is a bit difficult to implement as compared to contract last webservice as the xsd and wsdl needs to be created manually. Contract first webservice is more advantageous though as it eliminates the impedance mismatch problem. Below code snippets explains how to use spring-ws to implement the SOAP based webservice.

Tuesday, 1 April 2014

Rest client java using apache http client

This blog explains how a rest web service can be called using Apache Http Client API.

Below class is a utility class that transforms a Java object to XML and also the other way around.
This class uses JAXB to marshal an unmarshal the objects and xml string.

XML Rest Client with Google Chrome Advanced Rest Client App



For Web Service Introduction click here

Below are some posts that explain how to implement and test SOAP/REST Webservices

Host
SOAP REST
JAX-WS JAX-RS
Spring-ws Spring-MVC-REST
Client
SOAP REST
JAX-WS(wsimport) Google REST APP
SOAP UI Apache REST

Friday, 14 March 2014

Spring Rest MVC + JSP + Jquery


Spring MVC + REST + JSP + Jquery
This post explains how a application can be made with a combination of Spring  Rest MVC + JSP Jquery.

Below is the pom

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.nihilent.rest</groupId>
  <artifactId>rest-web-app</artifactId>
  <packaging>war</packaging>
  <version>0.0.1-SNAPSHOT</version>
  <name>rest-web-app</name>
  <url>http://maven.apache.org</url>
  <build>
  <finalName>rest-web-app</finalName>
 </build>
  <properties>
  <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  <spring.version>3.2.2.RELEASE</spring.version>
  <java.version>1.6</java.version>
  <servlet-api.version>2.5.0</servlet-api.version>
 </properties>
  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
     <dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-web</artifactId>
   <version>${spring.version}</version>
  </dependency>
  <dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-webmvc</artifactId>
   <version>${spring.version}</version>
  </dependency>
  <dependency>
   <groupId>commons-logging</groupId>
   <artifactId>commons-logging</artifactId>
   <version>1.1.1</version>
  </dependency>
  <dependency>
   <groupId>log4j</groupId>
   <artifactId>log4j</artifactId>
   <version>1.2.16</version>
  </dependency>
  <!-- JSTL -->
  <dependency>
   <groupId>javax.servlet</groupId>
   <artifactId>jstl</artifactId>
   <version>1.1.2</version>
  </dependency>

  <dependency>
   <groupId>taglibs</groupId>
   <artifactId>standard</artifactId>
   <version>1.1.2</version>
  </dependency>

  <!-- for compile only, your container should have this -->
  <dependency>
   <groupId>javax.servlet</groupId>
   <artifactId>servlet-api</artifactId>
   <version>2.5</version>
   <scope>provided</scope>
  </dependency>
  <dependency>
   <groupId>junit</groupId>
   <artifactId>junit</artifactId>
   <version>4.11</version>
   <scope>test</scope>
  </dependency>
  <dependency>
   <groupId>commons-codec</groupId>
   <artifactId>commons-codec</artifactId>
   <version>1.8</version>
  </dependency>
  </dependencies>
</project>

Below is the web.xml

<?xml version="1.0" encoding="UTF-8"?>
<!-- * This software is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES 
 OR CONDITIONS OF ANY KIND. -->
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
 xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
 version="2.5">
 <display-name>Order Web Service</display-name>

 <context-param>
  <param-name>log4jConfigLocation</param-name>
  <param-value>/WEB-INF/classes/log4j.xml</param-value>
 </context-param>

 <listener>
  <listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
 </listener>

 <servlet>
  <servlet-name>rest</servlet-name>
  <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  <load-on-startup>1</load-on-startup>
 </servlet>

 <servlet-mapping>
  <servlet-name>rest</servlet-name>
  <url-pattern>/rest/*</url-pattern>
 </servlet-mapping>
 <welcome-file-list>
 <welcome-file>index.jsp</welcome-file>
 </welcome-file-list>
</web-app>

Spring context file rest-servlet.xml

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xmlns:p="http://www.springframework.org/schema/p"
 xmlns:tx="http://www.springframework.org/schema/tx"
 xmlns:context="http://www.springframework.org/schema/context"
 xmlns:oxm="http://www.springframework.org/schema/oxm"
 xmlns:util="http://www.springframework.org/schema/util"
 xmlns:aop="http://www.springframework.org/schema/aop"
 xmlns:mvc="http://www.springframework.org/schema/mvc"
 xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
  http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
  http://www.springframework.org/schema/oxm http://www.springframework.org/schema/oxm/spring-oxm-3.0.xsd
  http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
  http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd
  http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd
  http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd"
  default-autowire="byName">
 
 <context:component-scan base-package="com.nihilent.*" />
 <mvc:annotation-driven />

 <bean
  class="org.springframework.web.servlet.view.InternalResourceViewResolver">
  <property name="prefix">
   <value>/WEB-INF/pages/</value>
  </property>
  <property name="suffix">
   <value>.jsp</value>
  </property>
 </bean>
</beans>

XML request message which will be needed to create XSD

<login>
<username>admin</username>
<password>admin</password>
</login>
<response>
<message>login successful</message>
</response>
<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:element name="response">
    <xs:complexType>
      <xs:sequence>
        <xs:element type="xs:string" name="message"/>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
</xs:schema>

The Message XSD that can be created from any online tool from a XML

<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:element name="login">
    <xs:complexType>
      <xs:sequence>
        <xs:element type="xs:string" name="username"/>
        <xs:element type="xs:string" name="password"/>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
</xs:schema>

Pojo created from the XSD. The POJO can be created by using the xjc command of JDK

package com.nihilent.model;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;


@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
    "username",
    "password"
})
@XmlRootElement(name = "login")
public class Login {

    @XmlElement(required = true)
    protected String username;
    @XmlElement(required = true)
    protected String password;

    public String getUsername() {
        return username;
    }
    public void setUsername(String value) {
        this.username = value;
    }
    public String getPassword() {
        return password;
    }
    public void setPassword(String value) {
        this.password = value;
    }

}

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
    "message"
})
@XmlRootElement(name = "response")
public class Response {

    @XmlElement(required = true)
    protected String message;

   
    public String getMessage() {
        return message;
    }

    
    public void setMessage(String value) {
        this.message = value;
    }

}

Controller class RestController.java

package com.nihilent.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import com.nihilent.model.Login;
import com.nihilent.model.Response;

@Controller

public class RestController {
 
 @RequestMapping(value = "/login", method = RequestMethod.POST, headers = "Accept=application/xml")
 public @ResponseBody
 Response login(@RequestBody Login login) {
  Response response = new Response();
  if(login.getUsername().equals("admin") && login.getPassword().equals("admin")){
   response.setMessage("login successful");
  }else{
   response.setMessage("login invalid");
  }
  
  return response;
 }
}


index.jsp


<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
 pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
<script type="text/javascript" src="scripts/jquery-ui.min.js"></script>
<script type="text/javascript" src="scripts/jquery.js"></script>

<link rel="stylesheet" href="styles/jquery-ui.css" type="text/css" />
</head>
<script>
 $(document).ready(function() {

 });
 function submitfun() {

  $.ajax({
   type : "POST",
   headers : {
    "Content-Type" : "application/xml"
   },
   url : 'rest/login',
   dataType : "xml",
   data : '<?xml version="1.0" encoding="UTF-8"?><login><username>'
     + $('#username').val() + '</username><password>'
     + $('#password').val() + '</password></login>',
   success : function(response) {

    $(response).find('message').each(function() {
     $('#response').html($(this).text());
    });

   },
   error : function(response) {
    alert('error:' + response);
   }
  });
 }
</script>
<body>

 <h1 align="center">Spring 3.0 MVC Rest + Jquery + JSP</h1>
 <table cellpadding="5" cellspacing="5" align="center"
  style="vertical-align: middle; border: 1px solid #ccc; background: #F1F6F6">
  <tr>
   <td>Username</td>
   <td><input id="username" type="text"></input></td>
  </tr>
  <tr>
   <td>Password</td>
   <td><input id="password" type="password"></input></td>
  </tr>
  <tr>
   <td align="center" colspan="2"><input type="button"
    value="Login" onclick="submitfun();" /></td>
  </tr>

 </table>

 <div align="center" id="response"></div>
</html>

The final structure of the project should be like :
Get the source code from here


The same rest service can also be tested using Google chrome app - Advanced Rest Client.
To know how see this blog
The rest service can also be tested using a HTTP client API from Apache which simulates the HTTP request. To see how it can be implemented, refer this blog

For Web Service Introduction click here

Below are some posts that explain how to implement and test SOAP/REST Webservices

Host
SOAP REST
JAX-WS JAX-RS
Spring-ws Spring-MVC-REST
Client
SOAP REST
JAX-WS(wsimport) Google REST APP
SOAP UI Apache REST

Share the post