RESTFul-service guideline

 

1. Spring MVC到 JAX-RS的遷移指導

 
1.1 WHAT
  1. 關於Spring REST 和Spring MVC 
    REST特性是Spring Framework的一部分,也是現有的Spring MVC編程模型的延續,所以,並無所謂的「Spring REST framework」這種概念,有的只是Spring和Spring MVC。這意味着若是你有一個Spring應用的話,你既可使用Spring MVC建立HTML Web層,也能夠建立RESTful Web Services層。
  2. 關於JAX-RS和Jersey 
    JAX-RS:The Java API for RESTful Web Services,是Java的JSR339規範,詳見:https://jcp.org/en/jsr/detail?id=339
    Jersey:是JAX-RS的一個實現。咱們實際上在pom.xml中配置的依賴,使用的就是Jersey提供的各類Jar包。並且,Jersey不只僅是JAX-RS的實現,還提供了不少方便開發者的特性和工具。 
    詳見:https://jersey.java.net/index.html
  3. 關於RESTEasy
    RESTEasy是JAX-RS的另一個實現,是JBoss提供的。跟Jersey相比性能上要更優越一些,詳見:http://colobu.com/2015/11/17/Jax-RS-Performance-Comparison/ 。對於REST service的實現類來講,使用方法都是同樣的,都是使用JAX-RS提供的註解。全局的配置有差異,下面將會詳述。

1.2 WHY

從Spring遷移到JAX-RS 的目的有: 
1. JAX-RS : Java的JSR339規範,是業內通用的標準。是個標準化的Java RESTFul service的技術框架。 
2. JAX-RS比Spring MVC更加輕量級, Spring MVC比較重量級,其目標是Web應用開發。對REST的支持只是其中的一部分功能。 網上有一篇文章提到Spring實現的的REST的性能較差,詳見:http://colobu.com/2015/11/17/Jax-RS-Performance-Comparison/ 
3. JAX-RS的使用很簡便上手,跟Spring的使用方式基本相似,使用各類註解就可以實現一個RESTFul的webservice。
4. 對Swagger的支持相對於Spring要好。Swagger的標準用法和實例都是針對的JAX-RS來實現的。而spring若要支持Swagger,須要一些特殊的配置,和非標準的使用方式,頗有可能會有一些坑,遇到問題也不太好解決。html

1.3 HOW

1.3.1 配置Jersey

  • pom.xml中的配置(此處配置可能會優化修改) 
    增長以下dependency

 

<dependency>
  <groupId>javax.servlet</groupId>
  <artifactId>servlet-api</artifactId>
  <version>${servlet-api-version}</version>
  </dependency>
  <dependency>
  <groupId>org.glassfish.jersey.containers</groupId>
  <artifactId>jersey-container-servlet-core</artifactId>
  <version>${jersey2-version}</version>
  </dependency>
  <dependency>
  <groupId>org.glassfish.jersey.media</groupId>
  <artifactId>jersey-media-multipart</artifactId>
  <version>${jersey2-version}</version>
  </dependency>
  <dependency>
  <groupId>org.glassfish.jersey.ext</groupId>
  <artifactId>jersey-spring3</artifactId>
  <version> 2.23 . 2 </version>
  </dependency>
  <dependency>
  <groupId>io.swagger</groupId>
  <artifactId>swagger-jersey2-jaxrs</artifactId>
  <scope>compile</scope>
  <version>${swagger-core-version}</version>
  </dependency>

 

對應版本以下前端

 

<properties>
<swagger-core-version> 1.5 . 9 </swagger-core-version>
<jetty-version> 9.2 . 9 .v20150224</jetty-version>
<jersey2-version> 2.22 . 2 </jersey2-version>
<junit-version> 4.12 </junit-version>
<servlet-api-version> 2.5 </servlet-api-version>
</properties>

 

  • web.xml中的配置 (此處配置未來可能會優化修改)

 

<servlet>
<servlet-name>Jersey REST Service</servlet-name>
<servlet- class >org.glassfish.jersey.servlet.ServletContainer</servlet- class >
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>com.facishare.paas.metadata.rest</param-value> // REST service的Java代碼所在的路徑要註冊在這裏
</init-param>
<init-param>
<param-name>jersey.config.server.provider.classnames</param-name>
<param-value>org.glassfish.jersey.media.multipart.MultiPartFeature</param-value>
</init-param>
<load-on-startup> 1 </load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Jersey REST Service</servlet-name>
<url-pattern>/rest/*</url-pattern> //這裏是全部REST api的baseUrl
</servlet-mapping>

 

  • Java代碼中的配置

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import  org.springframework.beans.factory.annotation.Autowired;
import  javax.ws.rs.*;
import  javax.ws.rs.core.Response;
import  org.springframework.stereotype.Component;
@Component  //此註解保證此REST service可使用Spring的IOC
@Path ( "/{apiVersion}/tenant" ) //指定此service的根path。至關於Spring的@RequestMapping("/{apiVersion}/tenant")
@Consumes ({ "application/json" }) //用於此處來講明此service全部的method傳入參數的傳輸數據格式都是基於json。至關於spring的consumes = "application/json"
@Produces ({ "application/json" }) //用於此處來講明此service全部的method返回值的傳輸數據格式都是基於json。至關於spring的produces = "application/json"
public  class  TenantCtrl {
  @Autowired //依賴注入其餘後臺service
  ITenantInitializeService tenantInitializeService;
  @GET  //至關於Spring中的@RequestMapping中的method = RequestMethod.GET, 描述此方法是個GET請求。
  @Path ( "/init/{tenantId}/{type}" ) //方法級別的path定義。至關於Spring中的@RequestMapping中的value = "/init/{tenantId}/{type}"
  public  Response initializeTenant( @PathParam ( "tenantId" ) String tenantId,  @PathParam ( "type" ) String type, @QueryParam ( "level" ) String level) {
  //上面的@PathParam至關於Spring的@PathVariable, @QueryParam至關於Spring的@RequestParam
  APIResult result =  new  APIResult();
  try  {
result.setMessage(APIResult.OK);
tenantInitializeService.initialTenant(tenantId, type, level);
  return  Response.ok().entity(result).build(); //後臺操做成功,返回200狀態碼,ok()表明成功。entity()方法能夠把某個Java對象做爲返回值傳入到Response中。前面配置@Produces是application/json,將會把Java Object轉化爲Json格式返回給前端。
  catch  (DBException e) {
log.error( "Init tenant failed with tenantId:" +tenantId+ " , exception:" ,e);
result.setMessage(APIResult.ERROR);
result.setErrorDetail(e.toString());
  return  Response.serverError().entity(result).build();
  //若是遇到異常或者報錯,返回500狀態碼。直接使用serverError()方法,能夠將包裝好的APIResult對象,帶着異常棧信息返回給客戶端。
  //此處也能夠拋出WebApplicationException,詳見: https://jersey.java.net/apidocs/latest/jersey/javax/ws/rs/WebApplicationException.html
  }
  }

 

  • 其餘設置 
    須要一個工具類的支持,來包裝Java Object在Respons.entity()方法中轉化爲json格式時候可以順利成功。 
    JacksonJsonProvider.java

 

package  com.facishare.paas.metadata.rest;
import  com.fasterxml.jackson.databind.ObjectMapper;
import  com.fasterxml.jackson.jaxrs.json.JacksonJaxbJsonProvider;
import  javax.ws.rs.Produces;
import  javax.ws.rs.core.MediaType;
import  javax.ws.rs.ext.Provider;
import  io.swagger.util.Json;
@Provider
@Produces ({MediaType.APPLICATION_JSON})
public  class  JacksonJsonProvider  extends  JacksonJaxbJsonProvider {
  private  static  ObjectMapper commonMapper = Json.mapper();
  public  JacksonJsonProvider() {
  super .setMapper(commonMapper);
  }
}

 

1.3.2 配置RESTEasy

pom.xml 中的配置
<properties>
     <resteasy-version> 3.0 . 19 .Final</resteasy-version>
     <servlet-api-version> 3.1 . 0 </servlet-api-version>
</properties>
<dependency>
     <groupId>javax.servlet</groupId>
     <artifactId>javax.servlet-api</artifactId>
     <version>${servlet-api-version}</version>
     <scope>provided</scope>
</dependency>
<dependency>
     <groupId>org.jboss.resteasy</groupId>
     <artifactId>resteasy-jaxrs</artifactId>
     <version>${resteasy-version}</version>
     <scope>provided</scope>
</dependency>
<dependency>
     <groupId>org.jboss.resteasy</groupId>
     <artifactId>resteasy-client</artifactId>
     <version>${resteasy-version}</version>
</dependency>
<dependency>
     <groupId>org.jboss.resteasy</groupId>
     <artifactId>resteasy-multipart-provider</artifactId>
     <version>${resteasy-version}</version>
     <scope>provided</scope>
</dependency>
<dependency>
     <groupId>org.jboss.resteasy</groupId>
     <artifactId>resteasy-jackson2-provider</artifactId>
     <version>${resteasy-version}</version>
</dependency>
<dependency>
     <groupId>org.jboss.resteasy</groupId>
     <artifactId>resteasy-servlet-initializer</artifactId>
     <version>${resteasy-version}</version>
</dependency>
web.xml

由於使用了Servlet 3 ,因此web.xml中無需再作設置java

增長一個javax.ws.rs.core.Application的子類

此類的做用是註冊REST service,並能夠經過此類的配置來跟swagger集成,也能夠註冊其餘的provider,例如git

JacksonJsonProvider等。
如例:
package  com.facishare.paas.metadata.rest;
 
import  java.util.HashSet;
import  java.util.Set;
 
import  javax.ws.rs.ApplicationPath;
import  javax.ws.rs.core.Application;
 
import  io.swagger.jaxrs.config.BeanConfig;
 
/**
  * Created by Jacky on 8/30/16.
  */
 
