{"id":34439,"date":"2014-12-23T13:00:17","date_gmt":"2014-12-23T11:00:17","guid":{"rendered":"http:\/\/www.javacodegeeks.com\/?p=34439"},"modified":"2014-12-22T19:06:28","modified_gmt":"2014-12-22T17:06:28","slug":"accessing-meetups-streaming-api-with-rxnetty","status":"publish","type":"post","link":"https:\/\/www.javacodegeeks.com\/2014\/12\/accessing-meetups-streaming-api-with-rxnetty.html","title":{"rendered":"Accessing Meetup&#8217;s streaming API with RxNetty"},"content":{"rendered":"<p>This article will touch upon multiple subjects: reactive programming, HTTP, parsing JSON and integrating with social API. All in one use case: we will load and process new <a href=\"http:\/\/www.meetup.com\/\">meetup.com<\/a> events in real time via non-bloking <a href=\"https:\/\/github.com\/ReactiveX\/RxNetty\">RxNetty<\/a> library, combining the power of <a href=\"http:\/\/netty.io\/\">Netty<\/a> framework and flexibility of <a href=\"https:\/\/github.com\/ReactiveX\/RxJava\">RxJava<\/a> library. Meetup provides publicly available <a href=\"http:\/\/www.meetup.com\/meetup_api\/docs\/stream\/2\/open_events\/\">streaming API<\/a> that pushes every single Meetup registered all over the world in real-time. Just browse to <a href=\"https:\/\/stream.meetup.com\/2\/open_events\">stream.meetup.com\/2\/open_events<\/a> and observe how chunks of JSON are slowly appearing on your screen. Every time someone creates new event, self-containing JSON is pushed from the server to your browser. This means such request never ends, instead we keep receiving partial data as long as we want. We already examined similar scenario in <a href=\"http:\/\/www.nurkiewicz.com\/2014\/01\/turning-twitter4j-into-rxjavas.html\"><em>Turning Twitter4J into RxJava&#8217;s Observable<\/em><\/a>. Each new meetup event publishes a standalone JSON document, similar to this (lots of details omitted):<\/p>\n<pre class=\"brush:java\">{ \"id\" : \"219088449\",\r\n  \"name\" : \"Silver Wings Brunch\",\r\n  \"time\" : 1421609400000,\r\n  \"mtime\" : 1417814004321,\r\n  \"duration\" : 900000,\r\n  \"rsvp_limit\" : 0,\r\n  \"status\" : \"upcoming\",\r\n  \"event_url\" : \"http:\/\/www.meetup.com\/Laguna-Niguel-Social-Networking-Meetup\/events\/219088449\/\",\r\n  \"group\" : { \"name\" : \"Former Flight Attendants South Orange and North San Diego Co\",\r\n              \"state\" : \"CA\"\r\n              ...\r\n  },\r\n  \"venue\" : { \"address_1\" : \"26860 Ortega Highway\",\r\n              \"city\" : \"San Juan Capistrano\",\r\n              \"country\" : \"US\"\r\n              ...\r\n  },\r\n  \"venue_visibility\" : \"public\",\r\n  \"visibility\" : \"public\",\r\n  \"yes_rsvp_count\" : 1\r\n  ...\r\n}<\/pre>\n<p>Every time our long-polling HTTP connection (with <code>Transfer-Encoding: chunked<\/code>response header) pushes such piece of JSON, we want to parse it and somehow pass further. We hate callbacks, thus RxJava seems like a reasonable alternative (think: <code>Observable&lt;Event&gt;<\/code>).<\/p>\n<h2>Step 1: Receiving raw data with RxNetty<\/h2>\n<p>We can&#8217;t use ordinary HTTP client as they are focused on request-response semantics. There is no response here, we simply leave opened connection forever and consume data when it comes. RxJava has an out-of-the-box <a href=\"https:\/\/github.com\/ReactiveX\/RxApacheHttp\">RxApacheHttp<\/a> library, but it assumes <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Server-sent_events\/Using_server-sent_events\"><code>text\/event-stream<\/code> content type<\/a>. Instead we will use quite low-level, versatile RxNetty library. It&#8217;s a wrapper around Netty (duh!) and is capable of <a href=\"https:\/\/github.com\/ReactiveX\/RxNetty\/tree\/0.x\/rxnetty-examples\">implementing arbitrary<\/a> TCP\/IP (including HTTP) and UDP clients and servers. If you don&#8217;t know Netty, it&#8217;s packet- rather than stream-oriented, so we can expect one Netty event per each Meetup push. The API certainly isn&#8217;t straightforward, but makes sense once you grok it:<\/p>\n<pre class=\"brush:java;wrap-lines:false\">HttpClient&lt;ByteBuf, ByteBuf&gt; httpClient = RxNetty.&lt;ByteBuf, ByteBuf&gt;newHttpClientBuilder(\"stream.meetup.com\", 443)\r\n        .pipelineConfigurator(new HttpClientPipelineConfigurator&lt;&gt;())\r\n        .withSslEngineFactory(DefaultFactories.trustAll())\r\n        .build();\r\n \r\nfinal Observable&lt;HttpClientResponse&gt; responses = \r\n    httpClient.submit(HttpClientRequest.createGet(\"\/2\/open_events\"));\r\nfinal Observable byteBufs = \r\n    responses.flatMap(AbstractHttpContentHolder::getContent);\r\nfinal Observable chunks = \r\n    byteBufs.map(content -&gt; content.toString(StandardCharsets.UTF_8));\r\n<\/pre>\n<p>First we create <code>HttpClient<\/code> and set up SSL (keep in mind that <code>trustAll()<\/code> with regards to server certificates is probably not the best production setting). Later we<code>submit()<\/code> GET request and receive <code>Observable&lt;HttpClientResponse&lt;ByteBuf&gt;&gt;<\/code> in return. <code>ByteBuf<\/code> is Netty&#8217;s abstraction over a bunch of bytes sent or received over the wire. This observable will tell us immediately about every piece of data received from Meetup. After extracting <code>ByteBuf<\/code> from response we turn it into a <code>String<\/code> containing aforementioned JSON. So far so good, it works.<div style=\"display:inline-block; margin: 15px 0;\"> <div id=\"adngin-JavaCodeGeeks_incontent_video-0\" style=\"display:inline-block;\"><\/div> <\/div><\/p>\n<h2>Step 2: Aligning packets with JSON documents<\/h2>\n<p>Netty is very powerful because it doesn&#8217;t hide inherent complexity over leaky abstractions. Every time <em>something<\/em> is received over the TCP\/IP wire, we are notified. You might believe that when server sends 100 bytes, Netty on the client side will notify us about these 100 bytes received. However TCP\/IP stack is free to split and merge data you send over wire, especially since it is suppose to be a stream, so how it is split into packets should be irrelevant. This caveat is greatly explained in <a href=\"http:\/\/netty.io\/wiki\/user-guide-for-4.x.html#wiki-h3-11\">Netty&#8217;s documentation<\/a>. What does it mean to us? When Meetup sends a single event, we might receive just one <code>String<\/code> in <code>chunks<\/code> observable. But just as well it can be divided into arbitrary number of packets, thus <code>chunks<\/code> will emit multiple <code>String<\/code>s. Even worse, if Meetup sends two events right after another, they might fit in one packet. In that case<code>chunks<\/code> will emit one <code>String<\/code> with two independent JSON documents. As a matter of fact we can&#8217;t assume any alignment between JSON strings and networks packets received. All we know is that individual JSON documents representing events are separated by newlines. Amazingly, <a href=\"https:\/\/github.com\/ReactiveX\/RxJavaString\"><code>RxJavaString<\/code><\/a> official add-on has a method precisely for that:<\/p>\n<pre class=\"brush:java\">Observable jsonChunks = StringObservable.split(chunks, \"\\n\");<\/pre>\n<p>Actually there is even simpler <code>StringObservable.byLine(chunks)<\/code>, but it uses platform-dependent end-of-line. What <code>split()<\/code> does is best explained in <a href=\"http:\/\/reactivex.io\/documentation\/string.html\">official documentation<\/a>:<\/p>\n<p><a href=\"http:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2014\/12\/St.split_.png\"><img decoding=\"async\" class=\"aligncenter size-full wp-image-34861\" src=\"http:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2014\/12\/St.split_.png\" alt=\"St.split\" width=\"640\" height=\"213\" \/><\/a><\/p>\n<p>Now we can safely parse each <code>String<\/code> emitted by <code>jsonChunks<\/code>:<\/p>\n<h2>Step 3: Parsing JSON<\/h2>\n<p>Interestingly this step is not so straightforward. I admit, I <em>sort-of<\/em> enjoyed WSDL times because I could easily and predictably generate Java model that follows web-service&#8217;s contract. JSON, especially taking marginal market penetration of <a href=\"http:\/\/json-schema.org\/\">JSON schema<\/a>, is basically the Wild West of integration. Typically you are left with informal documentation or samples of requests and responses. No type information or format, whether fields are mandatory, etc. Moreover because I reluctantly work with <em>maps of maps<\/em> (hi there, fellow Clojure programmers), in order to work with JSON based REST services I have to write mapping POJOs myself. Well, there are workarounds. First I took one representative example of JSON produced by Meetup streaming API and placed it in <code>src\/main\/json\/meetup\/event.json<\/code>. Then I used <a href=\"https:\/\/github.com\/joelittlejohn\/jsonschema2pojo\"><code>jsonschema2pojo-maven-plugin<\/code><\/a> (<a href=\"http:\/\/www.jsonschema2pojo.org\/\">Gradle and Ant<\/a> versions exist as well). Plugin&#8217;s name is confusing, it can also work with JSON example, not only schema, to produce Java models:<\/p>\n<pre class=\"brush:xml\">&lt;plugin&gt;\r\n    &lt;groupId&gt;org.jsonschema2pojo&lt;\/groupId&gt;\r\n    &lt;artifactId&gt;jsonschema2pojo-maven-plugin&lt;\/artifactId&gt;\r\n    &lt;version&gt;0.4.7&lt;\/version&gt;\r\n    &lt;configuration&gt;\r\n        &lt;sourceDirectory&gt;${basedir}\/src\/main\/json\/meetup&lt;\/sourceDirectory&gt;\r\n        &lt;targetPackage&gt;com.nurkiewicz.meetup.generated&lt;\/targetPackage&gt;\r\n        &lt;includeHashcodeAndEquals&gt;true&lt;\/includeHashcodeAndEquals&gt;\r\n        &lt;includeToString&gt;true&lt;\/includeToString&gt;\r\n        &lt;initializeCollections&gt;true&lt;\/initializeCollections&gt;\r\n        &lt;sourceType&gt;JSON&lt;\/sourceType&gt;\r\n        &lt;useCommonsLang3&gt;true&lt;\/useCommonsLang3&gt;\r\n        &lt;useJodaDates&gt;true&lt;\/useJodaDates&gt;\r\n        &lt;useLongIntegers&gt;true&lt;\/useLongIntegers&gt;\r\n        &lt;outputDirectory&gt;target\/generated-sources&lt;\/outputDirectory&gt;\r\n    &lt;\/configuration&gt;\r\n    &lt;executions&gt;\r\n        &lt;execution&gt;\r\n            &lt;id&gt;generate-sources&lt;\/id&gt;\r\n            &lt;phase&gt;generate-sources&lt;\/phase&gt;\r\n            &lt;goals&gt;\r\n                &lt;goal&gt;generate&lt;\/goal&gt;\r\n            &lt;\/goals&gt;\r\n        &lt;\/execution&gt;\r\n    &lt;\/executions&gt;\r\n&lt;\/plugin&gt;\r\n<\/pre>\n<p>At this point Maven will create <code>Event.java<\/code>, <code>Venue.java<\/code>, <code>Group.java<\/code>, etc. compatible with Jackson:<\/p>\n<pre class=\"brush:java\">private Event parseEventJson(String jsonStr) {\r\n    try {\r\n        return objectMapper.readValue(jsonStr, Event.class);\r\n    } catch (IOException e) {\r\n        throw new UncheckedIOException(e);\r\n    }\r\n}\r\n<\/pre>\n<p>It just works, sweet:<\/p>\n<pre class=\"brush:java\">final Observable<Event> events = jsonChunks.map(this::parseEventJson);<\/pre>\n<h2>Step 4: ???<sup><a href=\"http:\/\/knowyourmeme.com\/memes\/profit\">[1]<\/a><\/sup><\/h2>\n<h2>Step 5: PROFIT!!!<\/h2>\n<p>Having <code>Observable&lt;Event&gt;<\/code> we can implement some really interesting use cases. Want to find names of all meetups in Poland that were just created? Sure!<\/p>\n<pre class=\"brush:java\">events\r\n        .filter(event -> event.getVenue() != null)\r\n        .filter(event -> event.getVenue().getCountry().equals(\"pl\"))\r\n        .map(Event::getName)\r\n        .forEach(System.out::println);<\/pre>\n<p>Looking for statistics how many events are created per minute? No problem!<\/p>\n<pre class=\"brush:java\">events\r\n        .buffer(1, TimeUnit.MINUTES)\r\n        .map(List::size)\r\n        .forEach(count -> log.info(\"Count: {}\", count));<\/pre>\n<p>Or maybe you want to continually search for meetups furthest in the future, skipping those closer than ones already found?<\/p>\n<pre class=\"brush:java\">events\r\n        .filter(event -> event.getTime() != null)\r\n        .scan(this::laterEventFrom)\r\n        .distinct()\r\n        .map(Event::getTime)\r\n        .map(Instant::ofEpochMilli)\r\n        .forEach(System.out::println);\r\n \r\n\/\/...\r\n \r\nprivate Event laterEventFrom(Event first, Event second) {\r\n    return first.getTime() > second.getTime() ?\r\n            first :\r\n            second;\r\n}<\/pre>\n<p>This code filters out events without known time, emits either current event or the previous one (<code>scan()<\/code>), depending on which one was later, filters out duplicates and displays time. This tiny program running for few minutes already found one just created meetup scheduled for November 2015 &#8211; and it&#8217;s December 2014 as of this writing. Possibilities are endless.<\/p>\n<p>I hope I gave you a good grasp of how you can mashup various technologies together easily: reactive programming to write super fast networking code, type-safe JSON parsing without boiler-plate code and RxJava to quickly process streams of events. Enjoy!<\/p>\n<div class=\"attribution\">\n<table>\n<tbody>\n<tr>\n<td><span class=\"reference\">Reference: <\/span><\/td>\n<td><a href=\"http:\/\/www.nurkiewicz.com\/2014\/12\/accessing-meetups-streaming-api-with.html\">Accessing Meetup&#8217;s streaming API with RxNetty<\/a> from our <a href=\"http:\/\/www.javacodegeeks.com\/jcg\/\">JCG partner<\/a> Tomasz Nurkiewicz at the <a href=\"http:\/\/www.nurkiewicz.com\/\">Java and neighbourhood<\/a> blog.<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>This article will touch upon multiple subjects: reactive programming, HTTP, parsing JSON and integrating with social API. All in one use case: we will load and process new meetup.com events in real time via non-bloking RxNetty library, combining the power of Netty framework and flexibility of RxJava library. Meetup provides publicly available streaming API that &hellip;<\/p>\n","protected":false},"author":13,"featured_media":112,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[8],"tags":[],"class_list":["post-34439","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-enterprise-java"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.5 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Accessing Meetup&#039;s streaming API with RxNetty<\/title>\n<meta name=\"description\" content=\"This article will touch upon multiple subjects: reactive programming, HTTP, parsing JSON and integrating with social API. All in one use case: we will\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.javacodegeeks.com\/2014\/12\/accessing-meetups-streaming-api-with-rxnetty.html\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Accessing Meetup&#039;s streaming API with RxNetty\" \/>\n<meta property=\"og:description\" content=\"This article will touch upon multiple subjects: reactive programming, HTTP, parsing JSON and integrating with social API. All in one use case: we will\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.javacodegeeks.com\/2014\/12\/accessing-meetups-streaming-api-with-rxnetty.html\" \/>\n<meta property=\"og:site_name\" content=\"Java Code Geeks\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/javacodegeeks\" \/>\n<meta property=\"article:published_time\" content=\"2014-12-23T11:00:17+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/enterprise-java-logo.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"150\" \/>\n\t<meta property=\"og:image:height\" content=\"150\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Tomasz Nurkiewicz\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@https:\/\/twitter.com\/tnurkiewicz\" \/>\n<meta name=\"twitter:site\" content=\"@javacodegeeks\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Tomasz Nurkiewicz\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"7 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2014\\\/12\\\/accessing-meetups-streaming-api-with-rxnetty.html#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2014\\\/12\\\/accessing-meetups-streaming-api-with-rxnetty.html\"},\"author\":{\"name\":\"Tomasz Nurkiewicz\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#\\\/schema\\\/person\\\/fb1be85725c10e8361e641fa851e79e1\"},\"headline\":\"Accessing Meetup&#8217;s streaming API with RxNetty\",\"datePublished\":\"2014-12-23T11:00:17+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2014\\\/12\\\/accessing-meetups-streaming-api-with-rxnetty.html\"},\"wordCount\":948,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#organization\"},\"image\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2014\\\/12\\\/accessing-meetups-streaming-api-with-rxnetty.html#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2012\\\/10\\\/enterprise-java-logo.jpg\",\"articleSection\":[\"Enterprise Java\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/www.javacodegeeks.com\\\/2014\\\/12\\\/accessing-meetups-streaming-api-with-rxnetty.html#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2014\\\/12\\\/accessing-meetups-streaming-api-with-rxnetty.html\",\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2014\\\/12\\\/accessing-meetups-streaming-api-with-rxnetty.html\",\"name\":\"Accessing Meetup's streaming API with RxNetty\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2014\\\/12\\\/accessing-meetups-streaming-api-with-rxnetty.html#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2014\\\/12\\\/accessing-meetups-streaming-api-with-rxnetty.html#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2012\\\/10\\\/enterprise-java-logo.jpg\",\"datePublished\":\"2014-12-23T11:00:17+00:00\",\"description\":\"This article will touch upon multiple subjects: reactive programming, HTTP, parsing JSON and integrating with social API. All in one use case: we will\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2014\\\/12\\\/accessing-meetups-streaming-api-with-rxnetty.html#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.javacodegeeks.com\\\/2014\\\/12\\\/accessing-meetups-streaming-api-with-rxnetty.html\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2014\\\/12\\\/accessing-meetups-streaming-api-with-rxnetty.html#primaryimage\",\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2012\\\/10\\\/enterprise-java-logo.jpg\",\"contentUrl\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2012\\\/10\\\/enterprise-java-logo.jpg\",\"width\":150,\"height\":150,\"caption\":\"java-interview-questions-answers\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2014\\\/12\\\/accessing-meetups-streaming-api-with-rxnetty.html#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/www.javacodegeeks.com\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Java\",\"item\":\"https:\\\/\\\/www.javacodegeeks.com\\\/category\\\/java\"},{\"@type\":\"ListItem\",\"position\":3,\"name\":\"Enterprise Java\",\"item\":\"https:\\\/\\\/www.javacodegeeks.com\\\/category\\\/java\\\/enterprise-java\"},{\"@type\":\"ListItem\",\"position\":4,\"name\":\"Accessing Meetup&#8217;s streaming API with RxNetty\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#website\",\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/\",\"name\":\"Java Code Geeks\",\"description\":\"Java Developers Resource Center\",\"publisher\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#organization\"},\"alternateName\":\"JCG\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/www.javacodegeeks.com\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#organization\",\"name\":\"Exelixis Media P.C.\",\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2022\\\/06\\\/exelixis-logo.png\",\"contentUrl\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2022\\\/06\\\/exelixis-logo.png\",\"width\":864,\"height\":246,\"caption\":\"Exelixis Media P.C.\"},\"image\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#\\\/schema\\\/logo\\\/image\\\/\"},\"sameAs\":[\"https:\\\/\\\/www.facebook.com\\\/javacodegeeks\",\"https:\\\/\\\/x.com\\\/javacodegeeks\"]},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#\\\/schema\\\/person\\\/fb1be85725c10e8361e641fa851e79e1\",\"name\":\"Tomasz Nurkiewicz\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/f2a8f9f1060fc7c1161c42f8ba901e0e79fb767dec39ec34b2d3b95cab9dc728?s=96&d=mm&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/f2a8f9f1060fc7c1161c42f8ba901e0e79fb767dec39ec34b2d3b95cab9dc728?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/f2a8f9f1060fc7c1161c42f8ba901e0e79fb767dec39ec34b2d3b95cab9dc728?s=96&d=mm&r=g\",\"caption\":\"Tomasz Nurkiewicz\"},\"description\":\"Java EE developer, Scala enthusiast. Enjoying data analysis and visualization. Strongly believes in the power of testing and automation.\",\"sameAs\":[\"http:\\\/\\\/nurkiewicz.blogspot.com\\\/\",\"https:\\\/\\\/x.com\\\/https:\\\/\\\/twitter.com\\\/tnurkiewicz\"],\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/author\\\/tomasz-nurkiewicz\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Accessing Meetup's streaming API with RxNetty","description":"This article will touch upon multiple subjects: reactive programming, HTTP, parsing JSON and integrating with social API. All in one use case: we will","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.javacodegeeks.com\/2014\/12\/accessing-meetups-streaming-api-with-rxnetty.html","og_locale":"en_US","og_type":"article","og_title":"Accessing Meetup's streaming API with RxNetty","og_description":"This article will touch upon multiple subjects: reactive programming, HTTP, parsing JSON and integrating with social API. All in one use case: we will","og_url":"https:\/\/www.javacodegeeks.com\/2014\/12\/accessing-meetups-streaming-api-with-rxnetty.html","og_site_name":"Java Code Geeks","article_publisher":"https:\/\/www.facebook.com\/javacodegeeks","article_published_time":"2014-12-23T11:00:17+00:00","og_image":[{"width":150,"height":150,"url":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/enterprise-java-logo.jpg","type":"image\/jpeg"}],"author":"Tomasz Nurkiewicz","twitter_card":"summary_large_image","twitter_creator":"@https:\/\/twitter.com\/tnurkiewicz","twitter_site":"@javacodegeeks","twitter_misc":{"Written by":"Tomasz Nurkiewicz","Est. reading time":"7 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.javacodegeeks.com\/2014\/12\/accessing-meetups-streaming-api-with-rxnetty.html#article","isPartOf":{"@id":"https:\/\/www.javacodegeeks.com\/2014\/12\/accessing-meetups-streaming-api-with-rxnetty.html"},"author":{"name":"Tomasz Nurkiewicz","@id":"https:\/\/www.javacodegeeks.com\/#\/schema\/person\/fb1be85725c10e8361e641fa851e79e1"},"headline":"Accessing Meetup&#8217;s streaming API with RxNetty","datePublished":"2014-12-23T11:00:17+00:00","mainEntityOfPage":{"@id":"https:\/\/www.javacodegeeks.com\/2014\/12\/accessing-meetups-streaming-api-with-rxnetty.html"},"wordCount":948,"commentCount":0,"publisher":{"@id":"https:\/\/www.javacodegeeks.com\/#organization"},"image":{"@id":"https:\/\/www.javacodegeeks.com\/2014\/12\/accessing-meetups-streaming-api-with-rxnetty.html#primaryimage"},"thumbnailUrl":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/enterprise-java-logo.jpg","articleSection":["Enterprise Java"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.javacodegeeks.com\/2014\/12\/accessing-meetups-streaming-api-with-rxnetty.html#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.javacodegeeks.com\/2014\/12\/accessing-meetups-streaming-api-with-rxnetty.html","url":"https:\/\/www.javacodegeeks.com\/2014\/12\/accessing-meetups-streaming-api-with-rxnetty.html","name":"Accessing Meetup's streaming API with RxNetty","isPartOf":{"@id":"https:\/\/www.javacodegeeks.com\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.javacodegeeks.com\/2014\/12\/accessing-meetups-streaming-api-with-rxnetty.html#primaryimage"},"image":{"@id":"https:\/\/www.javacodegeeks.com\/2014\/12\/accessing-meetups-streaming-api-with-rxnetty.html#primaryimage"},"thumbnailUrl":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/enterprise-java-logo.jpg","datePublished":"2014-12-23T11:00:17+00:00","description":"This article will touch upon multiple subjects: reactive programming, HTTP, parsing JSON and integrating with social API. All in one use case: we will","breadcrumb":{"@id":"https:\/\/www.javacodegeeks.com\/2014\/12\/accessing-meetups-streaming-api-with-rxnetty.html#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.javacodegeeks.com\/2014\/12\/accessing-meetups-streaming-api-with-rxnetty.html"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.javacodegeeks.com\/2014\/12\/accessing-meetups-streaming-api-with-rxnetty.html#primaryimage","url":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/enterprise-java-logo.jpg","contentUrl":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/enterprise-java-logo.jpg","width":150,"height":150,"caption":"java-interview-questions-answers"},{"@type":"BreadcrumbList","@id":"https:\/\/www.javacodegeeks.com\/2014\/12\/accessing-meetups-streaming-api-with-rxnetty.html#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.javacodegeeks.com\/"},{"@type":"ListItem","position":2,"name":"Java","item":"https:\/\/www.javacodegeeks.com\/category\/java"},{"@type":"ListItem","position":3,"name":"Enterprise Java","item":"https:\/\/www.javacodegeeks.com\/category\/java\/enterprise-java"},{"@type":"ListItem","position":4,"name":"Accessing Meetup&#8217;s streaming API with RxNetty"}]},{"@type":"WebSite","@id":"https:\/\/www.javacodegeeks.com\/#website","url":"https:\/\/www.javacodegeeks.com\/","name":"Java Code Geeks","description":"Java Developers Resource Center","publisher":{"@id":"https:\/\/www.javacodegeeks.com\/#organization"},"alternateName":"JCG","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.javacodegeeks.com\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/www.javacodegeeks.com\/#organization","name":"Exelixis Media P.C.","url":"https:\/\/www.javacodegeeks.com\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.javacodegeeks.com\/#\/schema\/logo\/image\/","url":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2022\/06\/exelixis-logo.png","contentUrl":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2022\/06\/exelixis-logo.png","width":864,"height":246,"caption":"Exelixis Media P.C."},"image":{"@id":"https:\/\/www.javacodegeeks.com\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/javacodegeeks","https:\/\/x.com\/javacodegeeks"]},{"@type":"Person","@id":"https:\/\/www.javacodegeeks.com\/#\/schema\/person\/fb1be85725c10e8361e641fa851e79e1","name":"Tomasz Nurkiewicz","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/f2a8f9f1060fc7c1161c42f8ba901e0e79fb767dec39ec34b2d3b95cab9dc728?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/f2a8f9f1060fc7c1161c42f8ba901e0e79fb767dec39ec34b2d3b95cab9dc728?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/f2a8f9f1060fc7c1161c42f8ba901e0e79fb767dec39ec34b2d3b95cab9dc728?s=96&d=mm&r=g","caption":"Tomasz Nurkiewicz"},"description":"Java EE developer, Scala enthusiast. Enjoying data analysis and visualization. Strongly believes in the power of testing and automation.","sameAs":["http:\/\/nurkiewicz.blogspot.com\/","https:\/\/x.com\/https:\/\/twitter.com\/tnurkiewicz"],"url":"https:\/\/www.javacodegeeks.com\/author\/tomasz-nurkiewicz"}]}},"_links":{"self":[{"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/posts\/34439","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/users\/13"}],"replies":[{"embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/comments?post=34439"}],"version-history":[{"count":0,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/posts\/34439\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/media\/112"}],"wp:attachment":[{"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/media?parent=34439"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/categories?post=34439"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/tags?post=34439"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}