<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Luke Smetham</title>
    <description>The latest articles on DEV Community by Luke Smetham (@lukesmetham).</description>
    <link>https://dev.to/lukesmetham</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F158208%2Fc87fc7ab-6649-4b16-9ab5-14111050a5f5.jpg</url>
      <title>DEV Community: Luke Smetham</title>
      <link>https://dev.to/lukesmetham</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/lukesmetham"/>
    <language>en</language>
    <item>
      <title>Supercharge Feeds with Algolia &amp; GraphQL</title>
      <dc:creator>Luke Smetham</dc:creator>
      <pubDate>Fri, 11 Dec 2020 18:05:24 +0000</pubDate>
      <link>https://dev.to/lukesmetham/supercharge-feeds-with-algolia-graphql-4adb</link>
      <guid>https://dev.to/lukesmetham/supercharge-feeds-with-algolia-graphql-4adb</guid>
      <description>&lt;p&gt;When you're modeling and building an API, storing ID references to other documents to create relationships between types of data within your domain is paramount to efficient querying, scalability, and even your own sanity.&lt;/p&gt;

&lt;p&gt;Imagine you're building the backend for a blog platform and want users to be able to search blog posts by category. So you store the category &lt;code&gt;name&lt;/code&gt; on your posts, and you can query for "all posts with a category field equal to 'Tutorials'." But what if you wanted to eventually change "Tutorials" to "Walkthroughs"? &lt;/p&gt;

&lt;p&gt;You would have to update not only the category data but every post within the category too. If you instead store an ID for the category, the name — or any other property — can change, and the ID will still reference the correct object and keep the relationship alive.&lt;/p&gt;

&lt;p&gt;Most service providers for databases and API-driven SaaS products provide a mechanism to make this easy for developers. &lt;a href="https://getstream.io/activity-feeds/"&gt;Stream Feeds&lt;/a&gt; has enrichment for &lt;a href="https://getstream.io/docs/users_introduction/?language=js"&gt;users&lt;/a&gt; and &lt;a href="https://getstream.io/docs/collections_introduction/?language=js"&gt;collections&lt;/a&gt; in your &lt;a href="https://getstream.io/docs/adding_activities/?language=js"&gt;Activities&lt;/a&gt; and &lt;a href="https://www.mongodb.com/"&gt;MongoDB&lt;/a&gt; allows you to store a ref via an &lt;code&gt;ObjectID&lt;/code&gt; that points to a document in another collection. In both cases you can store a reference to another thing and have it "auto-populate" when you query for the data and the ID you stored is replaced with the full document.&lt;/p&gt;

&lt;p&gt;However, MongoDB cannot auto-populate an ID for anything other than another MongoDB document &lt;em&gt;that is stored in the same database&lt;/em&gt;. You can't reference the ID of a Stream activity and expect it to just show up. At least, not out-of-the-box. The same applies to Stream: We can only enrich data for IDs that reference other "Stream Objects" — like collections or users.&lt;/p&gt;

&lt;p&gt;This is just a fact of life for a developer, and it's not even necessarily a bad thing. Most platforms work this way so they can remain efficient, keep as much control as possible in their customers' hands, and allow you as the developer the flexibility to use whatever combination of tools, services, and APIs you see fit.&lt;/p&gt;

&lt;p&gt;But what if we could do better? What if we could &lt;em&gt;teach&lt;/em&gt; a GraphQL API to understand &lt;em&gt;all&lt;/em&gt; of our data, &lt;strong&gt;regardless of its origin or implementation&lt;/strong&gt;, so that we can enrich data seamlessly and bidirectionally between the tools, services, and APIs that comprise our stack?&lt;/p&gt;

&lt;p&gt;Sounds idealistic right? &lt;/p&gt;

&lt;h3&gt;
  
  
  What We'll Be Building
&lt;/h3&gt;

&lt;p&gt;Funnily enough, building this kind of nested relationship is something that GraphQL is designed to handle. Today, I'm going to walk through a relatively quick and simple example of how you can use Stream Feeds with &lt;code&gt;@stream-io/graphql-feeds&lt;/code&gt; (our new, early-release GraphQL toolset for Stream Feeds) and extend the provided types to produce functionality such as this: &lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;As you can see, there is a new custom field &lt;code&gt;search&lt;/code&gt; — &lt;strong&gt;&lt;em&gt;on the Feed itself&lt;/em&gt;&lt;/strong&gt;  — that will utilize Algolia under the hood, take full advantage of everything Algolia offers for best-in-class search, but will ultimately return &lt;em&gt;actual Stream Activities&lt;/em&gt; rather than a list of search results with references to activities, collection entries, or users.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Disclaimer&lt;/strong&gt;: In this tutorial, I aim only to introduce the concepts of relationships across different services with a GraphQL API as the middleman, and how &lt;code&gt;graphql-feeds&lt;/code&gt; can be leveraged in this way. We are going to gloss over some details such as authentication, which in this case will not be production-ready. In later posts we will expand on this example, add a database to go beyond Stream Collections, implement better authentication, and so much more.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Initial Setup
&lt;/h3&gt;

&lt;p&gt;To get started, rather than step through the linting and babel setup and installing dependencies, I've created a template repository so you can get straight to coding with the same setup I'm using.&lt;/p&gt;

&lt;p&gt;If you have the &lt;a href="https://cli.github.com/"&gt;GitHub CLI&lt;/a&gt; installed (&lt;code&gt;brew install gh&lt;/code&gt;)  you can run the following command:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;blockquote&gt;
&lt;p&gt;If you don't have/want the GH CLI, you can clone the repo as normal, or create your own repo from the template on the GitHub website, and then clone to your local machine from there.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Once you have the repo on your computer, &lt;code&gt;cd&lt;/code&gt; into it and run &lt;code&gt;yarn&lt;/code&gt; (you will also need to run &lt;code&gt;git pull origin main&lt;/code&gt; if you created using the GitHub CLI).&lt;/p&gt;

&lt;p&gt;Lastly, create a &lt;code&gt;.env&lt;/code&gt; file in the root and paste in the following:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;This is everything we need to get up and running! You'll no doubt notice that &lt;code&gt;src/index.js&lt;/code&gt; (our entry point) is an empty file. We'll be getting to this next — but first, let's get that &lt;code&gt;.env&lt;/code&gt; filled out and make sure we have everything set up for Stream and Algolia.&lt;/p&gt;

&lt;h3&gt;
  
  
  Stream
&lt;/h3&gt;

&lt;p&gt;For &lt;a href="https://getstream.io/"&gt;Stream&lt;/a&gt;, this tutorial will be easiest when using a new/empty Feeds App. You can take the things you learned and apply them to your own existing projects later.&lt;/p&gt;