@ApplicationPath ( "/rest" )
public  class  RestApplication  extends  Application {
     private  Set<Object> singletons =  new  HashSet<Object>();
     private  Set<Class<?>> classes =  new  HashSet<Class<?>>();
 
     public  RestApplication()
     {
         BeanConfig beanConfig =  new  BeanConfig();
         beanConfig.setVersion( "1.0.2" );
         beanConfig.setSchemes( new  String[]{ "http" });
         beanConfig.setHost( "localhost:8080" );
         beanConfig.setBasePath( "/rest" );
         beanConfig.setResourcePackage( "io.swagger.resources" );
         beanConfig.setScan( true );
         singletons.add( new  PingJAXRS());
         singletons.add( new  TenantCtrl());
         singletons.add( new  ObjectDescribeCtrl());
         singletons.add( new  ObjectDataCtrl());
         singletons.add( new  GlobalDataSourceConfigCtrl());
         singletons.add( new  GlobalDataStoreConfigCtrl());
         singletons.add( new  DataStoreCtrl());
         classes.add(io.swagger.jaxrs.listing.ApiListingResource. class );
         classes.add(io.swagger.jaxrs.listing.SwaggerSerializers. class );
         classes.add(JacksonJsonProvider. class );
     }
 
     @Override
     public  Set<Class<?>> getClasses()
     {
         return  classes;
     }
 
     @Override
     public  Set<Object> getSingletons()
     {
         return  singletons;
     }
}

 

其中在singletongs中增長每個Rest的服務的一個實例。此處很是重要。若是不添加到singletons中的話,這個REST服務是沒法被swagger所探測到,就沒法生成對應的swagger.json中的內容。github

        singletons.add(new PingJAXRS());
        singletons.add(new TenantCtrl());
        singletons.add(new ObjectDescribeCtrl());
        singletons.add(new ObjectDataCtrl());
        singletons.add(new GlobalDataSourceConfigCtrl());
        singletons.add(new GlobalDataStoreConfigCtrl());
        singletons.add(new DataStoreCtrl());

因此,每當新增長一個新的REST服務的時候,必定要修改此處代碼,把新的服務註冊進來。不然沒法生成swaggerweb

 

關於和Spring bean的集成,須要一些特殊的配置,不然沒法注入spring的bean。

根據 RESTEasy的官方文檔: http://docs.jboss.org/resteasy/docs/3.0.19.Final/userguide/html_single/index.html#RESTEasy_Spring_Integrationspring

須要進行兩個配置,npm

      1,在pom.xml中增長:編程

<dependency>json

    <groupId>org.jboss.resteasy</groupId>
    <artifactId>resteasy-spring</artifactId>
    <version>${resteasy-version}</version>
</dependency>

     2, 在web.xml中配置:

<listener>
      <listener-class>org.jboss.resteasy.plugins.server.servlet.ResteasyBootstrap</listener-class>
   </listener>

   <listener>
      <listener-class>org.jboss.resteasy.plugins.spring.SpringContextLoaderListener</listener-class>
   </listener>

可是在咱們的項目中遇到了和FcpServerContextListener衝突的問題。 解決方案是繼承FcpServerContextListener寫一個新類,而後把

