Integrating the Stripe NPM Library With React and GraphQL

We'll continue to update the GraphQL resolver functions we've prepared to allow users to connect & disconnect from Stripe in our application.

Project Source Code

Get the project source code below, and follow along with the lesson material.

Download Project Source Code

To set up the project on your local machine, please follow the directions provided in the README.md file. If you run into any issues with running the project source code, then feel free to reach out to the author in the course's Discord channel.

This lesson preview is part of the TinyHouse: A Fullstack React Masterclass with TypeScript and GraphQL - Part Two course and can be unlocked immediately with a single-time purchase. Already have access to this course? Log in here.

This video is available to students only
Unlock This Course

Get unlimited access to TinyHouse: A Fullstack React Masterclass with TypeScript and GraphQL - Part Two, plus 70+ \newline books, guides and courses with the \newline Pro subscription.

Thumbnail for the \newline course TinyHouse: A Fullstack React Masterclass with TypeScript and GraphQL - Part Two
  • [00:00 - 00:10] We're going to install a new dependency into our server application and the additional type definitions. We're going to install the official Stripe API library for node applications.

    [00:11 - 00:22] The Stripe node library will allow us to make requests to Stripe from our node server. So with that said, we'll head to the terminal and install the Stripe library.

    [00:23 - 00:33] And when installed, we'll install the type definitions from the definitely typed repository. NPM install -d @ types /stripe.

    [00:34 - 00:49] At this moment in time, the Stripe node library doesn't have its own typings, though there is some discussion in the community to make that happen. So we'll go and install the community supported type definitions file.

    [00:50 - 01:18] Just like how we have a Google file kept within our lib API folder responsible in setting up the functions necessary to interact with Google APIs, we'll create a Stripe file in the lib API folder to consolidate all the functionalities we are to have interacting with the Stripe API. And in the lib API index file, we'll re-export the Stripe object we'll soon create.

    [01:19 - 01:33] In our Stripe file, we'll import the Stripe constructor from the Stripe library . We'll create a constant function called client that will be the Stripe constructor function we can run.

    [01:34 - 01:54] The Stripe constructor function expects us to pass in the API secret key of our platform Stripe account. We have this secret key kept as an environment variable in our server project, so we'll reference it and pass it in with process.env.s secret key.

    [01:55 - 02:08] We'll then construct a constant called Stripe. It would have at this moment only a connect function property that is to accept a code of type string.

    [02:09 - 02:27] This code will be the authorization code received from the client and will be used to make an authorization request to Stripe's server. In our connect function, we'll use the OAuth token function available to us within our constructed Stripe client.

    [02:28 - 02:47] This OAuth token function takes an options object and returns the connected user's information. We'll need to specify the code that is to be passed into this function from the client to successfully connect the user to our Stripe connect platform and retrieve the user's connected Stripe user ID.

    [02:48 - 03:04] In addition, the documentation tells us to specify a grant type option with a value of authorization code with which we'll do as well. Our TypeScript ES lint setup will warn us here and tell us that these properties should be in camel case.

    [03:05 - 03:29] Normally, we agree, but the grant type property is in this format and we can't really change it. So we'll simply disable the TypeScript ES lint camel case rule around these options.

    [03:30 - 03:56] Now if this response doesn't exist for some reason or another, we'll simply just return an error that says failed to connect with Stripe. If the response does exist, we'll simply have this connect function return the response.

    [03:57 - 04:12] Now this response object is to contain a series of different fields. And if we dive into the type definitions file of our Stripe library, and if we actually look up for this particular interface, this is the object essentially that will be returned from that connect function.

    [04:13 - 04:31] It would have a series of fields like the Stripe user ID, the access token, scope, live mode, token type and so forth and so on. Usually with OAuth 2.0 implementations, we'll grab the access token so we can make requests on behalf of the person's accounts.

    [04:32 - 04:41] However, in this case, all we'll need to collect for our use case is the Stripe user ID. The Stripe user ID is a reference to the connected accounts.

    [04:42 - 05:06] So when a payment is made, we'll simply pay out to the user with this particular ID. If you need to do more things within your Stripe platform, such as perhaps recurring payments or acting on behalf of a user, you may need to collect more of this information , but in our GraphQL mutation resolver, we'll only grab the Stripe user ID.

    [05:07 - 05:17] Now we'll modify our connect Stripe and disconnect Stripe mutation resolvers we have in our viewer resolvers map. And we'll begin with the connect Stripe mutation.

    [05:18 - 05:42] In the types file within the viewer resolver's folder, we'll first create an interface to represent the shape of data for the arguments that can be passed into our connect Stripe mutation. We'll export this interface called connect Stripe ARGS, that is to have an inputs property with a code property of type string.

    [05:43 - 06:13] In our viewer resolvers file, we'll import the connect Stripe ARGS interface. And in our connect Stripe mutation resolver, we'll retrieve the input argument and the database and request objects from the context available in our resol vers.

    [06:14 - 06:34] And we'll state that our connect Stripe function will be asynchronous and will return a promise that when resolved will be the viewer object. We'll set up a try catch block and in the beginning of our try statement, we'll destruct the code value from the input argument.

    [06:35 - 06:47] We'll then look to identify the viewer that is making this request. We'll only want a viewer to be logged into our application to connect with Stri pe and hence have this function to work.

    [06:48 - 07:05] We already have an authorized function we've set up to determine and identify a viewer so we'll run it and pass in the database and request objects. Remember, viewer is the term we use for the user viewing our app.

    [07:06 - 07:29] If the viewer can't be found or recognized from our authorized function, we'll throw an error along the lines of viewer cannot be found. We'll need to import this authorized function from the libutels folder.

    [07:30 - 07:48] We'll also import the Stripe object from the libapi folder since we're just about to use it to run the connect function we've just set up. When this viewer object is available, we'll know that this request is coming from a viewer successfully logged in.

    [07:49 - 08:05] So we'll run the connect function in our Stripe object and pass in the code that is to be passed in from the client. For the context of our application, we'll call the object that is to be returned from Stripe the wallets.

    [08:06 - 08:20] When we inspect this wallet object, it tells us that it could be of type error or Stripe OAuth iOAuth token, which is the actual wallet information we're looking for. That's not exactly the way we want it to behave.

    [08:21 - 08:36] I think that's the reason because we've stated that the connect function will return an error if this response does not exist. So what we'll do instead is we'll remove this returned error statement here to ensure that our Stripe connect function returns the response object.

    [08:37 - 08:50] If an error was to occur within the client token function, it would probably occur within it. And then in our connect Stripe mutation function, we can simply check over here if this wallet for some reason doesn't exist.

    [08:51 - 09:04] And then here we can throw an error that we would like to do. And we'll say something along the lines of Stripe grant error.

    [09:05 - 09:19] With this wallet information available to us, we'll look to update the user document for it is viewer in the user's collection and specify the wallet ID we've just obtained. We'll use the Mongo Find1 and Update function.

    [09:20 - 09:40] We'll find the appropriate user document from the underscore ID field that is to be the underscore ID value of the viewer. We'll use the set option property to update the wallet ID field of this document with the Stripe user ID field from the wallet.

    [09:41 - 09:54] If we needed to store more information from Stripe like the access token or refresh token, we'll do so here. But as we've mentioned, we'll only be interested in keeping the Stripe user ID value.

    [09:55 - 10:02] We'll specify the return original property to be false. So dysfunction value will be the updated value, not the original.

    [10:03 - 10:14] And if the value property within this update can't be found, it means we haven 't been able to update it for some reason. So we'll throw an error and say viewer cannot be updated.

    [10:15 - 10:32] If this value property exists, we'll update the viewer variable we have in this function with this new viewer object that is to now have the wallet ID property populated. At this moment, we can have the mutation return whatever the client might need to access.

    [10:33 - 10:58] So we may not need all this information in the client, we'll go ahead and return the viewer details such as the viewer_id, token, avatar, and the wallet ID. And we'll specify the did request property as true to convey that the request was made.

    [10:59 - 11:27] And in our catch statement, if an error was to ever occur in our actual try block, we'll catch the error and place it within an error statement that says failed to connect with Stripe. Our disconnect stripe mutation will appear similar, but instead of updating a user document with a valid wallet ID value, it will instead remove the value of the wallet ID field for that user document.

    [11:28 - 11:57] And in our context, this is how we state that we've disconnected the user from Stripe in our application. So in the disconnect stripe resolver function, we'll simply just access the database and request objects available as context.

    [11:58 - 12:29] We'll look to identify and authorize the viewer making the request and the viewer can't be found, we'll throw an error along the lines of viewer could not be found. If the viewer is available, we'll update the user document of this viewer, however in this case we'll set the wallet ID field of this document as null.

    [12:30 - 12:50] If the value property of the update doesn't exist, it probably means we couldn 't make the update, so we'll throw an error and say viewer could not be updated. If the value does exist, it probably means we've made the update successfully and we'll simply return the viewer object similar to what we return in the connect stripe mutation.

    [12:51 - 13:11] We'll return the ID token avatar wallet ID, which should now be no and the did request property. If an error is to occur anywhere in our tri-block, we'll capture it and keep it within another error message that says failed to disconnect with Stripe.

    [13:12 - 13:24] And that's pretty much it. Our connect stripe and disconnect stripe functions are now capable to connect a user into our application with their Stripe account and into our Stripe connected platform.

    [13:25 - 13:48] And essentially what we're looking for in particular is capturing the Stripe user ID return to us from Stripe's API and storing it in our database. Now it wouldn't be very easy to test what we've done so far, but we'll be able to do so in the next coming lessons when we build out the client functionality of passing the code that Stripe returns and calling this particular connect stripe mutation.