Popular New Releases in Reactive Programming
axios
v0.26.1
RxJava
3.1.4
fetch
RxSwift
Atlas
ReactiveCocoa
12.0.0
Popular Libraries in Reactive Programming
by axios javascript
92140 MIT
Promise based HTTP client for the browser and node.js
by ReactiveX java
45971 Apache-2.0
RxJava – Reactive Extensions for the JVM – a library for composing asynchronous and event-based programs using observable sequences for the Java VM.
by caolan javascript
27509 MIT
Async utilities for node and the browser
by ReactiveX typescript
26586 Apache-2.0
A reactive programming library for JavaScript
by github javascript
25051 MIT
A window.fetch JavaScript polyfill.
by ReactiveX swift
22027 NOASSERTION
Reactive Programming in Swift
by ReactiveCocoa swift
19983 NOASSERTION
Cocoa framework and Obj-C dynamism bindings for ReactiveSwift.
by petkaantonov javascript
19726 MIT
:bird: :zap: Bluebird is a full featured promise library with unmatched performance.
by Reactive-Extensions javascript
19688 NOASSERTION
The Reactive Extensions for JavaScript
Trending New libraries in Reactive Programming
by piscinajs typescript
2414 NOASSERTION
A fast, efficient Node.js Worker Thread Pool implementation
by smol-rs rust
2074 NOASSERTION
A small and fast async runtime for Rust
by iswbm python
1913
Python 黑魔法手册
by tokio-rs rust
1779 MIT
a debugger for async rust!
by rx-angular typescript
1237 MIT
Reactive Extensions for Angular.
by shiyanhui c
1179 MIT
A concurrency C library 10x faster than Golang.
by nolar python
894 MIT
A Python framework to write Kubernetes operators in just a few lines of code
by sansyrox rust
859 BSD-2-Clause
Robyn is a fast and extensible async python web server with a rust runtime
by David-Haim c++
809 MIT
Modern concurrency for C++. Tasks, executors, timers and C++20 coroutines to rule them all
Top Authors in Reactive Programming
1
59 Libraries
1402
2
53 Libraries
11846
3
36 Libraries
22896
4
27 Libraries
1723
5
26 Libraries
1089
6
23 Libraries
5125
7
20 Libraries
135294
8
20 Libraries
954
9
20 Libraries
21648
10
19 Libraries
3883
1
59 Libraries
1402
2
53 Libraries
11846
3
36 Libraries
22896
4
27 Libraries
1723
5
26 Libraries
1089
6
23 Libraries
5125
7
20 Libraries
135294
8
20 Libraries
954
9
20 Libraries
21648
10
19 Libraries
3883
Trending Kits in Reactive Programming
No Trending Kits are available at this moment for Reactive Programming
Trending Discussions on Reactive Programming
Swift custom toggle style freezes UI
How to return a Reactive Flux that contains a Reactive Mono and Flux?
Setting an @Published var to nil after no more events are received
Is it possible for a non reactive Client (RestTemplate) to consume a Reactive REST API (WebFlux)
How to re-render UI in response to computed property buried in a nested class?
Scatter & Gather using Spring Webclient
Return a String value when method return type is Mono<String>
In reactive programming, is the sequence of doOnNext calls guaranteed?
Why does the `R` pipe operator `|>` not work in the reactive programming using Shiny?
Spring Webflux vs Rsocket
QUESTION
Swift custom toggle style freezes UI
Asked 2022-Feb-10 at 12:20I would like to create a view with a list of checkboxes which I can select independently and keep track of these changes in an array. I have implemented some code to try and achieve this however Im experiencing weird behaviour where the screen freezes as a result of this code. Im still new to SwiftUI and reactive programming so I'm not sure if I am missusing reactive components.
When selecting the checkboxes the screen freezes and from there onwards I'm unable to click anything on the screen.
Entity
1class Entity: Identifiable, Codable, Equatable {
2
3 var id = UUID()
4 let name: String
5 var enabled: Bool
6
7 init(name: String, enabled: Bool) {
8 self.name = name
9 self.enabled = enabled
10 }
11
12 static func == (lhs: Entity, rhs: Entity) -> Bool {
13 lhs.id == rhs.id
14 }
15}
16
17
MyToggleStyle1
1class Entity: Identifiable, Codable, Equatable {
2
3 var id = UUID()
4 let name: String
5 var enabled: Bool
6
7 init(name: String, enabled: Bool) {
8 self.name = name
9 self.enabled = enabled
10 }
11
12 static func == (lhs: Entity, rhs: Entity) -> Bool {
13 lhs.id == rhs.id
14 }
15}
16
17struct MyToggleStyle1: ToggleStyle {
18 func makeBody(configuration: Configuration) -> some View {
19 return HStack {
20 configuration.label
21 Image(systemName: configuration.isOn ? "checkmark.square" : "square")
22 .resizable()
23 .foregroundColor(configuration.isOn ? .green : .red)
24 .frame(width: 22, height: 22)
25 .onTapGesture { configuration.isOn.toggle() }
26 }
27 }
28}
29
EntitySelectorView
1class Entity: Identifiable, Codable, Equatable {
2
3 var id = UUID()
4 let name: String
5 var enabled: Bool
6
7 init(name: String, enabled: Bool) {
8 self.name = name
9 self.enabled = enabled
10 }
11
12 static func == (lhs: Entity, rhs: Entity) -> Bool {
13 lhs.id == rhs.id
14 }
15}
16
17struct MyToggleStyle1: ToggleStyle {
18 func makeBody(configuration: Configuration) -> some View {
19 return HStack {
20 configuration.label
21 Image(systemName: configuration.isOn ? "checkmark.square" : "square")
22 .resizable()
23 .foregroundColor(configuration.isOn ? .green : .red)
24 .frame(width: 22, height: 22)
25 .onTapGesture { configuration.isOn.toggle() }
26 }
27 }
28}
29struct EntitySelectorView: View {
30 @State var customArray: [Entity] = [Entity(name: "All entities", enabled: false),
31 Entity(name: "Boston Merchandising", enabled: false),
32 Entity(name: "Canns & Co", enabled: false),
33 Entity(name: "Sterling Auto Spares", enabled: false),
34 Entity(name: "Compendia Bioscience Life Technologies", enabled: true),
35 Entity(name: "Boston Consulting Group", enabled: false)]
36
37 var body: some View {
38 VStack(spacing: 0) {
39 ScrollView(.vertical, showsIndicators: false) {
40 VStack{
41 ForEach($customArray) { $entity in
42 HStack {
43 Toggle(isOn: $entity.enabled) {
44 Text(entity.name)
45 .foregroundColor(Colors.darkTextColor.color)
46 .font(.system(size: 16, weight: entity.name == "All entities" ? .bold : .regular, design: .default))
47 }
48 .toggleStyle(MyToggleStyle1())
49
50 Spacer()
51 }.padding(.top, 12)
52 }
53
54 Spacer()
55 }
56 }
57
58 Spacer()
59 }.padding()
60 }
61}
62
63
ANSWER
Answered 2022-Feb-10 at 12:20It is about model: 1st - it must be value, and 2nd - equatable should depend on any changed property.
Here is fixed part. Tested with Xcode 13.2 / iOS 15.2
1class Entity: Identifiable, Codable, Equatable {
2
3 var id = UUID()
4 let name: String
5 var enabled: Bool
6
7 init(name: String, enabled: Bool) {
8 self.name = name
9 self.enabled = enabled
10 }
11
12 static func == (lhs: Entity, rhs: Entity) -> Bool {
13 lhs.id == rhs.id
14 }
15}
16
17struct MyToggleStyle1: ToggleStyle {
18 func makeBody(configuration: Configuration) -> some View {
19 return HStack {
20 configuration.label
21 Image(systemName: configuration.isOn ? "checkmark.square" : "square")
22 .resizable()
23 .foregroundColor(configuration.isOn ? .green : .red)
24 .frame(width: 22, height: 22)
25 .onTapGesture { configuration.isOn.toggle() }
26 }
27 }
28}
29struct EntitySelectorView: View {
30 @State var customArray: [Entity] = [Entity(name: "All entities", enabled: false),
31 Entity(name: "Boston Merchandising", enabled: false),
32 Entity(name: "Canns & Co", enabled: false),
33 Entity(name: "Sterling Auto Spares", enabled: false),
34 Entity(name: "Compendia Bioscience Life Technologies", enabled: true),
35 Entity(name: "Boston Consulting Group", enabled: false)]
36
37 var body: some View {
38 VStack(spacing: 0) {
39 ScrollView(.vertical, showsIndicators: false) {
40 VStack{
41 ForEach($customArray) { $entity in
42 HStack {
43 Toggle(isOn: $entity.enabled) {
44 Text(entity.name)
45 .foregroundColor(Colors.darkTextColor.color)
46 .font(.system(size: 16, weight: entity.name == "All entities" ? .bold : .regular, design: .default))
47 }
48 .toggleStyle(MyToggleStyle1())
49
50 Spacer()
51 }.padding(.top, 12)
52 }
53
54 Spacer()
55 }
56 }
57
58 Spacer()
59 }.padding()
60 }
61}
62
63struct Entity: Identifiable, Codable, Equatable { // << here !!
64
65 var id = UUID()
66 let name: String
67 var enabled: Bool
68
69 init(name: String, enabled: Bool) {
70 self.name = name
71 self.enabled = enabled
72 }
73
74 static func == (lhs: Entity, rhs: Entity) -> Bool {
75 lhs.id == rhs.id && lhs.enabled == rhs.enabled // << here !!
76 }
77}
78
QUESTION
How to return a Reactive Flux that contains a Reactive Mono and Flux?
Asked 2022-Jan-14 at 07:24I'm new to reactive programming and ran into this problem:
1[
2 {
3 "customerDTO": {
4 "scanAvailable": true
5 },
6 "bankAccountDTOs": {
7 "scanAvailable": true,
8 "prefetch": -1
9 }
10 }
11]
12
DTO:
1[
2 {
3 "customerDTO": {
4 "scanAvailable": true
5 },
6 "bankAccountDTOs": {
7 "scanAvailable": true,
8 "prefetch": -1
9 }
10 }
11]
12public class ResponseClientDTO {
13 private Mono<CustomerDTO> customerDTO;
14 private Flux<BankAccountDTO> bankAccountDTOs;
15}
16
Service:
1[
2 {
3 "customerDTO": {
4 "scanAvailable": true
5 },
6 "bankAccountDTOs": {
7 "scanAvailable": true,
8 "prefetch": -1
9 }
10 }
11]
12public class ResponseClientDTO {
13 private Mono<CustomerDTO> customerDTO;
14 private Flux<BankAccountDTO> bankAccountDTOs;
15}
16public Flux<ResponseClientDTO> getCustomerWithBankAccounts(String customerId){
17 Flux<BankAccountDTO> bankAccounts = webClient
18 .get()
19 .uri(uriBuilder ->
20 uriBuilder.path("customers")
21 .queryParam("customerId", customerId).build())
22 .accept(MediaType.APPLICATION_JSON)
23 .retrieve()
24 .bodyToFlux(BankAccountDTO.class);
25
26
27 Mono<CustomerDTO> cMono = findOne(customerId);
28
29 ResponseClientDTO responseClientDTO = new ResponseClientDTO();
30 responseClientDTO.setBankAccountDTOs(bankAccounts);
31 responseClientDTO.setCustomerDTO(cMono);
32
33 return Flux.just(responseClientDTO);
34}
35
I query an endpoint from another API, and it returns a Flux<BankAccounts>
. I want to get the client with all his bank accounts.
ANSWER
Answered 2022-Jan-14 at 07:24That is not what you want in a reactive stack. First, change your DTO (Data Transfer Object) so that it does't include Mono
and Flux
, but CustomerDTO
and List<BankAccountDTO>
instead:
1[
2 {
3 "customerDTO": {
4 "scanAvailable": true
5 },
6 "bankAccountDTOs": {
7 "scanAvailable": true,
8 "prefetch": -1
9 }
10 }
11]
12public class ResponseClientDTO {
13 private Mono<CustomerDTO> customerDTO;
14 private Flux<BankAccountDTO> bankAccountDTOs;
15}
16public Flux<ResponseClientDTO> getCustomerWithBankAccounts(String customerId){
17 Flux<BankAccountDTO> bankAccounts = webClient
18 .get()
19 .uri(uriBuilder ->
20 uriBuilder.path("customers")
21 .queryParam("customerId", customerId).build())
22 .accept(MediaType.APPLICATION_JSON)
23 .retrieve()
24 .bodyToFlux(BankAccountDTO.class);
25
26
27 Mono<CustomerDTO> cMono = findOne(customerId);
28
29 ResponseClientDTO responseClientDTO = new ResponseClientDTO();
30 responseClientDTO.setBankAccountDTOs(bankAccounts);
31 responseClientDTO.setCustomerDTO(cMono);
32
33 return Flux.just(responseClientDTO);
34}
35public class ResponseClientDTO {
36 private CustomerDTO customerDTO;
37 private List<BankAccountDTO> bankAccountDTOs;
38}
39
Then, you need to rearrange your method to return a Mono<ResponseClientDTO>
instead and to change the logic to deal with Flux
and Mono
:
1[
2 {
3 "customerDTO": {
4 "scanAvailable": true
5 },
6 "bankAccountDTOs": {
7 "scanAvailable": true,
8 "prefetch": -1
9 }
10 }
11]
12public class ResponseClientDTO {
13 private Mono<CustomerDTO> customerDTO;
14 private Flux<BankAccountDTO> bankAccountDTOs;
15}
16public Flux<ResponseClientDTO> getCustomerWithBankAccounts(String customerId){
17 Flux<BankAccountDTO> bankAccounts = webClient
18 .get()
19 .uri(uriBuilder ->
20 uriBuilder.path("customers")
21 .queryParam("customerId", customerId).build())
22 .accept(MediaType.APPLICATION_JSON)
23 .retrieve()
24 .bodyToFlux(BankAccountDTO.class);
25
26
27 Mono<CustomerDTO> cMono = findOne(customerId);
28
29 ResponseClientDTO responseClientDTO = new ResponseClientDTO();
30 responseClientDTO.setBankAccountDTOs(bankAccounts);
31 responseClientDTO.setCustomerDTO(cMono);
32
33 return Flux.just(responseClientDTO);
34}
35public class ResponseClientDTO {
36 private CustomerDTO customerDTO;
37 private List<BankAccountDTO> bankAccountDTOs;
38}
39public Mono<ResponseClientDTO> getCustomerWithBankAccounts(String customerId){
40 Flux<BankAccountDTO> bankAccounts = webClient
41 .get()
42 .uri(uriBuilder ->
43 uriBuilder.path("customers")
44 .queryParam("customerId", customerId).build())
45 .accept(MediaType.APPLICATION_JSON)
46 .retrieve()
47 .bodyToFlux(BankAccountDTO.class);
48
49 Mono<CustomerDTO> cMono = findOne(customerId);
50
51 return bankAccounts.collectList().zipWith(cMono).map(data -> {
52 ResponseClientDTO responseClientDTO = new ResponseClientDTO();
53 responseClientDTO.setBankAccountDTOs(data.getT1());
54 responseClientDTO.setCustomerDTO(data.getT2());
55 })
56}
57
(Sorry for any Java typo but at this point I am too used to Kotlin).
Consider taking a look at the following useful online resources:
QUESTION
Setting an @Published var to nil after no more events are received
Asked 2021-Nov-20 at 16:40Consider the following code:
1class MyController: NSObject, ObservableObject {
2
3 //...
4
5 @Published var myRapidlyChangingVar: MyEnum? = nil
6
7 //...
8
9 func calledAtHighFrequencyByExternalEvents(value: MyEnum) {
10 myRapidlyChangingVar = value
11 }
12}
13
The value of myRapidlyChangingVar
needs to be set to nil
if no calls to calledAtHighFrequencyByExternalEvents()
have been made for 1 second.
What is the simplest and cleanest approach to adopt to achieve this?
Strikes me as the sort of thing which Reactive programming should make incredibly simple, but unsure where to start or what to search for.
ANSWER
Answered 2021-Nov-20 at 16:40You can easily achive this with a debounce(for:scheduler:options:)
1class MyController: NSObject, ObservableObject {
2
3 //...
4
5 @Published var myRapidlyChangingVar: MyEnum? = nil
6
7 //...
8
9 func calledAtHighFrequencyByExternalEvents(value: MyEnum) {
10 myRapidlyChangingVar = value
11 }
12}
13let cancellable = myRapidlyChangingVar
14 .compactMap { $0 }
15 .debounce(for: .seconds(1), scheduler: DispatchQueue.main)
16 .sink { [weak self] _ in self?.myRapidlyChangingVar = nil }
17}
18
Debounce has a fairly similar sibiling throttle(for:scheduler:latest:)
You can read more about both in this blogpost.
QUESTION
Is it possible for a non reactive Client (RestTemplate) to consume a Reactive REST API (WebFlux)
Asked 2021-Nov-14 at 00:40Is it possible for a RestTemplate to consume an endpoint which is reactive based (Spring WebFlux)? I understand that the main idea of reactive programming is to avoid blocking and make better use of threads (eliminate thread per connection model) so what happens if my Client is non reactive?
1.- Will I still be able to call the service even if it is in a blocking manner?
2.- To achieve full reactiveness (non blocking) both Client and Server must be reactive?
ANSWER
Answered 2021-Nov-14 at 00:40- Yes, that is not relevant to the clients of Reactive applications. The reason is that this is a regular HTTP call.
- Each may be fully reactive on its own. Having said that, if you use WebFlux in both Client and Server you will have a system that is as a whole reactive. But there is nothing forcing you to do this. You can have only one of the services as a Reactive application. It comes down to your needs and context.
QUESTION
How to re-render UI in response to computed property buried in a nested class?
Asked 2021-Nov-11 at 00:51It's not clear to me how you would combine the output of the following computed property, to the UI.
1var isComplete: Bool {
2 Set([.givenName, .familyName]).isSubset(of: elements)
3}
4
I essentially want the user interface to update if the above changes. How would I do this using Combine?
Reactive programming demands that I now think backwards and I'm having trouble thinking about model <<< UI rather than model >>> UI.
Here is the code in context.
1var isComplete: Bool {
2 Set([.givenName, .familyName]).isSubset(of: elements)
3}
4struct EditPersonView: View {
5
6 let model: ViewModel
7
8 private var captionView: some View {
9 HStack {
10 /*
11 stuff
12 */
13 if submitted && model.name.isComplete {
14 Spacer()
15 Text("select".localizedCapitalized) + Text(" ") + Text("save") + Text(" ") + Text("👆")
16 }
17 }
18 }
19
20 var body: some View {
21 /*
22 stuff - including captionView
23 */
24 }
25}
26
27extension EditPersonView {
28
29 final class ViewModel {
30
31 let name: PersonName
32
33 init(person: Person) {
34 self.name = PersonName(for: person)
35 }
36 }
37}
38
39extension EditPersonView.ViewModel {
40
41 final class PersonName {
42
43 let person: Person
44
45 private let formatter = PersonNameComponentsFormatter()
46
47 init(for person: Person) {
48 self.person = person
49 }
50
51 var text: String {
52 get { person.name ?? "" }
53 set { person.name = newValue }
54 }
55
56 private var components: PersonNameComponents? {
57 formatter.personNameComponents(from: text)
58 }
59
60 var givenName: String? {
61 components?.givenName
62 }
63
64 var familyName: String? {
65 components?.familyName
66 }
67
68 private func isValid(component: String?) -> Bool {
69 if let name = component, name.count > 1 {
70 return true
71 }
72 return false
73 }
74
75 var elements: Set<Elements> {
76 var collection = Set<Elements>()
77 if isValid(component: givenName) { collection.insert(.givenName) }
78 if isValid(component: familyName) { collection.insert(.familyName) }
79 return collection
80 }
81
82 var isComplete: Bool {
83 Set([.givenName, .familyName]).isSubset(of: elements)
84 }
85 }
86}
87
88extension EditPersonView.ViewModel.PersonName {
89
90 enum Elements {
91 case givenName, familyName
92 }
93}
94
ANSWER
Answered 2021-Nov-11 at 00:51Below is what I came up with.
The root of the sequence is the textPublisher
. This begins the sequence with the values sent to text
.
didSet
sends the text to the sequence and saves it in the person's name just as the original code does.
isComplete
becomes a publisher that sends true
or false
depending on whether the components are valid. The chain of map
operators each take the value through one step of the computations in your original code. You could easily reduce this to a single map
I would think. (or filter the computations out into functions with meaningful names and substitute the functions for the closures)
An external Subscriber
could subscribe to isComplete
and respond when it emits a true
value.
1var isComplete: Bool {
2 Set([.givenName, .familyName]).isSubset(of: elements)
3}
4struct EditPersonView: View {
5
6 let model: ViewModel
7
8 private var captionView: some View {
9 HStack {
10 /*
11 stuff
12 */
13 if submitted && model.name.isComplete {
14 Spacer()
15 Text("select".localizedCapitalized) + Text(" ") + Text("save") + Text(" ") + Text("👆")
16 }
17 }
18 }
19
20 var body: some View {
21 /*
22 stuff - including captionView
23 */
24 }
25}
26
27extension EditPersonView {
28
29 final class ViewModel {
30
31 let name: PersonName
32
33 init(person: Person) {
34 self.name = PersonName(for: person)
35 }
36 }
37}
38
39extension EditPersonView.ViewModel {
40
41 final class PersonName {
42
43 let person: Person
44
45 private let formatter = PersonNameComponentsFormatter()
46
47 init(for person: Person) {
48 self.person = person
49 }
50
51 var text: String {
52 get { person.name ?? "" }
53 set { person.name = newValue }
54 }
55
56 private var components: PersonNameComponents? {
57 formatter.personNameComponents(from: text)
58 }
59
60 var givenName: String? {
61 components?.givenName
62 }
63
64 var familyName: String? {
65 components?.familyName
66 }
67
68 private func isValid(component: String?) -> Bool {
69 if let name = component, name.count > 1 {
70 return true
71 }
72 return false
73 }
74
75 var elements: Set<Elements> {
76 var collection = Set<Elements>()
77 if isValid(component: givenName) { collection.insert(.givenName) }
78 if isValid(component: familyName) { collection.insert(.familyName) }
79 return collection
80 }
81
82 var isComplete: Bool {
83 Set([.givenName, .familyName]).isSubset(of: elements)
84 }
85 }
86}
87
88extension EditPersonView.ViewModel.PersonName {
89
90 enum Elements {
91 case givenName, familyName
92 }
93}
94final class PersonName {
95 var person: Person
96
97 private let formatter = PersonNameComponentsFormatter()
98
99 let textPublisher = PassthroughSubject<String, Never>()
100 var text: String {
101 get { person.name ?? "" }
102 set { textPublisher.send(newValue); person.name = newValue }
103 }
104
105 var isComplete : AnyPublisher<Bool, Never>!
106
107 init(for person: Person) {
108 self.person = person
109
110 isComplete = textPublisher
111 .map{ self.formatter.personNameComponents(from: $0) }
112 .map{ (components: PersonNameComponents?) -> Set<Elements> in
113 var collection = Set<Elements>()
114
115 if let components = components {
116 if self.isValid(component: components.givenName) { collection.insert(.givenName) }
117 if self.isValid(component: components.familyName) { collection.insert(.familyName) }
118 }
119
120 return collection
121 }
122 .map { Set([Elements.givenName, Elements.familyName]).isSubset(of: $0) }
123 .eraseToAnyPublisher()
124 }
125
126 private func isValid(component: String?) -> Bool {
127 if let name = component, name.count > 1 {
128 return true
129 }
130 return false
131 }
132}
133
QUESTION
Scatter & Gather using Spring Webclient
Asked 2021-Oct-26 at 07:13I am new to reactive programming concepts and trying to build one service that sends requests to a two backend service in parallel and combine those results. Those two backend service has a different response structure and i have created a mapper method to convert all that into a common Response structure.
This is what i have right now and it is working when both the services return results.
1public Mono<List<Response>> getRecords(String input){
2
3List<Response> response = new ArrayList<>();
4
5Mono<FirstApiResponse> gResp = this.firstWebClient.get().uri(uriBuilder -> uriBuilder
6 .path("/")
7 .queryParam("q", input)
8 .build()).retrieve()
9 .bodyToMono(FirstApiResponse.class).log()
10 .timeout(Duration.ofSeconds(50L));
11
12Mono<SecondApiResponse> iResp = this.secondWebClient.get().uri(uriBuilder -> uriBuilder
13 .path("/search")
14 .queryParam("term", input)
15 .build()).retrieve()
16 .bodyToMono(SecondApiResponse.class).log().timeout(Duration.ofSeconds(50L));
17
18
19return Mono.zip(firstResp,secResp).map(objects ->{
20 if(firstResp != null)
21 response.addAll(Mapper.convert(objects.getT1()));
22 if(secResp != null);
23 response.addAll(Mapper.convert(objects.getT2()));
24 return response;
25});
26
27}
28
29public List<Response> convert(FirstApiResponse resp){
30 ////
31 Mapping to Response object
32 ////
33
34 return response;
35}
36
37public List<Response> convert(SecondApiResponse resp){
38 ////
39 Mapping to Response object
40 ////
41
42 return response;
43}
44
I don't know if this is the right way to do it. Moreover, i want to make it in such a way that if there is any errors from any of this service, then it should still return the results from the other service. Right now it throws the exception and I am not able to figure out how to handle it properly
How to handle these errors in a proper way ?
ANSWER
Answered 2021-Oct-26 at 07:13This is a pretty valid scenario and there are many ways to handle it. One crude way would be to use onErrorReturn
a new Model which you can handle. It could be either an empty response or a wrapper around your model whichever seems fit for your scenario.
1public Mono<List<Response>> getRecords(String input){
2
3List<Response> response = new ArrayList<>();
4
5Mono<FirstApiResponse> gResp = this.firstWebClient.get().uri(uriBuilder -> uriBuilder
6 .path("/")
7 .queryParam("q", input)
8 .build()).retrieve()
9 .bodyToMono(FirstApiResponse.class).log()
10 .timeout(Duration.ofSeconds(50L));
11
12Mono<SecondApiResponse> iResp = this.secondWebClient.get().uri(uriBuilder -> uriBuilder
13 .path("/search")
14 .queryParam("term", input)
15 .build()).retrieve()
16 .bodyToMono(SecondApiResponse.class).log().timeout(Duration.ofSeconds(50L));
17
18
19return Mono.zip(firstResp,secResp).map(objects ->{
20 if(firstResp != null)
21 response.addAll(Mapper.convert(objects.getT1()));
22 if(secResp != null);
23 response.addAll(Mapper.convert(objects.getT2()));
24 return response;
25});
26
27}
28
29public List<Response> convert(FirstApiResponse resp){
30 ////
31 Mapping to Response object
32 ////
33
34 return response;
35}
36
37public List<Response> convert(SecondApiResponse resp){
38 ////
39 Mapping to Response object
40 ////
41
42 return response;
43}
44Mono<Wrapper<FirstApiResponse>> gResp = this.firstWebClient.get().uri(uriBuilder -> uriBuilder
45 .path("/")
46 .queryParam("q", input)
47 .build()).retrieve()
48 .bodyToMono(FirstApiResponse.class).log()
49 .map( response -> new Wrapper().withResponse(response))
50 .timeout(Duration.ofSeconds(50L))
51 .doOnError(throwable -> logger.error("Failed", throwable))
52 .onErrorReturn(new Wrapper().withError( YourDefaultErrorReponse(...));
53
54Mono<SecondApiResponse> iResp = this.secondWebClient.get().uri(uriBuilder -> uriBuilder
55 .path("/search")
56 .queryParam("term", input)
57 .build())
58 .retrieve()
59 .bodyToMono(SecondApiResponse.class).log()
60 .map( response -> new Wrapper().withResponse(response))
61 .timeout(Duration.ofSeconds(50L))
62 ..doOnError(throwable -> logger.error("Failed", throwable))
63 .onErrorReturn(new Wrapper().withError( YourDefaultErrorReponse(...))
64
Again there are ways to return a default response. A simple one would be to use something like a wrapper
1public Mono<List<Response>> getRecords(String input){
2
3List<Response> response = new ArrayList<>();
4
5Mono<FirstApiResponse> gResp = this.firstWebClient.get().uri(uriBuilder -> uriBuilder
6 .path("/")
7 .queryParam("q", input)
8 .build()).retrieve()
9 .bodyToMono(FirstApiResponse.class).log()
10 .timeout(Duration.ofSeconds(50L));
11
12Mono<SecondApiResponse> iResp = this.secondWebClient.get().uri(uriBuilder -> uriBuilder
13 .path("/search")
14 .queryParam("term", input)
15 .build()).retrieve()
16 .bodyToMono(SecondApiResponse.class).log().timeout(Duration.ofSeconds(50L));
17
18
19return Mono.zip(firstResp,secResp).map(objects ->{
20 if(firstResp != null)
21 response.addAll(Mapper.convert(objects.getT1()));
22 if(secResp != null);
23 response.addAll(Mapper.convert(objects.getT2()));
24 return response;
25});
26
27}
28
29public List<Response> convert(FirstApiResponse resp){
30 ////
31 Mapping to Response object
32 ////
33
34 return response;
35}
36
37public List<Response> convert(SecondApiResponse resp){
38 ////
39 Mapping to Response object
40 ////
41
42 return response;
43}
44Mono<Wrapper<FirstApiResponse>> gResp = this.firstWebClient.get().uri(uriBuilder -> uriBuilder
45 .path("/")
46 .queryParam("q", input)
47 .build()).retrieve()
48 .bodyToMono(FirstApiResponse.class).log()
49 .map( response -> new Wrapper().withResponse(response))
50 .timeout(Duration.ofSeconds(50L))
51 .doOnError(throwable -> logger.error("Failed", throwable))
52 .onErrorReturn(new Wrapper().withError( YourDefaultErrorReponse(...));
53
54Mono<SecondApiResponse> iResp = this.secondWebClient.get().uri(uriBuilder -> uriBuilder
55 .path("/search")
56 .queryParam("term", input)
57 .build())
58 .retrieve()
59 .bodyToMono(SecondApiResponse.class).log()
60 .map( response -> new Wrapper().withResponse(response))
61 .timeout(Duration.ofSeconds(50L))
62 ..doOnError(throwable -> logger.error("Failed", throwable))
63 .onErrorReturn(new Wrapper().withError( YourDefaultErrorReponse(...))
64public final class Wrapper<T> {
65 private T response ;
66 private Error error;
67
68 public Wrapper<T> withResponse ( T response ){
69 this.response = response;
70 return this;
71 }
72 public Wrapper<T> withError( Error error) {
73 this.error = error;
74 return this;
75 }
76
77 public Boolean hasError(){
78 return error != null ;
79 }
80
81 public T getResponse(){
82 return response;
83 }
84}
85
QUESTION
Return a String value when method return type is Mono<String>
Asked 2021-Oct-06 at 03:48My method returns a Mono<String>
response back to the controller. However, I am getting the following error
while trying to return a String
value.
1Required Type: Mono<String>,
2Provided: Mono<Object>
3no instance(s) of type variable(s) T exist so that Mono<T> conforms to String inference variable R has incompatible bounds: equality constraints
4
Service:
1Required Type: Mono<String>,
2Provided: Mono<Object>
3no instance(s) of type variable(s) T exist so that Mono<T> conforms to String inference variable R has incompatible bounds: equality constraints
4public Mono<String> moveToDB(String pid, String op, MoveRequest moveRequest) {
5 return Mono.just(pid)
6 .subscribeOn(Schedulers.boundedElastic())
7 .map(id -> persistenceService.withTransaction((s, em) -> {
8 //some code goes here
9 if (condition)
10 return "data sync failed"; //ERROR
11 return "data synced successfully"; //ERROR
12 }));
13}
14
I am new to reactive programming and I am probably making a silly mistake but I'd appreciate some help on this. Thanks!
ANSWER
Answered 2021-Oct-05 at 17:28I guess method withTransaction()
does not return String
as it should. You should map the return value to a String
:
1Required Type: Mono<String>,
2Provided: Mono<Object>
3no instance(s) of type variable(s) T exist so that Mono<T> conforms to String inference variable R has incompatible bounds: equality constraints
4public Mono<String> moveToDB(String pid, String op, MoveRequest moveRequest) {
5 return Mono.just(pid)
6 .subscribeOn(Schedulers.boundedElastic())
7 .map(id -> persistenceService.withTransaction((s, em) -> {
8 //some code goes here
9 if (condition)
10 return "data sync failed"; //ERROR
11 return "data synced successfully"; //ERROR
12 }));
13}
14.map(id -> service.withTransaction((s, em) -> {
15 //some code goes here
16 if (true)
17 return "data sync failed";
18 return "data synced successfully";
19}))
20.map(e -> e.toString()); //or whatever
21
QUESTION
In reactive programming, is the sequence of doOnNext calls guaranteed?
Asked 2021-Sep-27 at 13:08Reactive programming newbie. I have a sequence of calls in my Flux and I need to ensure they're done in order. Eg
1Flux<Thing> flux = ...
2.doOnNext(this::sendThing)
3.doOnNext(this::persistThing)
4.doOnError(error -> log.error("", error))
5.blockLast();
6
I need to ensure that sendThing
completes before persistThing
. I'm unclear, being a reactive newbie, if this is guaranteed.
ANSWER
Answered 2021-Sep-24 at 21:24Not familiar with this reactive implementation, but looks like you're adding two independent subscribers to a single observable, which does not guarantee an order of execution.
If send and persist are blocking (sync) functions you can just create some 'sendAndSync' function.
Otherwise, you need to make the 'send' into and observable itself, and 'persist' should be its subscriber. You can achieve this by 'send' writing to a PublishSubject once a send is completed, and 'persist' being the subscriber (via doOnNext) of that PublishSubject.
QUESTION
Why does the `R` pipe operator `|>` not work in the reactive programming using Shiny?
Asked 2021-Sep-22 at 09:38I want to use the pipe operator |>
in the latest version of R
while doing reactive programming with Shiny
. For example, when I use the |>
in the server
function like so:
1library(shiny)
2
3ui <- fluidPage(
4 textInput("age", "How old are you?"),
5 textOutput("message")
6)
7
8server <- function(input, output, server) {
9 message <- paste0("You are ", input$age) |> reactive({})
10 output$message <- renderText(message())
11}
12
13shinyApp(ui, server)
14
I get this error:
1library(shiny)
2
3ui <- fluidPage(
4 textInput("age", "How old are you?"),
5 textOutput("message")
6)
7
8server <- function(input, output, server) {
9 message <- paste0("You are ", input$age) |> reactive({})
10 output$message <- renderText(message())
11}
12
13shinyApp(ui, server)
14Listening on http://127.0.0.1:4346
15Warning: Error in : `env` must be an environment
16 56: <Anonymous>
17Error : `env` must be an environment
18
This error is fixed when I make slight changes in my server function like so:
1library(shiny)
2
3ui <- fluidPage(
4 textInput("age", "How old are you?"),
5 textOutput("message")
6)
7
8server <- function(input, output, server) {
9 message <- paste0("You are ", input$age) |> reactive({})
10 output$message <- renderText(message())
11}
12
13shinyApp(ui, server)
14Listening on http://127.0.0.1:4346
15Warning: Error in : `env` must be an environment
16 56: <Anonymous>
17Error : `env` must be an environment
18server <- function(input, output, server) {
19 message <- reactive({paste0("You are ", input$age, " years old")})
20 output$message <- renderText(message())
21}
22
However, I would like to be able to use the pipe operator in my Shiny
apps. What is wrong with the way I use |>
in my shiny app?
ANSWER
Answered 2021-Sep-22 at 09:38The problem is, that you are passing an empty expression {}
to reactive
's first argument (x argument: reactive(x = {})
).
With your above code the pipe |>
passes it's expression to reactive
's second argument env
, which results in the error you get. See ?reactive
This works:
1library(shiny)
2
3ui <- fluidPage(
4 textInput("age", "How old are you?"),
5 textOutput("message")
6)
7
8server <- function(input, output, server) {
9 message <- paste0("You are ", input$age) |> reactive({})
10 output$message <- renderText(message())
11}
12
13shinyApp(ui, server)
14Listening on http://127.0.0.1:4346
15Warning: Error in : `env` must be an environment
16 56: <Anonymous>
17Error : `env` must be an environment
18server <- function(input, output, server) {
19 message <- reactive({paste0("You are ", input$age, " years old")})
20 output$message <- renderText(message())
21}
22library(shiny)
23
24ui <- fluidPage(
25 textInput("age", "How old are you?"),
26 textOutput("message")
27)
28
29server <- function(input, output, server) {
30 message <- paste0("You are ", input$age) |> reactive()
31 output$message <- renderText(message())
32}
33
34shinyApp(ui, server)
35
QUESTION
Spring Webflux vs Rsocket
Asked 2021-Aug-26 at 07:03is have been studying rsocket and reactive programming for a while and quite often spring webflux is mentioned i wanted to ask whats the difference between the rsocket and spring webflux or are they same things.Thanks
ANSWER
Answered 2021-Aug-26 at 07:03RSocket (https://rsocket.io) provides a protocol for Reactive Streams semantics between client-server, and server-server communication. It allows you to use Flow (Flux), or a single response (Mono) over a network with various semantics and bidirectionally.
Spring Webflow (https://spring.io/projects/spring-webflow) is a way to build a webapp with reactive stream semantics for non blocking operations.
Typically you might combine these, such as your backend connecting to other services using RSocket, or you might choose for some clients (e.g. Javscript running in the browser) to talk to the server using RSocket over WebSockets for streaming events.
Community Discussions contain sources that include Stack Exchange Network
Tutorials and Learning Resources in Reactive Programming
Tutorials and Learning Resources are not available at this moment for Reactive Programming