org.jboss.resteasy.plugins.spring.SpringContextLoaderListener中的內容拷貝到此類中。而後在web.xml配置這個類。代碼以下:
package  com.facishare.paas.metadata.rest;
 
import  com.facishare.fcp.server.FcpServerContextListener;
 
import  org.jboss.resteasy.plugins.spring.SpringContextLoader;
import  org.jboss.resteasy.plugins.spring.SpringContextLoaderSupport;
import  org.jboss.resteasy.plugins.spring.i18n.Messages;
import  org.springframework.web.context.ConfigurableWebApplicationContext;
import  org.springframework.web.context.ContextLoader;
 
import  javax.servlet.ServletContext;
import  javax.servlet.ServletContextEvent;
 
/**
  * Created by Jacky on 9/6/16.
  */
public  class  RestEasyServerContextListener  extends  FcpServerContextListener {
     private  SpringContextLoaderSupport springContextLoaderSupport =  new  SpringContextLoaderSupport();
 
     @Override
     public  void  contextInitialized(ServletContextEvent event)
     {
         boolean  scanProviders =  false ;
         boolean  scanResources =  false ;
 
         String sProviders = event.getServletContext().getInitParameter( "resteasy.scan.providers" );
         if  (sProviders !=  null )
         {
             scanProviders = Boolean.valueOf(sProviders.trim());
         }
         String scanAll = event.getServletContext().getInitParameter( "resteasy.scan" );
         if  (scanAll !=  null )
         {
             boolean  tmp = Boolean.valueOf(scanAll.trim());
             scanProviders = tmp || scanProviders;
             scanResources = tmp || scanResources;
         }
         String sResources = event.getServletContext().getInitParameter( "resteasy.scan.resources" );
         if  (sResources !=  null )
         {
             scanResources = Boolean.valueOf(sResources.trim());
         }
 
         if  (scanProviders || scanResources)
         {
             throw  new  RuntimeException(Messages.MESSAGES.cannotUseScanParameters());
         }
 
 
         super .contextInitialized(event);
     }
 
     protected  ContextLoader createContextLoader()
     {
         return  new  SpringContextLoader();
     }
 
     @Override
     protected  void  customizeContext(ServletContext servletContext, ConfigurableWebApplicationContext configurableWebApplicationContext) {
         super .customizeContext(servletContext, configurableWebApplicationContext);
         this .springContextLoaderSupport.customizeContext(servletContext, configurableWebApplicationContext);
     }
 
}
 
 
  
---以下是web.xml中的配置
<listener>
     <listener- class >org.jboss.resteasy.plugins.server.servlet.ResteasyBootstrap</listener- class >
</listener>
 
<listener>
     <listener- class >com.facishare.paas.metadata.rest.RestEasyServerContextListener</listener- class >
</listener>

 

關於Swagger配置,

詳見:https://github.com/swagger-api/swagger-core/wiki/Swagger-Core-RESTEasy-2.X-Project-Setup-1.5

根據這個文檔,咱們在上面的Application實現類中的增長了以下代碼,支持了Swagger:

BeanConfig beanConfig =  new  BeanConfig();
beanConfig.setVersion( "1.0.2" );
beanConfig.setSchemes( new  String[]{ "http" });
beanConfig.setHost( "localhost:8080" );
beanConfig.setBasePath( "/rest" );
beanConfig.setResourcePackage( "io.swagger.resources" );
beanConfig.setScan( true );
classes.add(io.swagger.jaxrs.listing.ApiListingResource. class );
classes.add(io.swagger.jaxrs.listing.SwaggerSerializers. class );

 

關於RESTEasy,更多詳情請參考官方連接:

 http://jboss.org/resteasy 

 https://github.com/resteasy/Resteasy   

 http://resteasy.jboss.org/docs

2. Swagger的使用方法

2.1 WHAT

Swagger的定義:Swagger offers a specification and complete framework implementation for describing, producing, consuming, and visualizing RESTful web services. The Swagger framework works with many of the popular programming languages, such as Java, Scala, Clojure, Groovy, JavaScript, and .Net.」

「The Swagger framework has the following three major components:

  • Server: This component hosts the RESTful web API descriptions for the services that clients want to use
  • Client: This component uses the RESTful web API descriptions from the server to provide an automated interfacing mechanism to invoke the REST APIs
  • User interface: This part of the framework reads a description of the APIs from the server and renders it as a web page and provides an interactive sandbox to test the APIs」

