|
| 1 | +# SpringCloud Gateway RSocket Example |
| 2 | + |
| 3 | +## What is RSocket ? |
| 4 | + |
| 5 | +Check out the official docs: [RSocket Docs](https://rsocket.io/docs/) |
| 6 | + |
| 7 | +> Most interesting: |
| 8 | +>>Network communication is asynchronous. The RSocket protocol embraces |
| 9 | +>>this and models all communication as multiplexed streams of messages |
| 10 | +>>over a single network connection, and never synchronously blocks while |
| 11 | +>>waiting for a response |
| 12 | +
|
| 13 | +In this example I am using a SpringCloud Gateway (reactive) to demonstrate how |
| 14 | +RSocket communication works over **WebSocket**. |
| 15 | + |
| 16 | +## Motivation |
| 17 | + |
| 18 | +We'd like to use a **single** websocket *endpoint/broker* for multiple services. |
| 19 | +The *normal* spring integration with *STOMP over WebSocket* cannot be used on the |
| 20 | +reactive stack. Therefore, I had to take a deeper look into RSocket. |
| 21 | + |
| 22 | +## The Example |
| 23 | + |
| 24 | +The server is creating scheduled *order* events which are added to a stream, those can |
| 25 | +be retrieved using a *HTTP GET* or *RSocket Request Stream*. |
| 26 | + |
| 27 | +There are two *kind* of order, LOTR (Lord of the Rings) order and GOT (game of Thrones) order, |
| 28 | +to demonstrate how *routes* (& security) can be handled. |
| 29 | + |
| 30 | +The order event is a *order* with random *kind*. |
| 31 | + |
| 32 | +## Test it |
| 33 | + |
| 34 | +Either use the checked in IntelliJ run-configuration in *.run* or launch it manually. |
| 35 | + |
| 36 | +**Server:** (Maven v3.6.3) |
| 37 | + |
| 38 | +```shell |
| 39 | +$ mvn clean package |
| 40 | +$ cd target/ |
| 41 | +$ java -jar {{appname-version}}.jar |
| 42 | +``` |
| 43 | + |
| 44 | +**Client:** (Node v14.16.0 & NPM v6.14.11) |
| 45 | + |
| 46 | +```shell |
| 47 | +$ cd frontend |
| 48 | +$ npm install |
| 49 | +$ npm run dev |
| 50 | +``` |
| 51 | + |
| 52 | +The web browser will open automatically, and you are ready to test it. |
| 53 | + |
| 54 | +#### Ports used |
| 55 | + |
| 56 | +*Server:* 8070 |
| 57 | + |
| 58 | +*Client:* 8080 |
| 59 | + |
| 60 | +### Test with other tools |
| 61 | + |
| 62 | +#### RSocket |
| 63 | + |
| 64 | +For RSocket development is used [RSC](https://github.com/making/rsc) installed using |
| 65 | +`brew install making/tap/rsc`. |
| 66 | + |
| 67 | +Now you are ready to go. Make sure the server is running and fire: |
| 68 | + |
| 69 | +```shell |
| 70 | +# Basic |
| 71 | +$ rsc --stream --route=orders.all --debug ws://localhost:8070/server/rsocket |
| 72 | +$ rsc --stream --route=orders.lotr --debug ws://localhost:8070/server/rsocket |
| 73 | +$ rsc --stream --route=orders.got --debug ws://localhost:8070/server/rsocket |
| 74 | + |
| 75 | +# With data (payload) |
| 76 | +$ rsc --stream --route=orders.all --debug --data='{"rscclient":"request"}' ws://localhost:8070/server/rsocket |
| 77 | + |
| 78 | +# With metadata |
| 79 | +$ rsc --stream --route=orders.all --debug --metadata='{"data":"custom metadata value from rsc"}' ws://localhost:8070/server/rsocket |
| 80 | +``` |
| 81 | + |
| 82 | +This will produce output like: |
| 83 | + |
| 84 | +```text |
| 85 | +
|
| 86 | +2021-03-12 13:20:57.654 DEBUG 81691 --- [actor-tcp-nio-2] io.rsocket.FrameLogger : receiving -> |
| 87 | +Frame => Stream ID: 1 Type: NEXT Flags: 0b100000 Length: 194 |
| 88 | +Data: |
| 89 | + +-------------------------------------------------+ |
| 90 | + | 0 1 2 3 4 5 6 7 8 9 a b c d e f | |
| 91 | ++--------+-------------------------------------------------+----------------+ |
| 92 | +|00000000| 7b 22 64 61 74 65 54 69 6d 65 22 3a 22 32 30 32 |{"dateTime":"202| |
| 93 | +|00000010| 31 2d 30 33 2d 31 32 54 31 33 3a 32 30 3a 35 37 |1-03-12T13:20:57| |
| 94 | +|00000020| 2e 36 35 33 35 37 32 2b 30 31 3a 30 30 22 2c 22 |.653572+01:00","| |
| 95 | +|00000030| 65 6e 74 72 79 22 3a 37 37 35 2c 22 6e 75 6d 62 |entry":775,"numb| |
| 96 | +|00000040| 65 72 22 3a 33 2c 22 6e 61 6d 65 22 3a 22 47 69 |er":3,"name":"Gi| |
| 97 | +|00000050| 6e 67 65 72 20 53 6e 61 70 70 22 2c 22 61 64 64 |nger Snapp","add| |
| 98 | +|00000060| 72 65 73 73 22 3a 22 39 30 38 33 38 20 59 6f 6c |ress":"90838 Yol| |
| 99 | +|00000070| 61 6e 64 61 20 53 74 61 74 69 6f 6e 2c 20 4c 61 |anda Station, La| |
| 100 | +|00000080| 6b 65 20 4d 61 75 72 69 63 65 2c 20 4d 41 20 30 |ke Maurice, MA 0| |
| 101 | +|00000090| 36 37 31 32 2d 30 36 33 38 22 2c 22 6b 69 6e 64 |6712-0638","kind| |
| 102 | +|000000a0| 22 3a 22 4c 4f 54 52 22 2c 22 69 74 65 6d 22 3a |":"LOTR","item":| |
| 103 | +|000000b0| 22 53 68 61 64 6f 77 66 61 78 22 7d |"Shadowfax"} | |
| 104 | ++--------+-------------------------------------------------+----------------+ |
| 105 | +{"dateTime":"2021-03-12T13:20:57.653572+01:00","entry":775,"number":3,"name":"Ginger Snapp", |
| 106 | +"address":"90838 Yolanda Station, Lake Maurice, MA 06712-0638","kind":"LOTR","item":"Shadowfax"} |
| 107 | +2021-03-12 13:21:02.658 DEBUG 81691 --- [actor-tcp-nio-2] io.rsocket.FrameLogger : receiving -> |
| 108 | +Frame => Stream ID: 1 Type: NEXT Flags: 0b100000 Length: 204 |
| 109 | +Data: |
| 110 | + +-------------------------------------------------+ |
| 111 | + | 0 1 2 3 4 5 6 7 8 9 a b c d e f | |
| 112 | ++--------+-------------------------------------------------+----------------+ |
| 113 | +|00000000| 7b 22 64 61 74 65 54 69 6d 65 22 3a 22 32 30 32 |{"dateTime":"202| |
| 114 | +|00000010| 31 2d 30 33 2d 31 32 54 31 33 3a 32 31 3a 30 32 |1-03-12T13:21:02| |
| 115 | +|00000020| 2e 36 35 37 36 35 33 2b 30 31 3a 30 30 22 2c 22 |.657653+01:00","| |
| 116 | +|00000030| 65 6e 74 72 79 22 3a 37 37 36 2c 22 6e 75 6d 62 |entry":776,"numb| |
| 117 | +|00000040| 65 72 22 3a 38 2c 22 6e 61 6d 65 22 3a 22 52 79 |er":8,"name":"Ry| |
| 118 | +|00000050| 61 6e 20 43 61 72 6e 61 74 69 6f 6e 22 2c 22 61 |an Carnation","a| |
| 119 | +|00000060| 64 64 72 65 73 73 22 3a 22 53 75 69 74 65 20 38 |ddress":"Suite 8| |
| 120 | +|00000070| 37 33 20 32 32 38 37 20 45 66 66 65 72 74 7a 20 |73 2287 Effertz | |
| 121 | +|00000080| 53 70 75 72 2c 20 49 67 6e 61 63 69 61 76 69 65 |Spur, Ignaciavie| |
| 122 | +|00000090| 77 2c 20 4e 48 20 31 38 36 35 39 2d 39 31 32 30 |w, NH 18659-9120| |
| 123 | +|000000a0| 22 2c 22 6b 69 6e 64 22 3a 22 4c 4f 54 52 22 2c |","kind":"LOTR",| |
| 124 | +|000000b0| 22 69 74 65 6d 22 3a 22 54 6f 6d 20 42 6f 6d 62 |"item":"Tom Bomb| |
| 125 | +|000000c0| 61 64 69 6c 22 7d |adil"} | |
| 126 | ++--------+-------------------------------------------------+----------------+ |
| 127 | +{"dateTime":"2021-03-12T13:21:02.657653+01:00","entry":776,"number":8,"name":"Ryan Carnation", |
| 128 | +"address":"Suite 873 2287 Effertz Spur, Ignaciaview, NH 18659-9120","kind":"LOTR","item":"Tom Bombadil"} |
| 129 | +2021-03-12 13:21:07.663 DEBUG 81691 --- [actor-tcp-nio-2] io.rsocket.FrameLogger : receiving -> |
| 130 | +Frame => Stream ID: 1 Type: NEXT Flags: 0b100000 Length: 202 |
| 131 | +Data: |
| 132 | + +-------------------------------------------------+ |
| 133 | + | 0 1 2 3 4 5 6 7 8 9 a b c d e f | |
| 134 | ++--------+-------------------------------------------------+----------------+ |
| 135 | +|00000000| 7b 22 64 61 74 65 54 69 6d 65 22 3a 22 32 30 32 |{"dateTime":"202| |
| 136 | +|00000010| 31 2d 30 33 2d 31 32 54 31 33 3a 32 31 3a 30 37 |1-03-12T13:21:07| |
| 137 | +|00000020| 2e 36 36 32 38 33 31 2b 30 31 3a 30 30 22 2c 22 |.662831+01:00","| |
| 138 | +|00000030| 65 6e 74 72 79 22 3a 37 37 37 2c 22 6e 75 6d 62 |entry":777,"numb| |
| 139 | +|00000040| 65 72 22 3a 34 2c 22 6e 61 6d 65 22 3a 22 48 65 |er":4,"name":"He| |
| 140 | +|00000050| 61 74 68 65 72 20 4e 2e 20 59 6f 6e 6e 22 2c 22 |ather N. Yonn","| |
| 141 | +|00000060| 61 64 64 72 65 73 73 22 3a 22 33 33 34 20 5a 61 |address":"334 Za| |
| 142 | +|00000070| 63 68 61 72 79 20 4d 6f 75 6e 74 61 69 6e 2c 20 |chary Mountain, | |
| 143 | +|00000080| 43 72 75 69 63 6b 73 68 61 6e 6b 6c 61 6e 64 2c |Cruickshankland,| |
| 144 | +|00000090| 20 41 5a 20 34 33 32 32 37 22 2c 22 6b 69 6e 64 | AZ 43227","kind| |
| 145 | +|000000a0| 22 3a 22 4c 4f 54 52 22 2c 22 69 74 65 6d 22 3a |":"LOTR","item":| |
| 146 | +|000000b0| 22 47 72 c3 ac 6d 61 20 57 6f 72 6d 74 6f 6e 67 |"Gr..ma Wormtong| |
| 147 | +|000000c0| 75 65 22 7d |ue"} | |
| 148 | ++--------+-------------------------------------------------+----------------+ |
| 149 | +{"dateTime":"2021-03-12T13:21:07.662831+01:00","entry":777,"number":4,"name":"Heather N. Yonn", |
| 150 | +"address":"334 Zachary Mountain, Cruickshankland, AZ 43227","kind":"LOTR","item":"Grìma Wormtongue"} |
| 151 | +... |
| 152 | +
|
| 153 | +``` |
| 154 | + |
| 155 | +**Note:** The whole frames sent are visible, also check out the server logs. |
| 156 | + |
| 157 | +#### HTTP |
| 158 | + |
| 159 | +To retrieve the stream using *HTTP* I used [HTTPIE](https://httpie.io/) using: |
| 160 | + |
| 161 | +````shell |
| 162 | +http :8070/server/orders --stream |
| 163 | +```` |
| 164 | + |
| 165 | +This will produce output like: |
| 166 | + |
| 167 | +```json |
| 168 | +{ |
| 169 | + "address": "456 Herman Turnpike, Sporerchester, VT 49469-0588", |
| 170 | + "dateTime": "2021-03-12T13:23:07.754996+01:00", |
| 171 | + "entry": 801, |
| 172 | + "item": "Bethany Bracken", |
| 173 | + "kind": "GOT", |
| 174 | + "name": "Val Lay", |
| 175 | + "number": 6 |
| 176 | +} |
| 177 | + |
| 178 | +{ |
| 179 | + "address": "73538 Morar Well, West Cristobal, OH 28237", |
| 180 | + "dateTime": "2021-03-12T13:23:12.760175+01:00", |
| 181 | + "entry": 802, |
| 182 | + "item": "Kyle Condon", |
| 183 | + "kind": "GOT", |
| 184 | + "name": "Eli Ondefloor", |
| 185 | + "number": 0 |
| 186 | +} |
| 187 | + |
| 188 | +{ |
| 189 | + "address": "Suite 931 381 Bernita Lane, Lake Benjamin, TX 93575", |
| 190 | + "dateTime": "2021-03-12T13:23:17.765894+01:00", |
| 191 | + "entry": 803, |
| 192 | + "item": "Samwise Gamgee", |
| 193 | + "kind": "LOTR", |
| 194 | + "name": "Robin DeCraydle", |
| 195 | + "number": 6 |
| 196 | +} |
| 197 | + |
| 198 | +{ |
| 199 | + "address": "922 Julene Hollow, Bookermouth, WA 68785-6036", |
| 200 | + "dateTime": "2021-03-12T13:23:22.769958+01:00", |
| 201 | + "entry": 804, |
| 202 | + "item": "Arwen Evenstar", |
| 203 | + "kind": "LOTR", |
| 204 | + "name": "Ryan Coke", |
| 205 | + "number": 5 |
| 206 | +} |
| 207 | + |
| 208 | +{ |
| 209 | + "address": "Suite 063 41363 Omer Square, Machellemouth, NE 92997", |
| 210 | + "dateTime": "2021-03-12T13:23:27.771213+01:00", |
| 211 | + "entry": 805, |
| 212 | + "item": "Qezza", |
| 213 | + "kind": "GOT", |
| 214 | + "name": "Terry Achey", |
| 215 | + "number": 3 |
| 216 | +} |
| 217 | + |
| 218 | +... |
| 219 | + |
| 220 | +``` |
| 221 | + |
| 222 | +Use *HTTPie* to create order: |
| 223 | + |
| 224 | +```shell |
| 225 | +# Random |
| 226 | +http :8070/server/orders/new |
| 227 | +# Specific |
| 228 | +http :8070/server/orders/new kind==lotr |
| 229 | +http :8070/server/orders/new kind==got |
| 230 | +``` |
| 231 | + |
| 232 | +## Next up |
| 233 | + |
| 234 | +- [X] Payload integration |
| 235 | +- [X] Custom metadata |
| 236 | +- [X] Route with variable |
| 237 | +- [ ] SpringSecurity |
| 238 | +- [ ] Multiple routes |
0 commit comments