web-dev-qa-db-ja.com

Spring WebfluxコントローラーでFluxとResponseEntityを組み合わせる方法

ヘッダーやその他の応答情報を操作するために、WebfluxコントローラーでMonosをResponseEntitysと一緒に使用しています。例えば:

_@GetMapping("/{userId}")
fun getOneUser(@PathVariable userId: UserId): Mono<ResponseEntity<UserDto>> {
    return repository.findById(userId)
        .map(User::asDto)
        .map { ResponseEntity.ok(it) }
        .defaultIfEmpty(ResponseEntity.notFound().build())
}

@GetMapping
fun getAllUsers(): Flux<UserDto> {
    return repository.findAllActive().map(User::asDto)
}
_

どちらも正常に機能しますが、ResponseEntityFluxを組み合わせて使用​​する必要がある場合もあります。応答タイプはどうあるべきですか? _ResponseEntity<Flux<T>>_を使用することは正しいですか?

例えば:

_@GetMapping("/{userId}/options")
fun getAllUserOptions(@PathVariable userId: UserId): ??? {
    return repository.findById(userId)
        .flatMapIterable{ it.options }
        .map { OptionDto.from(it) }
        // if findById -> empty Mono then:
        //   return ResponseEntity.notFound().build() ?
        // else:
        //   return the result of `.map { OptionDto.from(it) }` ?
}
_

ここで達成したい動作は、repository.findById(userId)が空のMonoの場合、getAllUserOptionsは_404_を返し、それ以外の場合は_user.options_をFluxとして返します。

更新:ここのリポジトリはReactiveCrudRepositoryです

5
ovnia

switchIfEmptyを使用して、ユーザーが存在しない場合に例外をスローします。

return repository
    .findById(userId)
    .switchIfEmpty(Mono.error(NotFoundException("User not found")))
    .flatMapIterable{ it.options }
    .map { OptionDto.from(it) }

次に 例外ハンドラ を使用して、それを404応答に変換します。

3
jannis

ResponseEntityでMonoを返すことで使用できます

このような

public Mono<ResponseEntity<?>> oneRawImage(
        @PathVariable String filename) {
        // tag::try-catch[]
        return imageService.findOneImage(filename)
            .map(resource -> {
                try {
                    return ResponseEntity.ok()
                        .contentLength(resource.contentLength())
                        .body(new InputStreamResource(
                            resource.getInputStream()));
                } catch (IOException e) {
                    return ResponseEntity.badRequest()
                        .body("Couldn't find " + filename +
                            " => " + e.getMessage());
                }
            });         
    }

私もこのような例があります

  public ResponseEntity<Mono<?>>  newLive(@Valid @RequestBody Life life) {
        Mono<Life> savedLive = liveRepository.save(life);
        if (savedLive != null) {
            return new ResponseEntity<>(savedLive, HttpStatus.CREATED);
        }
        return new ResponseEntity<>(Mono.just(new Life()), HttpStatus.I_AM_A_TEAPOT);
    }

RESTコントローラでの関数型プログラミングは嫌いです。

以下に例を示します ReactiveController

1