2.2 WHY

爲何要使用Swagger呢?簡單的說Swagger能夠幫助咱們經過Swagger的註解,生成json文件,來描述咱們全部的REST API,以便於把REST API文檔化,規範化。

我的總結了一下Swagger的幾大優勢: 
1,功能強大,能夠從下倒上,也能夠從上到下兩個方向的設計REST API 
2,語言無關性,提供針對各類語言和框架的支持。 
3,json或者yaml的定義格式簡單易讀。針對咱們的REST外部數據源的動態接入方式,重點是解析json或者yaml,變能夠可以分析出相應REST Api的接口方法,參數和返回值的定義。 
4,Swagger很是流行,也是Open API的主要發起者,很是的成熟,用戶普遍,學習資料多。 
5,相關工具很是強大和易用,包括swagger editor, swagger ui, swager code generator, maven plugin等等。能夠幫助開發者很方便的在UI上定義一個REST API,並生成客戶端或者服務端代碼,還能夠在SwaggerUI上測試,很是方便開發者調試程序。

2.3 HOW

  • 若是是想要先定義REST API,而後經過yaml或者json生成Java代碼,這種從上到下的方式來使用Swagger的話。可使用SwaggerEditor。 
    http://editor.swagger.io/#/ 
    能夠open example,選擇一個例子,在其基礎上來修改。

  • 若是先有了Java代碼,須要反向生成Swagger.json定義文件的話。須要在Java代碼中使用Swagger的註解。 
    主要的經常使用註解以下: 
    @io.swagger.annotations.Api 
    @io.swagger.annotations.ApiOperation 
    @io.swagger.annotations.ApiResponses 
    @io.swagger.annotations.ApiParam 
    @io.swagger.annotations.ApiModel; 
    @io.swagger.annotations.ApiModelProperty;

詳見文檔:https://github.com/swagger-api/swagger-core/wiki/Annotations-1.5.X 
也能夠經過swagger Editor生成的Java code中去看每一個註解都是怎樣使用的。

  • 一些其餘重要的基礎配置:

    • pom.xml

     

       <build>
      <plugins>
      <plugin>
      <groupId>com.github.kongchen</groupId>
      <artifactId>swagger-maven-plugin</artifactId>
      <version> 3.1 . 0 </version>
      <configuration>
      <apiSources>
      <apiSource>
      <springmvc> false </springmvc>
      <locations>com.facishare.paas</locations>
      <schemes>http,https</schemes>
      <host>localhost: 8080 </host>
      <basePath>/service/rest</basePath>
      <info>
      <title>Facishare PAAS MDS</title>
      <version>v1</version>
      <description>This is PAAS metadata service project</description>
      </info>
      <swaggerDirectory>generated/swagger-ui</swaggerDirectory>
      </apiSource>
      </apiSources>
      </configuration>
      <executions>
      <execution>
      <phase>compile</phase>
      <goals>
      <goal>generate</goal>
      </goals>
      </execution>
      </executions>
      </plugin>
      </plugins>
    </build>

     

    • web.xml

 

<servlet>
  <servlet-name>Jersey REST Service</servlet-name>
  <servlet- class >org.glassfish.jersey.servlet.ServletContainer</servlet- class >
  <!-- Register resources and providers under com.vogella.jersey.first  package . -->
  <init-param>
  <param-name>jersey.config.server.provider.packages</param-name>
  <param-value>com.facishare.paas.metadata.rest,io.swagger.jaxrs.listing</param-value>
  </init-param>
  <init-param>
  <param-name>jersey.config.server.provider.classnames</param-name>
  <param-value>org.glassfish.jersey.media.multipart.MultiPartFeature</param-value>
  </init-param>
  <init-param>
  <param-name>jersey.config.server.wadl.disableWadl</param-name>
  <param-value> true </param-value>
  </init-param>
  <load-on-startup> 1 </load-on-startup>
  </servlet>
 
  

 

2.4 重要的網址連接:

Swagger UI

Live Demo:http://petstore.swagger.io/#/ 
doc: https://github.com/swagger-api/swagger-ui 
紛享銷客內部的SwaggerUI的相關連接和使用指導: 
http://oss.firstshare.cn/swagger-ui/ 
若是已有寫好的swagger api的json,可是沒有部署到Java工程中。能夠提交json到這個git的項目裏面 
http://git.firstshare.cn/paas/fs-swagger-api 
例如, 
http://oss.firstshare.cn/swagger-api/paas/metadata/crm_swagger_sample.json 
而後把這個url複製粘貼到http://oss.firstshare.cn/swagger-ui/中間的輸入框中,就能夠用UI來展示API的定義。

http://git.firstshare.cn/paas/fs-swagger-api 
每次push會自動推進到http://oss.firstshare.cn/fs-swagger-api/

Swagger editor

Live Demo: http://editor.swagger.io/#/ 
doc: https://github.com/swagger-api/swagger-editor 
未來也考慮在內部搭建一個SwaggerEditor的server

Swagger codegen: 
https://github.com/swagger-api/swagger-codegen 
也能夠在http://editor.swagger.io/#/ 生成代碼下載:

Swagger maven plugin: 
https://github.com/kongchen/swagger-maven-plugin

OpenAPI 規範

http://swagger.io/specification/ 
https://github.com/OAI/OpenAPI-Specification

3. REST API設計指導方針

如下內容基本翻譯自RESTful Java Web Services Second Edition ,

嚴格意義上說,REST是一種構建可擴展的webservices的軟件架構風格,不是規範。REST並無設計或者構建APIs的嚴格規範。 
這裏要討論一些標準,最佳實踐,慣例,技巧和竅門。 
但願能夠藉此在內部造成統一的風格,乃至規範。

3.1 從問題領域中識別和定義Resource

1,識別出全部的問題領域中的對象,也就是全部的名詞。例如:department , employee 
2,識別出全部跟上述對象相關的CRUD操做。

3.2 把操做轉化爲HTTP methods