&lt;p&gt;Go to the Stream Dashboard (&lt;a href="https://getstream.io/accounts/signup/"&gt;create an account&lt;/a&gt; if you haven't already) and once you're logged in, click "Create App" in the top right.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--19i-fOQc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://stream-blog-v2.imgix.net/blog/wp-content/uploads/c9c59650ca948c746d489df16d19afc2/Screenshot_2020-12-09_at_12.20.png%3Fauto%3Dcompress%252Cformat%26fit%3Dscale" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--19i-fOQc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://stream-blog-v2.imgix.net/blog/wp-content/uploads/c9c59650ca948c746d489df16d19afc2/Screenshot_2020-12-09_at_12.20.png%3Fauto%3Dcompress%252Cformat%26fit%3Dscale" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then, on the next screen, grab your Stream API Key, Secret, and App ID:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--hZXPFegL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://stream-blog-v2.imgix.net/blog/wp-content/uploads/2659a712a33d7a34d1a9d781c58da6af/Screenshot_2020-12-09_at_12.23.png%3Fauto%3Dcompress%252Cformat%26fit%3Dscale" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--hZXPFegL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://stream-blog-v2.imgix.net/blog/wp-content/uploads/2659a712a33d7a34d1a9d781c58da6af/Screenshot_2020-12-09_at_12.23.png%3Fauto%3Dcompress%252Cformat%26fit%3Dscale" alt="Stream Dashboard"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Add these to the correct spots in the &lt;code&gt;.env&lt;/code&gt; file from above and we're pretty much ready to move over to Algolia! &lt;/p&gt;

&lt;p&gt;We just have one more quick task in the Stream Dashboard: Click the "Add Feed Group" button in the dashboard (visible in the above screenshot) and create a new Flat feed group called "posts".&lt;/p&gt;

&lt;h3&gt;
  
  
  Algolia
&lt;/h3&gt;

&lt;p&gt;Next, you'll need an &lt;a href="https://algolia.com"&gt;Algolia account&lt;/a&gt;. You can set up a free trial on their website and spin up an Algolia application in just a few seconds.&lt;/p&gt;

&lt;p&gt;Once set up, you will be presented with the Algolia dashboard and a drawer on the right side with instructions to set up your search indexes etc. Click "Create Index" and enter &lt;code&gt;POSTS&lt;/code&gt; for the name.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--cocu5sLB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://stream-blog-v2.imgix.net/blog/wp-content/uploads/8e6a8023fd47c024d9e074bf09ad9a4e/image_3.png%3Fauto%3Dcompress%252Cformat%26fit%3Dscale" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--cocu5sLB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://stream-blog-v2.imgix.net/blog/wp-content/uploads/8e6a8023fd47c024d9e074bf09ad9a4e/image_3.png%3Fauto%3Dcompress%252Cformat%26fit%3Dscale" alt="Creating an Algolia Index"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After clicking "Create", you will be redirected to the "index" screen. &lt;/p&gt;

&lt;p&gt;Algolia is now ready to integrate into our API; however, we'll take this opportunity to add some facets to our index so we don't have to come back here later on.&lt;/p&gt;

&lt;p&gt;First, click "Configuration" in the tabbed toolbar at the top of the index management screen, and choose "facets" from the sidebar menu on the left beneath "Filters and Faceting".&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--94Q6-Pnr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://stream-blog-v2.imgix.net/blog/wp-content/uploads/7e07637f305c1404f5a98d18a8cef3be/image_4.png%3Fauto%3Dcompress%252Cformat%26fit%3Dscale%26h%3D1216%26ixlib%3Dphp-3.3.0%26w%3D1536%26wpsize%3D1536x1536" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--94Q6-Pnr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://stream-blog-v2.imgix.net/blog/wp-content/uploads/7e07637f305c1404f5a98d18a8cef3be/image_4.png%3Fauto%3Dcompress%252Cformat%26fit%3Dscale%26h%3D1216%26ixlib%3Dphp-3.3.0%26w%3D1536%26wpsize%3D1536x1536" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We will add a new facet for the following fields &lt;code&gt;feedID&lt;/code&gt; &lt;code&gt;userID&lt;/code&gt; and &lt;code&gt;feedSlug&lt;/code&gt;. This data does not exist yet in your Algolia index, so you will see the following warning below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--qN-TIGiT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://stream-blog-v2.imgix.net/blog/wp-content/uploads/e022cbcf2d4271c4a5405e92ec06b0d1/Screenshot_2020-12-09_at_12.51.47.png%3Fauto%3Dcompress%252Cformat%26fit%3Dscale%26h%3D258%26ixlib%3Dphp-3.3.0%26w%3D1536%26wpsize%3D1536x1536" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--qN-TIGiT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://stream-blog-v2.imgix.net/blog/wp-content/uploads/e022cbcf2d4271c4a5405e92ec06b0d1/Screenshot_2020-12-09_at_12.51.47.png%3Fauto%3Dcompress%252Cformat%26fit%3Dscale%26h%3D258%26ixlib%3Dphp-3.3.0%26w%3D1536%26wpsize%3D1536x1536" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This can be safely ignored as we will be adding objects containing these fields very shortly.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now, make sure all of the facets are set to "filter only" by selecting it from the dropdown for each list item, and once done, click "Review and Save Settings".&lt;/p&gt;

&lt;p&gt;Lastly, we need to get our &lt;strong&gt;Algolia Admin Key&lt;/strong&gt; and &lt;strong&gt;App ID&lt;/strong&gt; from the "API Keys" page and add them to our &lt;code&gt;.env&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--QUYblZJu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://stream-blog-v2.imgix.net/blog/wp-content/uploads/198103c247ce35a48dbdb85e63e6b096/image_5.png%3Fauto%3Dcompress%252Cformat%26fit%3Dscale%26h%3D1216%26ixlib%3Dphp-3.3.0%26w%3D1536%26wpsize%3D1536x1536" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--QUYblZJu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://stream-blog-v2.imgix.net/blog/wp-content/uploads/198103c247ce35a48dbdb85e63e6b096/image_5.png%3Fauto%3Dcompress%252Cformat%26fit%3Dscale%26h%3D1216%26ixlib%3Dphp-3.3.0%26w%3D1536%26wpsize%3D1536x1536" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now we can finally start to write some code! 🤓&lt;/p&gt;

&lt;h3&gt;
  
  
  Initialize the API
&lt;/h3&gt;

&lt;p&gt;Now that we have everything set up for our environment, we can start to implement &lt;code&gt;apollo-server&lt;/code&gt;. The concepts from here on out apply to pretty much all JS GraphQL server libraries, and if you're using something like &lt;code&gt;apollo-server-express&lt;/code&gt;, the setup will be pretty much identical. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Disclaimer&lt;/strong&gt;: We will not be implementing authentication in this example and instead just passing the Stream token along as a means of identifying the user. In subsequent articles, we will learn to stitch in MongoDB and create custom authentication and user management.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Let's create a new file, inside of a new directory, in the &lt;code&gt;src&lt;/code&gt; folder:  &lt;code&gt;src/schema/index.js&lt;/code&gt;&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Now, back in our empty &lt;code&gt;src/index.js&lt;/code&gt; we can add the following: &lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;In future posts, we'll likely swap this out and implement &lt;code&gt;apollo-server-express&lt;/code&gt; to give us extra capabilities — but this will serve us well for the purpose of this tutorial!&lt;/p&gt;

&lt;p&gt;All we do here is import the &lt;code&gt;schema&lt;/code&gt; and &lt;code&gt;dataSources&lt;/code&gt; that we exported from &lt;code&gt;schema/index&lt;/code&gt; and pass them to a new &lt;code&gt;ApolloServer&lt;/code&gt; instance. At this point, you can run &lt;code&gt;yarn dev&lt;/code&gt; and the GraphQL Playground should open up on &lt;a href="http://localhost:4000"&gt;localhost:4000&lt;/a&gt; and you will see the feeds schema in the "Docs" tab — but we still need a couple more things for everything to &lt;em&gt;actually work&lt;/em&gt; when you call one of the resolvers.&lt;/p&gt;

&lt;h3&gt;
  
  
  Context and Authentication
&lt;/h3&gt;

&lt;p&gt;Every resolver in GraphQL receives the following arguments: &lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Context in GraphQL is most commonly used to authenticate a request and pass along the user object or ID to be utilized in your resolvers. &lt;/p&gt;

&lt;p&gt;One common example of this is when GraphQL APIs often have a &lt;code&gt;me&lt;/code&gt; query that returns profile data for the user performing the query. This is usually achieved by verifying the &lt;code&gt;Authorization&lt;/code&gt; header in the &lt;code&gt;req&lt;/code&gt; and adding an ID or user object to the context. The user is then available in all of your resolvers, so you can make resolvers that are "scoped" to the authenticated user.&lt;/p&gt;

&lt;p&gt;This leads to an important point with GraphQL Stream, and although it's a little outside the scope of this article, it's worth mentioning, even if only briefly. When using Stream in this way, you need to implement authentication yourself because the server client is, by nature, allowed to make authenticated admin requests due to the use of your API secret.&lt;/p&gt;

&lt;p&gt;I will cover this in more detail with the Mongo and Auth examples as it will be implemented slightly differently from the context we create today. But, with the setup we have in this tutorial, there are two ways to handle this that I can quickly explain: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Verify the token yourself with &lt;code&gt;jsonwebtoken&lt;/code&gt; and the Stream secret environment variable as the signature. Then you can use the JWT payload along with anything else in your context to perform auth checks, fetch user data, etc.&lt;/li&gt;
&lt;li&gt;If the Stream token is in the &lt;code&gt;req&lt;/code&gt; headers, override the secret when creating the "Stream Context". This will make GraphQL Stream work like the client-side SDK, where users can only request their own data.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For this tutorial, we'll be keeping this pretty light and focusing on relationships between Stream and Algolia rather than authorization. However, we will be using an implementation similar to option 1 above to scope requests to the user. We just won't be performing any auth checks explicitly beyond "is there a valid Stream token in the request headers".&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;So, what is the Stream Context?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The "Stream Context" mentioned above refers to a helper method exported from the feeds schema that will add both the Feeds Client, and a GQL Subscriptions Helper for realtime feeds to the context object.&lt;/p&gt;

&lt;p&gt;Let's create a new file &lt;code&gt;src/schema&lt;/code&gt; called &lt;code&gt;context.js&lt;/code&gt; and add the following code:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;To quickly explain what's going on here: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The context function gets called on every request, and receives an object containing either &lt;code&gt;req&lt;/code&gt; or &lt;code&gt;connection&lt;/code&gt; depending on whether the transport is &lt;code&gt;http(s)://&lt;/code&gt; or &lt;code&gt;ws(s)://&lt;/code&gt; respectively.&lt;/li&gt;
&lt;li&gt;We then grab the Bearer Token from the &lt;code&gt;Authorization&lt;/code&gt; header (this will be a Stream User token in this case) and if it exists, verify the JWT with our secret.&lt;/li&gt;
&lt;li&gt;The resulting payload is then stored as &lt;code&gt;context.auth&lt;/code&gt;, and therefore made available to all of our resolvers from here on out. (We could, for example, check whether this exists and throw an error if not for resolvers we want to protect.)&lt;/li&gt;
&lt;li&gt;Finally we call &lt;code&gt;createFeedsContext&lt;/code&gt; from &lt;code&gt;@stream-io/graphql-feeds&lt;/code&gt; and pass our credentials from &lt;code&gt;process.env&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Last but not least, let's go back to &lt;code&gt;index.js&lt;/code&gt;, import our context creation method, and pass it to &lt;code&gt;ApolloServer&lt;/code&gt;.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Just like that, we're ready to start writing resolvers, and we're discovering the power and flexibility of Stream Feeds combined with GraphQL.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Before we continue:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Let's do a super quick recap into what our resolver context now looks like and why:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;As you can see above, we now have the payload from our JWT containing the ID of the authenticated user, dataSources with a &lt;code&gt;search&lt;/code&gt; property with key/value referecences to our Algolia indexes (just &lt;code&gt;search.posts&lt;/code&gt; in our case), and finally, the Stream context including an initialized Stream Feeds server client.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Ultimate Feeds Setup
&lt;/h3&gt;

&lt;p&gt;Okay,  so that claim might be a little rich, but I firmly believe this is the easiest, fastest way to get set up with &lt;a href="https://getstream.io/activity-feeds"&gt;Stream Feeds&lt;/a&gt; — especially as a beginner or feeds newbie — and start poking around. &lt;/p&gt;

&lt;p&gt;You can totally ignore the authentication part and only include the Stream context to have an unrestricted GraphQL playground where you can test how data moves around in your Stream Feeds application before you even think about writing any code — not to mention the frontend.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--aPTSBj4O--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://stream-blog-v2.imgix.net/blog/wp-content/uploads/6109faf69a289fb4b140799d63bc2fc5/Screenshot-2020-12-11-at-19.37.40.png%3Fauto%3Dcompress%252Cformat%26ixlib%3Dphp-3.3.0" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--aPTSBj4O--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://stream-blog-v2.imgix.net/blog/wp-content/uploads/6109faf69a289fb4b140799d63bc2fc5/Screenshot-2020-12-11-at-19.37.40.png%3Fauto%3Dcompress%252Cformat%26ixlib%3Dphp-3.3.0" alt="GraphQL Playground"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Check the &lt;a href="https://www.npmjs.com/package/@stream-io/graphql-feeds"&gt;@stream-io/graphql-feeds&lt;/a&gt; README for quick examples for getting started with apollo-server and apollo-server-express with subscriptions and more.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I digress, but beyond the benefits of creating your own Stream Feeds sandbox to play around in, the real silver bullet lies with the ability to "teach" our datasources how to understand each other and return data in one unified object.&lt;/p&gt;

&lt;p&gt;Back in our &lt;code&gt;src/schema/index.js&lt;/code&gt;, let's start by amending the code slightly to utilize "schema stitching".&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;As you can see, we have imported &lt;code&gt;stitchSchemas&lt;/code&gt; from &lt;code&gt;@graphql-tools/stitch&lt;/code&gt; and added our feeds schema as a "subschema". &lt;/p&gt;

&lt;p&gt;When you save and the playground refreshes, there will be no change in functionality and everything will work exactly as before. So what happened? 👀&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Schema stitching (@graphql-tools/stitch) creates a single GraphQL gateway schema from multiple underlying GraphQL services. Unlike schema merging, which simply consolidates local schema instances, stitching builds a combined proxy layer that delegates requests through to many underlying service APIs. &lt;a href="https://www.graphql-tools.com/docs/schema-stitching/"&gt;graphql-tools&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;As defined above by &lt;a href="https://www.graphql-tools.com/"&gt;graphql-tools&lt;/a&gt;, stitching is almost definitely overkill for our use case in the scope of this tutorial. Merging can be more appropriate depending on your setup or where the schema is kept, but we can go into more detail on this in a later post.&lt;/p&gt;

&lt;p&gt;However, implementing stitching now allows us to set ourselves up on the right foot for stitching in additional services in later articles (like Mongo, S3 etc.), and helps to illustrate another really awesome thing about GraphQL: Technically, the feeds schema (or your own extended and customized instance of the feed schema) could live on a totally different server somewhere else as a "microservice" of sorts, and you can still stitch it in and access it in the exact same way.&lt;/p&gt;

&lt;p&gt;See the above &lt;code&gt;graphql-tools&lt;/code&gt; links for more information on exactly how this works with remote schemas. But don't go anywhere just yet — it's about to get good. 😉&lt;/p&gt;

&lt;p&gt;We now need to create two new files in our &lt;code&gt;schema&lt;/code&gt; directory, one to define our custom type definitions, and one to teach GraphQL how to resolve them from our data.&lt;/p&gt;

&lt;p&gt;First, let's create &lt;code&gt;src/schema/typeDefs.js&lt;/code&gt; and add this:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;In the above snippet, we are writing a GraphQL SDL (Schema Definition Language) string that tells Apollo that we want to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add a type called &lt;code&gt;Post&lt;/code&gt;

&lt;ul&gt;
&lt;li&gt;Essentially the "model" for our Stream Collections entries&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Add an input type called &lt;code&gt;CreatePostInput&lt;/code&gt;

&lt;ul&gt;
&lt;li&gt;An input type can be used to define the shape of non-scalar argument for a Query, Mutation or Subscription (this is like defining the "model" for what the arguments of your resolvers will look like if the are not a scalar type).&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Then we extend the &lt;code&gt;StreamUser&lt;/code&gt; type from &lt;code&gt;@stream-io/graphql-feeds&lt;/code&gt; because our users will have names.

&lt;ul&gt;
&lt;li&gt;The base &lt;code&gt;StreamUser&lt;/code&gt; type has two properties

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;id&lt;/code&gt; - to uniquely identify this user.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;token&lt;/code&gt; - to optionally request the the token for this user (if auth allows it)&lt;/li&gt;
&lt;li&gt;This is intentionally bare-bones so you can extend the type to suit your domain. If you want the &lt;code&gt;name&lt;/code&gt; property to be an &lt;code&gt;Int&lt;/code&gt; for some reason, go for it!&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Finally, we tell Apollo that there will be a &lt;code&gt;createPost&lt;/code&gt; resolver of type &lt;code&gt;Mutation&lt;/code&gt; that returns the newly created Activity.

&lt;ul&gt;
&lt;li&gt;If you're new to GQL, in simplified terms: &lt;code&gt;Query&lt;/code&gt; is akin to &lt;code&gt;GET&lt;/code&gt;  operations in REST, whereas &lt;code&gt;Mutation&lt;/code&gt; is like a catch-all for &lt;code&gt;POST&lt;/code&gt; &lt;code&gt;PUT&lt;/code&gt; and &lt;code&gt;DELETE&lt;/code&gt; operations.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At this point, you can go back into your &lt;code&gt;src/schema/index.js&lt;/code&gt; file and amend it to import your typeDefs and pass them to the gateway schema created by &lt;code&gt;stitchSchemas&lt;/code&gt;.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Going back to the playground, you should see our new types in the "Docs" and "Schema" tabs. Try searching "Docs" for &lt;code&gt;StreamUser&lt;/code&gt; or &lt;code&gt;createPost&lt;/code&gt;!&lt;/p&gt;

&lt;p&gt;However, attempting to run &lt;code&gt;createPost&lt;/code&gt; right now will fail. We have told Apollo that there will be a resolver called &lt;code&gt;createPost&lt;/code&gt; but it still has no way of actually running this Mutation. We also added a new field to the &lt;code&gt;StreamUser&lt;/code&gt; type — but how do we make all this &lt;em&gt;actually work&lt;/em&gt;?&lt;/p&gt;

&lt;p&gt;Back in &lt;code&gt;src/schema&lt;/code&gt; let's create a new file as a sibling to &lt;code&gt;typeDefs&lt;/code&gt; called &lt;code&gt;resolvers.js&lt;/code&gt; and start out by creating the &lt;code&gt;createPost&lt;/code&gt; resolver:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Technically with &lt;code&gt;graphql-feeds&lt;/code&gt; you can just use the provided &lt;code&gt;addActivity&lt;/code&gt;  mutation, but to add custom behavior like saving to Algolia, we can use the above approach to wrap our own custom functionality around the original resolver. &lt;/p&gt;

&lt;p&gt;Libraries like &lt;code&gt;graphql-compose&lt;/code&gt; have helpers such as &lt;code&gt;withMiddlewares&lt;/code&gt; to achieve a similar effect. &lt;/p&gt;

&lt;p&gt;To break it down:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We first destructure some keys from our context for later on, and check if there is a &lt;code&gt;user_id&lt;/code&gt; in our &lt;code&gt;auth&lt;/code&gt; payload that came from the JWT.&lt;/li&gt;
&lt;li&gt;Next, we take our &lt;code&gt;args.data&lt;/code&gt; (which is of type &lt;code&gt;CreatePostInput&lt;/code&gt;) and use the feeds client in context to create a collection entry.&lt;/li&gt;
&lt;li&gt;We then take the returned data, and use the &lt;code&gt;id&lt;/code&gt; from the payload to reference the post entry in our activity.&lt;/li&gt;
&lt;li&gt;Then we create the activity by using &lt;code&gt;delegateToSchema&lt;/code&gt; to call our stitched feeds schema and pass off the task of creating the activity, but instead of passing the args along as-is, we construct the feedId ourselves with String Interpolation and the &lt;code&gt;user_id&lt;/code&gt; from our auth context.&lt;/li&gt;
&lt;li&gt;Finally we add some data to our Algolia index about the activity, and return the &lt;code&gt;Activity&lt;/code&gt;  object we got back from the &lt;code&gt;delegateToSchema&lt;/code&gt; call.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With this in place, we can import our &lt;code&gt;schema/resolvers.js&lt;/code&gt; file into our schema in the same way we did the &lt;code&gt;typeDefs&lt;/code&gt;:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Opening up the playground, you can now run &lt;code&gt;createPost&lt;/code&gt; and your new &lt;code&gt;Post&lt;/code&gt; will be added to a Stream Collection, referenced in an activity on a feed, and then added to our Algolia index for later too. &lt;/p&gt;

&lt;p&gt;Before that, let's quickly create a user and get a token so everything works as expected:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;This will create a new StreamFeeds user, with the name &lt;code&gt;Luke&lt;/code&gt; and id &lt;code&gt;luke&lt;/code&gt; (change these to whatever you like), and we are requesting that the mutation return us the token for this user if successful.&lt;/p&gt;

&lt;p&gt;Now copy the token, and in the bottom left of the playground, open up &lt;code&gt;HTTP Headers&lt;/code&gt; and add the following:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;And finally, the moment of truth: Create a new tab in the playground and run this mutation:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Assuming it succeeded, you just created a post, an activity, and added it to the Algolia index! 🎉&lt;/p&gt;

&lt;p&gt;You can verify that this worked by going into Algolia and viewing the index. You should see the newly created object that represents your post.&lt;/p&gt;

&lt;p&gt;We're nearly there! This is a fairly long post, but hopefully, you're still with us 😛&lt;/p&gt;

&lt;p&gt;At this point, you can add activities to your heart's content — and I recommend you do! Add varying strings in the text so that the search results are varied once we implement the remaining resolvers.&lt;/p&gt;

&lt;p&gt;You can also run the &lt;code&gt;flatFeed&lt;/code&gt; query to view your activities in a regular Stream Feed (remember to switch the &lt;code&gt;id&lt;/code&gt; argument to include the user id you just created):&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;You will see the results in the exact shape we request above, for each activity in the feed!&lt;/p&gt;

&lt;h3&gt;
  
  
  Searching with Algolia
&lt;/h3&gt;

&lt;p&gt;Now all that's left is to implement a resolver that can call Algolia, but before returning the response to the playground, it will revisit our typeDefs and resolve any custom fields we have in there. This is the magic of relational data in GraphQL.&lt;/p&gt;

&lt;p&gt;For this to work, we need to create a type for the response we get from Algolia. Open up &lt;code&gt;src/schema/typeDefs&lt;/code&gt; and somewhere within the type defs string add this:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;If you have used Algolia before you will recognize this shape, except for one crucial difference.&lt;/p&gt;

&lt;p&gt;We tell Apollo that &lt;code&gt;hits&lt;/code&gt; will return an array of &lt;code&gt;StreamActivities&lt;/code&gt; rather than the usual array of objects from Algolia that match your query. So if we were to call a resolver that returned a &lt;code&gt;SearchResponse&lt;/code&gt; right now, it would fail because &lt;code&gt;hits&lt;/code&gt; wouldn't match the expected response in the schema. &lt;/p&gt;

&lt;p&gt;This is great for utilizing Algolia more efficiently without worrying about storing data that is only there to display in the UI, i.e. the Title of an article. Algolia has a limit on the size of objects, just like Stream has a limit on Activity size. So with this solution, you only need to store an ID to create the relationship within GraphQL, and enough data to perform the queries and faceting you want. &lt;/p&gt;

&lt;p&gt;However, if we create a resolver for this field in our resolvers object, we can tell Apollo to do something different with specific fields. This is where the first argument of all resolvers, &lt;code&gt;source&lt;/code&gt;, becomes useful.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;source&lt;/code&gt; object will always be the original, untouched response — in this case, from Algolia. So with that in mind, let's go back to our &lt;code&gt;schema/resolvers&lt;/code&gt; file and add the following property to the resolvers object. (Should be in the "root" of the object, not nested beneath Mutation, or any other type.)&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Query, Mutation and Subscription are just types, known as Root types. When you create a new type, e.g. StreamActivity, it is also a root type. So to define how GraphQL should resolve its fields, you can add a StreamActivity property to the resolvers object just like we did for Mutation.&lt;/p&gt;
&lt;/blockquote&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Now Apollo knows that instead of giving you the &lt;code&gt;hits&lt;/code&gt; directly from Algolia, it should flatten the results into a list of IDs, and pass these along to the &lt;code&gt;getActivites&lt;/code&gt; method from Stream which returns activities in batch by their IDs.&lt;/p&gt;

&lt;p&gt;Finally, add the following to &lt;code&gt;resolvers.js&lt;/code&gt; and &lt;code&gt;typeDefs.js&lt;/code&gt; respectively:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;blockquote&gt;
&lt;p&gt;Adds the query resolver we can use to search activities. We only ask for the &lt;code&gt;objectID&lt;/code&gt; from Algolia as it is all we need to get the activities. (Algolia has already taken care of the search.)&lt;/p&gt;
&lt;/blockquote&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;With that, you can run the following query and return &lt;em&gt;actual&lt;/em&gt; Stream Activities, but using Algolia as the search engine.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h3&gt;
  
  
  Bonus
&lt;/h3&gt;

&lt;p&gt;From here the possibilities are endless, especially when you consider that Algolia or Stream in this instance could be any SaaS service, database, library etc that you choose. But things are still somewhat "separate" within the schema.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;searchPosts&lt;/code&gt; query will return all posts in your Stream app regardless of user, and it's a standalone resolver. However, what if we wanted to search just one feed? At this point it should be relatively straightforward to add a new argument to &lt;code&gt;searchPosts&lt;/code&gt; that accepts a valid &lt;code&gt;facet&lt;/code&gt; or &lt;code&gt;filter&lt;/code&gt; string for Algolia. This would be great addition, but we can do better. 😏&lt;/p&gt;

&lt;p&gt;Open your &lt;code&gt;typeDefs&lt;/code&gt; again and add the following extension to the &lt;code&gt;StreamFlatFeed&lt;/code&gt; type:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Here we add a new field to the &lt;code&gt;StreamFlatFeed&lt;/code&gt; type. This is exactly what we did with the &lt;code&gt;hits&lt;/code&gt; field for &lt;code&gt;SearchResponse&lt;/code&gt;. The difference is that there is no &lt;code&gt;search&lt;/code&gt; key in the source object for a feed. There is, however, an &lt;code&gt;id&lt;/code&gt; for the feed.&lt;/p&gt;

&lt;p&gt;Back in &lt;code&gt;resolvers.js&lt;/code&gt;, let's teach Apollo how to resolve the search field:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;This is slightly repetitive, and realistically, we could store this resolver method elsewhere and utilize the same function for &lt;code&gt;searchPosts&lt;/code&gt; and this &lt;code&gt;StreamFlatFeed.search&lt;/code&gt;. But in essence, we call Algolia again from our &lt;code&gt;dataSources&lt;/code&gt;, this time passing a &lt;code&gt;filters&lt;/code&gt; argument to the  &lt;code&gt;options&lt;/code&gt; object that will scope all results of the search to the "parent" feed that we are requesting.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;And by running the above query in the playground, you can see that your &lt;code&gt;StreamFlatFeed&lt;/code&gt; now has a nested property for searching its own activities! 🎉 &lt;/p&gt;

&lt;p&gt;The best part is that if you don't request it, Algolia will never get called! The resolver will only run if it has been asked to run.&lt;/p&gt;

&lt;h3&gt;
  
  
  Extra Footnotes
&lt;/h3&gt;

&lt;p&gt;One topic area I didn't cover in this article is the &lt;code&gt;object&lt;/code&gt; field, enrichment, and some of the quirks of enriching the &lt;code&gt;object&lt;/code&gt; and &lt;code&gt;actor&lt;/code&gt; fields either with Stream's own enrichment, or via a GraphQL field like we have discussed today. I strongly recommend reading this next section if you plan on playing around with GraphQL feeds — but feel free to skip it for now. There is more information on all of these concepts in the README when you're ready.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;actor&lt;/code&gt; and &lt;code&gt;object&lt;/code&gt; fields in a Stream Activity are versatile. This is excellent when using Stream in any other setting, but when actually creating the schema we can't define &lt;code&gt;actor&lt;/code&gt; or &lt;code&gt;object&lt;/code&gt; as a definite type. Ultimately, it's up to you what those fields look like.&lt;/p&gt;

&lt;p&gt;More often that not, these will be IDs referencing documents stored elsewhere — like in MongoDB — with which we can utilize the methods above to, in the case of &lt;code&gt;actor&lt;/code&gt;, for example, add a new field &lt;code&gt;actorData&lt;/code&gt;, and define a resolver for this field that takes the &lt;code&gt;[source.actor](http://source.actor)&lt;/code&gt; value and uses it to resolve the full object from Mongo etc.&lt;/p&gt;

&lt;p&gt;However, we also offer "Collections" with Stream Feeds, which can be utilized to store larger objects (like user profile data) that you can later reference in activities (like our &lt;code&gt;posts&lt;/code&gt;). If you &lt;em&gt;are&lt;/em&gt; using collections, it makes a lot of sense to pass the &lt;code&gt;enrich&lt;/code&gt; flag when you request activities and have the data automatically appear in the feed without extra boilerplate or extra network requests.&lt;/p&gt;

&lt;p&gt;Because of this, the &lt;code&gt;actor&lt;/code&gt; and &lt;code&gt;object&lt;/code&gt; fields are of type &lt;code&gt;JSON&lt;/code&gt; in the schema, which allows them to be objects, arrays but also a String. This provides perfect flexibility but also means these fields are always JSON (JSON is a Scalar with no subfields) as they inherit from a shared Interface. &lt;/p&gt;

&lt;p&gt;So, we can't override with a new type that graphql can then resolve, and we can't define nested relationships for fields within the object or actor should they be embedded objects. (Technically we could override it via something like &lt;code&gt;graphl-compose&lt;/code&gt; but depending on your setup this can cumbersome for the sake of one field. It should be easy to use this schema however you want, regardless of you GraphQL client or Node stack.)&lt;/p&gt;

&lt;p&gt;This may change down the line as this library matures, but right now the recommended approach if you use Streams enrichment is as follows (assuming the user has an identical shape to that used in this post):&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;and in your resolvers you can define the resolver for the &lt;code&gt;actorData&lt;/code&gt; field like so:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Assuming you called the feed like the below query (with the enrich option), you would now be able to access a typed version of the actors profile data that you can go on to extend and add more nested fields too if you feel necessary.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h3&gt;
  
  
  We're Outta Here!
&lt;/h3&gt;

&lt;p&gt;That's all, folks! There is a lot to go over here so thank you if you made it this far down the post! Hopefully, you learned a little about GraphQL — or at least how &lt;a href="https://getstream.io/"&gt;Stream&lt;/a&gt; can now start to be implemented in your GraphQL APIs. Also a massive thank you to our friends at &lt;a href="https://algolia.com/"&gt;Algolia&lt;/a&gt; for a consistently amazing product.&lt;/p&gt;

&lt;p&gt;You can also check out the finished code for this tutorial &lt;a href="https://github.com/GetStream/feed-search-tutorial"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://www.npmjs.com/package/@stream-io/graphql-feeds"&gt;@stream-io/graphql-feeds&lt;/a&gt; library is still very young and very much a work in progress, but expect more posts very soon, where we can expand further on what's possible with Feeds and GraphQL.&lt;/p&gt;

</description>
      <category>stream</category>
      <category>graphql</category>
      <category>apollo</category>
      <category>algolia</category>
    </item>
    <item>
      <title>Android &amp; iOS Push Notifications with Stream Chat and React Native</title>
      <dc:creator>Luke Smetham</dc:creator>
      <pubDate>Mon, 22 Apr 2019 15:46:36 +0000</pubDate>
      <link>https://dev.to/lukesmetham/android-ios-push-notifications-with-stream-chat-and-react-native-3n0a</link>
      <guid>https://dev.to/lukesmetham/android-ios-push-notifications-with-stream-chat-and-react-native-3n0a</guid>
      <description>&lt;h1&gt;
  
  
  &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--tvUlMkJl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/mv8erg9ajm7qmwt0drji.png" alt=""&gt;
&lt;/h1&gt;

&lt;h1&gt;
  
  
  Android &amp;amp; iOS Push Notifications with Stream Chat and React Native
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://getstream.io/chat"&gt;Stream Chat&lt;/a&gt;  allows you to add push notifications to your React Native application very easily. In this tutorial, we will show you how to create a sample React Native application from scratch with native push notifications that work both on Android and iOS devices.&lt;/p&gt;

&lt;p&gt;Note:&lt;em&gt;This tutorial is not supported in Expo applications. We need access to the native code to get the device tokens required to send push notifications for Stream Chat. If you are hoping to integrate this into an existing Expo application, you will need to eject.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;If you would like to see the code for this tutorial - or even clone and follow along yourself, you can find it in this repo:&lt;/em&gt; &lt;a href="https://github.com/GetStream/react-native-chat-example-push"&gt;https://github.com/GetStream/react-native-chat-example-push&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;First things first, make sure you've created an account with Stream and created an app within the dashboard. &lt;/p&gt;

&lt;p&gt;To make things easier, we are going to disable auth so that we can easily test push messages. Please note that this only suitable for test/dev environments. While in development mode, you can go to the Chat tab in the dashboard for your app, scroll down to Chat Events and enable the toggle for Disable Auth Checks. This means we don't need to send a valid user token - usually, we need to generate a valid user token from a server); You can find more details on generating a valid token for a production application using Stream here.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--obt23Vre--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.imgur.com/mimIWRC.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--obt23Vre--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.imgur.com/mimIWRC.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once you’re all set up, make sure you have your API key and secret in a safe spot for use later on this tutorial. &lt;/p&gt;

&lt;p&gt;Next, initialize your new project with the react-native init chat-push-example command in your terminal. You can rename chat-push-example to whatever you would like.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: if you are adding this to an existing React Native project created with Expo or CRNA, you will need to eject. Please note that ejecting is irreversible; however, it is required to access native iOS and Android capabilities._ &lt;a href="https://github.com/react-community/create-react-native-app/blob/master/EJECTING.md"&gt;eject&lt;/a&gt; &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We’ll start by installing all the dependencies we need:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;$ yarn add stream-chat react-native-push-notifications react-native link react-native-push-notifications&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  iOS Setup
&lt;/h2&gt;

&lt;p&gt;For iOS, we will be using Apple’s APN service to power the push functionality, rather than Expo or Firebase Cloud Messaging.&lt;/p&gt;

&lt;p&gt;You also need to link  &lt;a href="https://facebook.github.io/react-native/docs/pushnotificationios"&gt;PushNotificationIOS&lt;/a&gt; which is exported from React Native. Open Xcode and in the sidebar on the left, make sure you’re in the Project Navigator tab (the folder icon). Right click on the Libraries directory within your project name and select &lt;code&gt;Add files to &amp;lt;Project_Name_Here&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--64CHukxV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.imgur.com/Ql0eSjl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--64CHukxV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.imgur.com/Ql0eSjl.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A file dialog will pop-up. Navigate to the root of your project, then to your &lt;code&gt;node_modules&lt;/code&gt; directory and to the path as shown below. Click Add.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;./node_modules/react-native/Libraries/PushNotificationsIOS/RCTPushNotification.xcodeproj&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--SgTQsIIN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.imgur.com/JSc3LB2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SgTQsIIN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.imgur.com/JSc3LB2.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, click the root of your applications Xcode project in the navigator sidebar and click Build Phases in the tabs at the top of the middle pane. On the next screen, there are five dropdowns. Find the dropdown labeled Link Binaries with Libraries, expand it, and click the plus icon in the bottom left. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Fg0E7cM6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.imgur.com/O2kKmry.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Fg0E7cM6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.imgur.com/O2kKmry.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then, focus on the search box and type &lt;code&gt;RCTPushNotification&lt;/code&gt;. You should see a file named &lt;code&gt;libRCTPushNotification.a&lt;/code&gt; in the list. Select it and click Add.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ln-NJZW9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.imgur.com/7faenYo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ln-NJZW9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.imgur.com/7faenYo.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Last, add the following snippet to the bottom of your &lt;code&gt;AppDelegate.m&lt;/code&gt; file which can be found here: &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--XWL6N3aw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.imgur.com/YOzyzCP.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--XWL6N3aw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.imgur.com/YOzyzCP.png" alt=""&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Required to register for notifications

 - (void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings

 {

  [RCTPushNotificationManager didRegisterUserNotificationSettings:notificationSettings];

 }

 // Required for the register event.

 - (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken

 {

  [RCTPushNotificationManager didRegisterForRemoteNotificationsWithDeviceToken:deviceToken];

 }

 // Required for the notification event. You must call the completion handler after handling the remote notification.

 - (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo

fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {

    [RCTPushNotificationManager didReceiveRemoteNotification:userInfo fetchCompletionHandler:completionHandler];

 }

 // Required for the registrationError event.

 - (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error

 {

  [RCTPushNotificationManager didFailToRegisterForRemoteNotificationsWithError:error];

 }

 // Required for the localNotification event.

 - (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification

 {

  [RCTPushNotificationManager didReceiveLocalNotification:notification];

 }
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Note: This code hooks up your iOS application to React Native’s_ &lt;a href="https://facebook.github.io/react-native/docs/pushnotificationios"&gt;RCTPushNotificationMananager&lt;/a&gt;, allowing us to retrieve the device token and handle push notifications in our JavaScript code.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Running on Your Device
&lt;/h2&gt;

&lt;p&gt;Unfortunately, push notifications do not work in the iOS simulator, so you’re going to need a physical iOS device to be able to see the fruits of your labor. If you want to run your React Native application on a device, you’re going to have to edit the Xcode project to include code signing and push capabilities.&lt;/p&gt;

&lt;p&gt;Open up Xcode and from the navigation bar on the left make sure your project is selected. Navigate to the General tab and under Signing, make sure you are logged in with your Apple Developer Account. Once logged in, select your development team and be sure to check Automatically Manage Signing.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--g4Rf2RfL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.imgur.com/RknSkmi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--g4Rf2RfL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.imgur.com/RknSkmi.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the General tab, under Identity, make sure your Bundle Identifier matches the one you used to configure push notifications with Stream. If you haven’t done this yet, please head on over to &lt;a href="https://getstream.io/chat/docs/#push_ios"&gt;https://getstream.io/chat/docs/#push_ios&lt;/a&gt; and then return to this tutorial.&lt;/p&gt;

&lt;p&gt;Lastly, navigate to the Capabilities tab and make sure Push Notifications are enabled:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ECfRHLJ9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.imgur.com/89sZCHX.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ECfRHLJ9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.imgur.com/89sZCHX.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You’re all set! Plug in your iOS device, select it from the run menu in Xcode and press Run.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--UcVl7ZH5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.imgur.com/N2Fj33h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--UcVl7ZH5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.imgur.com/N2Fj33h.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Android Setup
&lt;/h2&gt;

&lt;p&gt;For Android, we’ll be using &lt;a href="https://firebase.google.com/docs/cloud-messaging/"&gt;Firebase Cloud Messaging&lt;/a&gt; to power push notifications. So first up, you’ll need to go to the  &lt;a href="http://console.firebase.google.com/"&gt;Firebase Console&lt;/a&gt; , create a new application OR select an existing project. Then, go to Project Settings and under the General tab. Click on Your Apps, add an Android application and download your google-services.json file – you need to put this in the root of your projects android directory.&lt;/p&gt;

&lt;p&gt;Now make sure &lt;code&gt;google-services.jsonfile&lt;/code&gt; is included in your Android project’s dependencies by navigating to your project level &lt;code&gt;build.gradle&lt;/code&gt; file (&lt;code&gt;._android_build.gradle&lt;/code&gt;), opening it, and copying the following code into your dependencies like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;buildscript {

    // ...

    dependencies {

        // ...

        classpath 'com.google.gms:google-services:+'

        // ...  

    }

    // ...

}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Then, in the same directory, find the &lt;code&gt;settings.gradle&lt;/code&gt; file and copy the following file if it isn’t already there.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: When you previously ran react-native link, it should have added the necessary files; however, it’s best to always double check. Linking can be temperamental at times.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;include ':react-native-push-notification'

project(':react-native-push-notification').projectDir = file('../node_modules/react-native-push-notification/android')
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Next, navigate to &lt;code&gt;._android_app/src&lt;/code&gt; and check you have the &lt;code&gt;res&lt;/code&gt; directory. If not, create it and inside create another directoy named values. Then create a new file named &lt;code&gt;colours.xml&lt;/code&gt; whose content is the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;resources&amp;gt;
        &amp;lt;color name="white"&amp;gt;#FFF&amp;lt;/color&amp;gt;
&amp;lt;/resources
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Linking may have also taken care of the next step, but once again, navigate to &lt;code&gt;MainApplication.java&lt;/code&gt; in your projects android directory within &lt;code&gt;android_app_src/main&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;And check it has these two parts, as highlighted with comments:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import com.dieam.reactnativepushnotification.ReactNativePushNotificationPackage;  // &amp;lt;--- THIS

public class MainApplication extends Application implements ReactApplication {

  private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
      @Override
      protected boolean getUseDeveloperSupport() {
        return BuildConfig.DEBUG;
      }

      @Override
      protected List&amp;lt;ReactPackage&amp;gt; getPackages() {

      return Arrays.&amp;lt;ReactPackage&amp;gt;asList(
          new MainReactPackage(),
          new ReactNativePushNotificationPackage() // &amp;lt;---- &amp;amp; THIS      
      );
    }
  };
  ....
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;And last but most certainly not least – go to &lt;code&gt;android_app_src_main_AndroidManifest.xml&lt;/code&gt; and copy the following (the comments below will help guide you for your particular setup):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;!-- &amp;lt; Only if you're using GCM or localNotificationSchedule() &amp;gt; --&amp;gt;

  &amp;lt;uses-permission android:name="android.permission.WAKE_LOCK" /&amp;gt;

  &amp;lt;permission
    android:name="${applicationId}.permission.C2D_MESSAGE"
    android:protectionLevel="signature" /&amp;gt;
   &amp;lt;uses-permission android:name="${applicationId}.permission.C2D_MESSAGE" /&amp;gt;

   &amp;lt;!-- &amp;lt; Only if you're using GCM or localNotificationSchedule() &amp;gt; --&amp;gt;
   &amp;lt;uses-permission android:name="android.permission.VIBRATE" /&amp;gt;
   &amp;lt;uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/&amp;gt;

&amp;lt;!-- Then, within the &amp;lt;application&amp;gt; block, place the following --&amp;gt;

    &amp;lt;receiver
    android:name="com.google.android.gms.gcm.GcmReceiver"
    android:exported="true"
    android:permission="com.google.android.c2dm.permission.SEND" &amp;gt;
    &amp;lt;intent-filter&amp;gt;
        &amp;lt;action android:name="com.google.android.c2dm.intent.RECEIVE" /&amp;gt;
        &amp;lt;category android:name="${applicationId}" /&amp;gt;
    &amp;lt;/intent-filter&amp;gt;
  &amp;lt;/receiver&amp;gt;

  &amp;lt;receiver android:name="com.dieam.reactnativepushnotification.modules.RNPushNotificationPublisher" /&amp;gt;
  &amp;lt;receiver android:name="com.dieam.reactnativepushnotification.modules.RNPushNotificationBootEventReceiver"&amp;gt;
    &amp;lt;intent-filter&amp;gt;
      &amp;lt;action android:name="android.intent.action.BOOT_COMPLETED" /&amp;gt;
    &amp;lt;/intent-filter&amp;gt;
  &amp;lt;/receiver&amp;gt;

  &amp;lt;service android:name="com.dieam.reactnativepushnotification.modules.RNPushNotificationRegistrationService"/&amp;gt;

  &amp;lt;service android:name="com.dieam.reactnativepushnotification.modules.RNPushNotificationListenerServiceGcm" android:exported="false" &amp;gt;
    &amp;lt;intent-filter&amp;gt;
      &amp;lt;action android:name="com.google.android.c2dm.intent.RECEIVE" /&amp;gt;
    &amp;lt;/intent-filter&amp;gt;
  &amp;lt;/service&amp;gt;

  &amp;lt;service
android:name="com.dieam.reactnativepushnotification.modules.RNPushNotificationListenerService"
        android:exported="false" &amp;gt;
    &amp;lt;intent-filter&amp;gt;
        &amp;lt;action android:name="com.google.firebase.MESSAGING_EVENT" /&amp;gt;
    &amp;lt;/intent-filter&amp;gt;
  &amp;lt;/service&amp;gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;And that’s it! We’re ready to start writing some plain old React Native and booting up our Stream Chat client prepared to send Push Notifications.&lt;/p&gt;

&lt;p&gt;Now is a good time to boot your application on your preferred platform, if you haven’t already, to check everything is going to plan without any dreaded red screens.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sending Push Notifications
&lt;/h2&gt;

&lt;p&gt;Thanks to &lt;a href="https://www.npmjs.com/package/react-native-push-notifications"&gt;react-native-push-notifications&lt;/a&gt;, we are provided a platform agnostic experience while still using native push on each platform! So first, before we send a notification, we’ll quickly hook up the Stream client.&lt;/p&gt;

&lt;p&gt;Open your App.js file in the root of your project. Check that &lt;code&gt;componentDidMount&lt;/code&gt; exists. If the file does not exist add an async &lt;code&gt;componentDidMount&lt;/code&gt; method to the class.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: This is where you’ll need your Stream application key from earlier. You’ll also want to generate a user token at this step if you’re not in development mode. If you are in production, see &lt;a href="https://getstream.io/chat/docs/#init_and_users"&gt;here&lt;/a&gt;: &lt;/p&gt;

&lt;p&gt;If you went with development mode, check the note in the code below, uncomment the call to &lt;code&gt;changeAppSettings&lt;/code&gt;, and then you can pass any string value as the token.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React, { Component } from 'react';
import StreamChat from 'stream-chat';
import { API_KEY, USER_ID, USER_TOKEN } from 'react-native-dotenv';

class App extends Component {
  async componentDidMount() {
    const client = new StreamChat(API_KEY, null);
    await client.setUser({ id: USER_ID }, USER_TOKEN);

    PushNotification.configure({
      onRegister(token) {
        client
          .addDevice(token.token, token.os === 'ios' ? 'apn' : 'firebase')
          .then(() =&amp;gt; {
            console.log(`registered device with token ${token}`);
          })
          .catch((e) =&amp;gt; {
            console.error(`registering device failed: ${e}`);
          });
      },
      onNotification(notification) {
        notification.finish(PushNotificationIOS.FetchResult.NoData);
      },
      senderID: "1069091084846",
      requestPermissions: true
    });  
  }
  // ...
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;For the sake of this tutorial, we created a .env file to store these values and grab them using  &lt;a href="https://www.npmjs.com/package/react-native-dotenv"&gt;react-native-dotenv&lt;/a&gt;  as shown above – a good idea for your &lt;code&gt;API_KEY&lt;/code&gt; in any case, but your &lt;code&gt;USER_ID&lt;/code&gt; and &lt;code&gt;USER_TOKEN&lt;/code&gt; will likely come from elsewhere in a real-world setting, depending on your use-case. &lt;/p&gt;

&lt;p&gt;Now all that’s left is to hook up  &lt;a href="https://github.com/zo0r/react-native-push-notification"&gt;react-native-push-notifications&lt;/a&gt; . &lt;/p&gt;

&lt;p&gt;Below your client.setUser call in componentDidMount, add the following config (and remember toimport PushNotification from ‘react-native-push-notification’; at the top).&lt;/p&gt;

&lt;p&gt;Below are the iOS and Android parts respectively, however, you can use both at the same time if your application is cross-platform:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PushNotification.configure({
  onRegister(token) {
    client
      .addDevice(token.token, token.os === 'ios' ? 'apn' : 'firebase')
      .then(() =&amp;gt; {
        console.log(`registered device with token ${token}`);
      })
      .catch((e) =&amp;gt; {
        console.error(`registering device failed: ${e}`);
      });
  },
  onNotification(notification) {
    // iOS only
    notification.finish(PushNotificationIOS.FetchResult.NoData);
  },
  senderID: "1069091084846", // (Android Only) Grab this from your Firebase Dashboard where you got google-services.json
  requestPermissions: true
});
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This is the bare minimum configuration to get &lt;a href="https://www.npmjs.com/package/react-native-push-notification"&gt;react-native-push-notification&lt;/a&gt; handling push notifications within your application. You should have a look at their &lt;a href="https://github.com/zo0r/react-native-push-notification#readme"&gt;GitHub repo&lt;/a&gt; for a full reference to configuration options and settings.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try It Out
&lt;/h2&gt;

&lt;p&gt;For this section, if your building for iOS you’ll need to plug in a real iOS device – push notifications won’t work within the simulator. However, the Android emulator &lt;em&gt;does&lt;/em&gt; support push notifications - just make sure you use an emulator with Google Play Services install (shown by the Play Store Icon in the AVD Manager)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--WnE1LXB_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.imgur.com/aky0VIi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--WnE1LXB_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.imgur.com/aky0VIi.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you enable the Remote JS Debugging when you boot your application, you should see the registered device with token  log appear in the console once you accept the permissions to allow notifications.&lt;/p&gt;

&lt;p&gt;Once your device is registered, ensure sure you have the &lt;a href="https://github.com/getstream/stream-cli"&gt;getstream-cli&lt;/a&gt;  installed and configured with your API key and secret (along with the other required arguments):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;stream config:set
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;After the configuration is complete, you can safely run the following command in your terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;stream chat:push:test
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;First, the CLI will prompt you for the ID of the user you want to send notifications to (you can find this in your .env – or wherever you stored it from earlier) – you then leave each remaining step blank to send a default notification to the devices registered to said user. For details information on the push CLI options, see  &lt;a href="https://github.com/GetStream/stream-cli/blob/master/docs/chat.md#stream-chatpushapn"&gt;here&lt;/a&gt; .&lt;/p&gt;

&lt;p&gt;If all is well, you just heard a ding or a chime of some sort, and you’re notification appeared on your device. Congrats! 😎&lt;/p&gt;

</description>
      <category>ios</category>
      <category>android</category>
      <category>pushnotifications</category>
      <category>reactnative</category>
    </item>
  </channel>
</rss>
