51Testing软件测试论坛

标题: 使用 Postman 与 Kotlin 交互REST API接口数据 [打印本页]

作者: 乐哈哈yoyo    时间: 2019-1-15 15:51
标题: 使用 Postman 与 Kotlin 交互REST API接口数据

此文简单介绍如何使用Postman快速完成REST API接口的数据交互及调试工作,Postman的下载地址:https://www.getpostman.com/

就像其主页上说明的一样,Postman能让API的开发工作更加简单高效,建议做API开发还没有用过Postman的同学尝尝鲜。


[attach]121002[/attach]


回到正题,实现数据交互,我们需要在REST API服务端实现针对不同类型HTTP请求的响应机制,其中常见的HTTP请求类型包括GET,POST,DELETE,PUT等,前面我们的接口仅实现了针对不带参数的GET类型请求的响应机制,现在我们先看看含参数的GET请求如何处理。


GET类型HTTP请求传递参数有如下2种方式,可分别通过request.pathVariable("id")或者request.queryParam("id")获取到传入的参数值:

请求路径格式参考

传参方式

Kotlin响应函数

“/get/XXX”
URL路径变量
GET("/get/{id}")
{ request -> ServerResponse.ok().body(bookRepository.findById(request.pathVariable("id")))}
“/get?id=XXX”
FORM表单参数
GET("/get")
{ request ->
     val id = request.queryParam("id")
     ServerResponse.ok().body(bookRepository.findById(id.get()))
}

实现以上接口函数的方法后,可以简单通过Postman提交如下2个测试请求:

http://localhost:8080/book/get/5b976f860dded66908723462

http://localhost:8080/book/get?id=5b976f860dded66908723462


两次请求获取到的结果相同,具体参考如下截图:


[attach]121003[/attach]


POST类型HTTP请求传递参数有如下2种方式,获取参数值的方法参见下表:

请求路径格式参考

传参方式

Kotlin获取参数值的方法

“/add?name=XXX”
FORM表单参数
request.queryParam("name")
"/add"
Request Body
获取多个同类型Java对象参数值:request.bodyToFlux(Book::class.java)
获取单个Java对象参数值:request.bodyToMono(Book::class.java)

以上2种传参方式的区别在于FORM表单参数仅支持简单类型参数传值,而Request Body可通过JSON格式传递复杂类型数据到服务端,Spring WebFlux框架会自动将JSON格式的入参转化为指定类型的实体bean,如果传入的是多个Book类型对象的数组,可以用request.bodyToFlux(Book::class.java)将其转化为Book类型元素的Flux流再做后续处理,如果传入的是单个Book类型对象,可以用request.bodyToMono(Book::class.java)将其转化为Book类型元素的Mono流做后续处理。


以下我们声明一个RestBookHandler对象来受理来自REST API的POST请求:

  1. @Component
  2. class RestBookHandler(val bookRepository: BookRepository) {
  3.     fun saveBook(request: ServerRequest): Mono<ServerResponse> = request.bodyToMono(Book::class.java)
  4.             .flatMap { bookRepository.save(it) }
  5.             .flatMap { it ->
  6.                 ServerResponse.ok().body(fromObject(it))
  7.             }
  8. }
复制代码

受理POST请求的动作分解如下:

步骤1:request.bodyToMono(Book::class.java), 将传入的Request Body 中的JSON字符串转化为Book类型的Mono流;

步骤2:flatMap { bookRepository.save(it) },保存Mono流内的Book对象;

步骤3:flatMap { it -> ServerResponse.ok().body(fromObject(it)) },将保存后的Book对象返回给调用者。

在主函数的beans框架内添加如下部分声明一个名称为postHandler的bean处理来自/add路径的POST请求,接收到的请求交给bookResthandler对象的saveBook方法进行处理:

  1. bean("postHandler") {
  2.     val bookRestHandler = ref<RestBookHandler>()
  3.     router {
  4.         POST("/add", bookRestHandler::saveBook)
  5.     }
  6. }
复制代码

通过Postman提交如下测试请求:

请求类型
HTTP POST
请求URL
http://localhost:8080/add
Request Body(JSON格式串)
{
    "name":"Postman提交书籍",
    "author":"Michael Chen",
    "publish":"2018-09-11T13:49:00.000+0000"
}

服务器接受到Postman提交的请求后,正常执行相应过程返回的结果如下:


[attach]121004[/attach]


汇总以上实现的GET及POST方法,不带参数和带参数的方法,整个KotlinAppApplication.kt文件的代码如下:

  1. @SpringBootApplication
  2. class KotlinAppApplication

  3. interface BookRepository : ReactiveMongoRepository<Book, String>

  4. @Document
  5. data class Book(val id: ObjectId?, val name: String, val author: String, val publish: Date)

  6. fun main(args: Array<String>) {
  7.     runApplication<KotlinAppApplication>(*args) {
  8.         addInitializers(
  9.                 beans {

  10.                     bean("postHandler") {
  11.                         val bookRestHandler = ref<RestBookHandler>()
  12.                         router {
  13.                             POST("/add", bookRestHandler::saveBook)
  14.                         }
  15.                     }

  16.                     bean {
  17.                         val bookRepository = ref<BookRepository>()
  18.                         val interval = Flux.interval(Duration.ofMillis(100))
  19.                         router {
  20.                             (accept(TEXT_HTML) and "/book").nest {
  21.                                 GET("/list")
  22.                                 {
  23.                                     ServerResponse.ok().contentType(MediaType.TEXT_EVENT_STREAM)
  24.                                             .body(Flux.zip(interval, bookRepository.findAll()).map { entry -> entry.t2 })
  25.                                 }
  26.                                 GET("/get/{id}")
  27.                                 { request ->
  28.                                     ServerResponse.ok().body(bookRepository.findById(request.pathVariable("id")))
  29.                                 }
  30.                                 GET("/get")
  31.                                 { request ->
  32.                                     val id = request.queryParam("id")
  33.                                     ServerResponse.ok().body(bookRepository.findById(id.get()))
  34.                                 }
  35.                             }
  36.                         }
  37.                     }

  38.                     bean {
  39.                         val bookRepository = ref<BookRepository>()
  40.                         ApplicationRunner {
  41.                             bookRepository.deleteAll()
  42.                                     .thenMany(Flux.fromStream(Stream.generate { ObjectId.get() }.limit(10)))
  43.                                     .map { Book(it, "Spring 空间", "Michael Chen", Date()) }
  44.                                     .flatMap { bookRepository.save(it) }
  45.                                     .thenMany(bookRepository.findAll())
  46.                                     .subscribe { println(it) }
  47.                         }
  48.                     }
  49.                 }
  50.         )
  51.     }
  52. }
复制代码

通过以上样例可以看出,在结合Kotlin和Spring Boot 2.0的基础上,开发一个REST API接口可以有更多灵活的方案,而不用拘泥于@RestController的方式。


作者: 凌风行96    时间: 2019-2-15 14:57
感觉很棒的样子,虽然看不懂,留名




欢迎光临 51Testing软件测试论坛 (http://bbs.51testing.com/) Powered by Discuz! X3.2