最經常使用的HTTP methods有:POST ,GET , PUT ,DELETE 
idempotent[aɪ'dɛmpətənt]在這裏是個比較重要的概念,翻譯過來叫作冪等性。簡單的解釋:一個冪等性的REST API不管經過一樣的參數調用多少次都返回相同的結果。 
HTTP方法中:GET, HEAD, PUT , DELETE都是冪等的, POST則不是。

GET

GET操做只是讀取服務端Resource的represetation。只會讀取數據,不該該做出任何狀態變動。是冪等性的操做。

若是GET成功,應該返回200 OK的HTTP狀態碼。 
若是有錯誤,能夠返回404 NOT FOUND或者400 BAD REQUEST

DELETE

用DELETE作刪除操做。 
若是成功,返回200 OK 
若是已經刪除過,返回404 NOT FOUND

PUT

PUT method也是個冪等的。通常用於把Resource全部的可用的字段都PUT到Server上,不只僅是更改過的部分數據。

POST

POST是非冪等性的。當你不知道這個Resource的全部字段的值的時候須要建立或者更新資源時,使用POST。例如ID是在server端生成的。

若是成功建立資源,建議返回201 Created 狀態,並把新建立的Resource的location返回。 
例如: 
201 Created 
Location: /hrapp/api/employees/1001」

PUT和POST的區別 
You can use PUT for creating or updating a resource when the client has the full resource content available. In this case, all values are with the client, and the server does not generate a value for any of the fields.

You will use POST for creating or updating a resource if the client has only partial resource content available. Note that you are losing the idempotency support with POST. An idempotent method means that you can call the same API multiple times without changing the state. This is not true for the POST method; each POST method call may result in a server state change. PUT is idempotent, and POST is not. If you have strong customer demands, you can support both methods and let the client choose the suitable one on the basis of the use case.

3.3 HTTP狀態碼使用規範

200 OK

201 Created 
This status is generated in response to a POST operation that creates a new resource.」

204 No Content 
This code tells that the server has processed the request but not returned any content. For example, this can be used with the PUT, POST, GET, or DELETE operations if they do not result in any result body.

304 Not Modified 
This code tells the client that it can use the cached resource that was retrieved in the previous call. This code is typically used with the GET operation.

400 Bad Request 
This code indicates that the request sent by the client was invalid (client error) and could not be served. The exact error should be explained in the response entity body payload.

401 Unauthorized 
This code indicates that the REST API call requires user authentication. The client can take the necessary steps for authentication based on this response status.

403 Forbidden 
This code indicates that the caller (even after authentication) does not have access to the requested resource.

404 Not Found 
This code indicates that the requested resource is not found at this moment but may be available again in the future.

405 Method Not Allowed 
This code indicates that the HTTP method requested by the caller is not supported by the resource.」

406 Not Acceptable 
This code indicates that the server does not support the required representation. For example, this can be used in response to the GET, PUT, or POST operations if the underlying REST API does not support the representation of the resource that the client is asking for.

409 Conflict 
「This code indicates that the request could not be completed due to some general conflict with the current state of the resource. This response code makes sense where the caller is capable of resolving the conflict by looking at the error details present in the response body and resubmitting the request. For example, this code can be used in response to PUT, POST, and DELETE if the client sends an outdated resource object to the server or if the operation results in the duplication of resources

410 Gone

This code indicates that the resource identified by this URI is no longer available. Upon receiving a 410 status code, the caller should not request the resource again in the future.

415 Unsupported Media Type

This code indicates that the entity media type present in the request (PUT or POST) is not supported by the server.

422 Unprocessable Entity

This code indicates that the server cannot process the entity present in the request body. Typically, this happens due to semantic errors such as validation errors.」

429 Too Many Requests

This code indicates that the client has sent too many requests in a given time, which results in the rejection of requests due to rate limiting. Note that rate limiting is used for controlling the rate of traffic sent or received by a network interface controller.

500 Internal Server Error

This code indicates that the server encountered an unexpected error scenario while processing the request.

使用JAX-RS實現RESTful Service的話: 

  return  Response.status(Response.Status.OK).entity(result).build();


Response.Status中有全部HTTP 狀態碼的枚舉值。 
經常使用的狀態碼,例如200 OK,可以使用Response.ok()來返回,更加便捷。 
包括: 
ok() 200 
serverError() 500 
created() 201 
accepted() 202 
noContent() 204 
notModified() 304

3.4 命名

1,避免在resource path中出現動詞。儘可能都用名詞。 
2,應該一直使用複數的名詞做爲Resource的命名。例如: 
/departments 是get全部部門的uri. 
/departments/{id} 是獲取id爲10的單個department對象 
3, 儘可能用更加具體的名詞。例如:/programmers 比/employees更具體 
4,resource中儘可能不要包含特殊字符,下劃線等。 
5,駝峯式命名,首字母小寫,首字符不要用特殊符號。

3.5 版本

能夠有不少種實現方式:例如把version放在path中。

/rest/v1/customers

或者把版本放在request header中 
GET /api/departments HTTP/1.1 
api-version: 1.0」

混合方式:主版本放置在URI中。小版本放在request header中。

3.8 Header規範

 

名稱
說明
值(範例)
accept 接收的數據格式,約定都用Json application/json
content-type 傳輸的數據格式,約定都用Json application/json
x-fs-ea 企業帳號(通常來講用EI,不用EA,特殊狀況下能夠用EA來標識一個企業)  
x-fs-ei 企業ID。若是企業ID已經做爲PATH參數的話,header中的這個企業ID能夠不傳。 7
x-fs-userInfo 用戶信息,當前操做人ID 10000
x-fs-peer-host 調用方Host地址 例:VSWR104002
x-fs-peer-name 調用方Name 例:FBS, OpenAPI等
 

 


3.7 其餘

1,建議在RESTful service中不寫任何業務邏輯代碼。只是做爲一個controller,全部的業務邏輯都代理給另一個注入進來的Service。 


2,  什麼東西能夠放在header裏面,什麼不能夠放在header裏面的相關規範。

https://www.soapui.org/testing-dojo/best-practices/understanding-rest-headers-and-parameters.html

3,EasyREST和Jersey比較。用法,性能等方面。

http://resteasy.jboss.org/docs

http://colobu.com/2015/11/17/Jax-RS-Performance-Comparison/

4,dubboX 的REST和JAX-RS怎麼取捨? 
https://github.com/dangdangdotcom/dubbox 
5, update是否暴露ID 
什麼時候暴露ID到path中。 
批量操做,批量更新和刪除,如何定義API? 
6, 內部的安全校驗 

參考:
http://172.31.160.165:8500/ui/#/firstshare/acls/2f8a1b46-9f71-af0b-3a58-35fd36261f3c 
7, swagger 可否支持mockup 
https://github.com/dzdrazil/swagger-mock-api 
https://www.npmjs.com/package/swagger-mock

8, Java對象和json之間的轉換,fastjson or jackson

https://github.com/alibaba/fastjson

http://colobu.com/2014/09/30/using-fastjson-as-JAX-RS-data-binding/

相關文章
相關標籤/搜索