Skip to content

Instantly share code, notes, and snippets.

@wbobeirne
Created May 7, 2019 22:50
Show Gist options
  • Save wbobeirne/27af3853d7759d13569c3a7308fd739f to your computer and use it in GitHub Desktop.
Save wbobeirne/27af3853d7759d13569c3a7308fd739f to your computer and use it in GitHub Desktop.

Making Your First Lightning Web App - Part 2

Setting up our frontend and taking our first payment

Hey, this is part 2 of a 5 part series on building a Lightning app. If you haven't read part 1, you can go here and start from the beginning.

We left off with a basic webserver that had a single page for serving up our node's information. While it's a good start, we need a proper frontend with interactivity and style to consider ourselves an 'app'. And that's just what we'll be doing for part 2.

This time around we're adding Webpack, React, and Bootstrap (along with a) to the mix. Webpack will compile our code into files the browser knows how to deal with. React is the framework that will contain our frontend logic. Bootstrap will provide us with some nice components and styles so that we won't have to write that all from scratch.

Getting Started: Clone the (new) Project

Like last time, we'll start with cloning a further iteration of the project. If you want to keep any changes you made to the first part, feel free to manually add the new code.

git clone blah blah

Like before, you'll need to install the dependencies we need. We've added a few new ones to the mix, so it'll take a little longer this time:

yarn

And now we're all ready to go.

Project Overview

We now have a new folder in our project called client. This will contain the code and configuration for the frontend. There's a lot of new code here, and some alterations to the server, but a majority of it is pretty standard React / Webpack boilerplate.

I won't be covering all of that, since there are other tutorials that will do a much better job than I ever could. I recommend you brush up on that if you're completely unfamiliar with a React / Webpack / Typescript setup.

The code we'll be focusing on will strictly be the stuff that interacts with Lightning and our API, with some of the React-centric boilerplate excluded. Those include:

  • server/index.ts - New API-style routes have been added that our client will hit to fetch and create user-submitted posts.
  • client/lib/api.ts - A simple API interface that handles fetch requests to our API for those new routes.
  • client/components/PostForm.tsx - Form component for making a new post on our site, and paying the associated invoice.
  • client/components/Posts.tsx - List component that displays a list of all of the posts.

The Code

server/index.ts

Returning to our server from the previous tutorial, we now have a few new routes that all interact with the server/posts.ts file. I won't cover what's in there. since it's just a set of basic Javascript functions around adding and removing "Post" objects to a list stored in memory.

https://gist.github.com/f6f43fbeb815b03598fd41110357928e

Our first two routes are quite simple. The GET /api/posts endpoint returns an array of posts that have been paid for, ordered by most recent. The GET /api/posts/:id endpoint is one that gets a specific post, regardless of its payment status. These will be used for listing public posts, and checking on the status of your own post respectively.

The most interesting function here is the POST /api/posts endpoint, for submitting a new post:

https://gist.github.com/3e49d6fcf4621c23764ecb4d1457cd32

This creates a new Post object, which is initially marked as unpaid. We then generate an invoice with our node, and embed the post ID in the memo. This will allow us to look up the post later once it's been paid. We then return the unpaid post object, as well as the BOLT-11 payment request string to the user for them to pay.

Finally, down in our initialization logic, we have a bit of code that watches an invoice stream for paid invoices:

https://gist.github.com/a0f8e587887d615648f906aac993febf

Here we get a Readable object from our node API that allows us to tap into every invoice update from our node. This stream can update when invoices are created or paid, so we do a little logic upfront to exclude:

  • Unpaid, newly created inoices
  • Invoices that are potentially unrelated to our app, and don't have a correctly formatted memo

After we've ignored those, we can mark the post as paid with the ID we pulled out of the memo. The next time a user asks for the list of paid posts, this one will now show up!

client/lib/api.ts

https://gist.github.com/9f555b78d76cd16feb399b3a63aa168a

This provides us nicely typed functions for our server API in a way that gives us promise functions for the endpoints we just went over. Don't worry too much about the code in here, just know that we can call these methods now to get data from our server.

client/components/Posts.tsx

https://gist.github.com/828ed66529293baa450495e3d967f730

Here we're displaying any and all posts that users made and paid for. We make a request to our API to fetch the posts. If the request is successful, we store them in component state. If it fails for any reason, we store the error message in state instead.

But in order to make posts, we'll need to look at...

components/PostForm.tsx

Beyond the basic component stuff, PostForm has two important functions that we'll take a look at one at a time:

https://gist.github.com/e5781e3cd87145c5f3ac739b58b20fd7

Once we've filled out a name and some content for our post, this sets everything in motion. The post is submitted to the backend, and if all goes well we get back the post object, as well as that BOLT-11 paymentRequest string. We'll set these to our component's state so that we can render the payment request and a button to open it a wallet on our computer. We also call the checkIfPaid method:

https://gist.github.com/3b05d0dc4910df6c9ac9fdb7e26635a2

This method will check if we've paid for the post that we're currently showing an invoice for. It waits a second, checks, and if it hasn't been paid, calls itself again recursively. This will run forever until we either pay the invoice, which will cause it to refresh the page. Or if we just leave the page, the post will never be made public.

With that all taken care of, all that's left is to run the thing with yarn dev and check out our functioning Lightning app!


And that's it! There's a bit of glue connecting all of this logic together that we didn't cover, so please poke around and see how everything works. And by all means, tinker with the thing! Try making all posts cost the same amount, or double the cost per character. Add some of your own styling to really make it yours.

But there's still so much to improve here. Up next in part 3, we'll replace the janky behavior of long-polling to check our payment, and replace refreshing our page to have it instantly update with our post by using Web Sockets. Stay tuned!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment