51Testing软件测试论坛

 找回密码
 (注-册)加入51Testing

QQ登录

只需一步,快速开始

微信登录,快人一步

手机号码,快捷登录

查看: 2110|回复: 1
打印 上一主题 下一主题

[原创] 使用 Postman 与 Kotlin 交互REST API接口数据

[复制链接]
  • TA的每日心情
    无聊
    2024-7-12 13:16
  • 签到天数: 1 天

    连续签到: 1 天

    [LV.1]测试小兵

    跳转到指定楼层
    1#
    发表于 2019-1-15 15:51:03 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

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

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



    回到正题,实现数据交互,我们需要在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


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



    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提交的请求后,正常执行相应过程返回的结果如下:



    汇总以上实现的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的方式。

    本帖子中包含更多资源

    您需要 登录 才可以下载或查看,没有帐号?(注-册)加入51Testing

    x
    分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
    收藏收藏1
    回复

    使用道具 举报

    该用户从未签到

    2#
    发表于 2019-2-15 14:57:30 | 只看该作者
    感觉很棒的样子,虽然看不懂,留名
    回复 支持 反对

    使用道具 举报

    本版积分规则

    关闭

    站长推荐上一条 /1 下一条

    小黑屋|手机版|Archiver|51Testing软件测试网 ( 沪ICP备05003035号 关于我们

    GMT+8, 2024-11-22 22:17 , Processed in 0.070824 second(s), 23 queries .

    Powered by Discuz! X3.2

    © 2001-2024 Comsenz Inc.

    快速回复 返回顶部 返回列表