Loading
Lesson 13
Courses / Full Stack Web Dev Bootcamp (July 01 - July 12, 2024)
Intro to Expressjs - Full Stack Web Dev Bootcamp Day 7 (2024-07-10)

Learn to build a backend JSON RESTful API for the React app that was built to leave comments on a page.

JavaScript can now be used outside the browser, as a general purpose language called Nodejs.

The Express library (code written by somebody else) makes it easy to create an HTTP server.

Third-party modules or packages can be downloaded from the NPM registry.

The lecture goes over creating an endpoint or route to retrieve all the messages and load them on the frontend.

You leverage the pg library to create a client to access to the PostgreSQL database.

Video Transcript

Today, we'll talk about Express.js, which is a library we use to build an HP server using Node.js. It's the final step to glue the front end with the back end. So far, we did HTML, CSS, JavaScript. On the front end, we learned how to use the React library to build user interfaces. Then we venture into SQL to build a database. We got some tables to store the data for the app. Now we got to figure out how to hook them all up together, and that's the final piece. We're going to have a middleman acting between the front end and the database, and we're going to build that using JavaScript as well, because Node.js is nothing less than JavaScript programming language. It's just a different name. It just so happens that JavaScript in the beginning was just constrained to the browser, and then somebody had the idea of taking that out. Why not use JavaScript outside the browser for general things the same way other programming languages are used so Node.js was born. So don't be scared of the name. It's just a name, but it's basically just JavaScript server side. So you're going to need Node.js. This is the website you download, and the library is expressed, and we download that using npm, the Node package manager. But yeah, for now, if you recall what we had, let me power up the app first. What we had, github.com. This is the repository that we have been working on. You can see the SQL statements that yesterday are here. Basically, there's a web client directory where we have the React application. So if we go and power that up first, you see the two web client in the terminal, and then you run npm space start, and you got this. Notice it's part 3000. Keep that in mind, because the server has to run on a different port. Okay, we got the front end running. So we can access that. Let me see if I can bring it up. This is the front end, if you click slash messages. This is what we've been building, and we're going to build a back end for this. So far, we only have a fake back end that's loading these messages, and we have no way to persist in them, and we refresh, they're all gone. That's what we're going to build now to persist those. Okay, if you refresh your memory as well about the database, with pgadmin, we have a database, full stackdb2, schema is public, and we got a table here for messages and one for users. If you look at messages, here are the columns, we already had some data, the view added data all rows, and you can see each row is a different message with a comment by somebody. Okay, now let's build the server. Back to the repository, under the root, I create a new folder called its server to better organize what we've been doing. So we're going to create a new file there, it's called index.js. Now notice the .js extension, because this is going to be a JavaScript file. And then here, what you're going to do is, okay, before we do anything, we need to download a third-party package that is Express, and then we're going to need also the driver to access the database for Postgres, but the code for that, it's already written by somebody else, we don't have to write it from scratch. And to kind of download the code that somebody else wrote, we use npm, the node package manager. So before we do anything, we need to make this server directory an npm project, the same way we did web clients, we have a package.js on there with dependencies, we can do the same way. So basically, let me open a new terminal window here, where I choose command prompt. I have two, by the way, one for the web client, and then I'll have one for the server. I'm going to cd to server, and I'm going to npm init. That basically creates a package.json, so we don't have to do it manually. I'm going to enter everything, I don't care, I can change those later. Yes, and then we create a package.json here, under server directory, then we can install packages npm install, we're going to need express, and we're going to need pg. This is for the htp web server, pg is for the database driver. Now that we got them here, see under dependencies, and if you check node modules, I know I didn't talk much about node.js, so basically, whenever you install npm, it's going to install under node modules, so you're going to see express directory here. That's the source code, you can see the actual code for express, it's here, like that. Anyway, also the same for pg, and all of their dependencies are here. Anyway, we got that, so we're going to go back to index, now finally we can require. So the way you do, if you want to pull third-party code in node.js, by default we use what's called common.js pattern, which is different from the import that you've been seeing of React. So here we're going to say express, and let me disable my copilot, because that's not good for us as beginners, and I might have to refresh one moment, reload window. I hope you can see it again. Going back, so basically, we require the name of the module as the same name that we have in package.json, if I put it on the side here, the same name here has to match there, and then we can put that in a variable like const, to define a variable in JavaScript, and I usually call the same name as the module within the quotes, and then you can call that as a function to create what's an app. So this is a function call, and that returns you something, and that something is usually it's an application, and we usually call it app or app, so put that in a variable. And then we can ask the app to listen, so app.listen, and you can call it as a function like that, but it needs a part, so if you hover over this, usually visual studio code will tell you what the arguments are. So basically, we need a part here, and I'm putting a variable on this part, and notice we cannot do 3000 because it's already taken by the front end, so we should do something like 3000 month, or another one that's not 3000. And then, this should create a basic HTTP server, if you do to run the JavaScript file here, basically you just do node, space, file name, index.js, and notice nothing's happening, but it's actually happening, you don't see the prompt again like this, so it's running. So basically, you can go to the browser, and try accessing localhost colon 3001, and you should see it cannot get slash, that means it's running, and the message is just saying, hey, I don't recognize this endpoint because we haven't defined that, okay? If you want to inspect that with the dev tools, click network tab, same as Chrome, make sure you click all, filter, and you can see there's a 404, whatever, there's a response how you should see, let me see if you have power by express somewhere, usually there's a power by express, response, you know, get, whatever, yeah, I don't know why there's no power by it, usually there is, anyway, should see any of the other ones, okay, so going back there, this is not nice, so basically what we do is we want to get some feedback when we run it, so we add a second argument to listen, so this function takes the first argument apart, the second we can pass an actual function, that will be run when we power this up, and we can pretty much print a message with console log to the console, and I usually say with back tick, by the way, so I can interpolate the port later, server is running at htp colon slash slash local host colon, to interpolate dollar, curly brace the port, basically the value port here goes into that, if you have a question post in the chat, okay? All right, so that value will go here, so imagine that it will go here, like that, but in order for that to work, the only, you have to use the back tick like this, we cannot do single or double quotes, all right? Anyway, so going back here, just want to, but the person came later, that's the repository I've been using, so if you want to follow along, this is the repository, you have the web client directory, you have the CD to that, npm install, and then npm start, and then once you got that, go to a new terminal window, and then create a new folder called server, and then you create index.js like this, but before you should do npm init, and then npm install express and PG, all right? Why do we have to write a function in the lesson? Because we want some feedback when we run the server, right now when we run it without that, you see nothing is happening, so you might be confused what's going on. So you write that here, so that when we kill the server, we control C by the way, control C, and try it again, so every time you change the code, make sure to control C and restart it, every time you change the code, restart it, don't forget, and you now see that there is some feedback there, server is running at that, and I can control and click it to follow that, very nice, all right? So that's more convenient for us. Anyway, with that in place, let's learn how we can build an endpoint or a route to serve a resource. So basically, the server is just acting as an middleman, so it waits for requests, it's listening, if anybody comes along, they will ask for a resource, and the server will see if they can serve them, right? Usually, it would first authenticate the person, hey, is this person signing to our system? And then is the person authorized to do what they're trying to do? And then finally, they can either, along the way, they can either reject the person, hey, you're not allowed to do this, you don't have permission, or they are granted. But anyway, that's a little bit too complex for what we have right now, so let's do just a simple thing. So what we're going to do is just do a very simple route for a GET request. So a GET, if HTTP hypertracks transfer protocol is the way we usually communicate from the client to the server. And when you go in the browser, type an address, enter, that's actually making an HTTP request, and it's a GET request, okay? So how do you build a way to handle a GET request? Basically, say app.get, the GET is the method, and then you call this as a function. And this function here requires two things versus the path. So okay, where's this research going to be at? Let's say slash messages, when somebody comes in, they go to localhost 3001, right, slash messages, then it's going to hit this GET here. Now we got to do some instructions, what we're going to do when we get that kind of request, GET messages. Well, we got a past second argument, that's a function. So with a set of instructions to execute, and then ultimately going to reply with a response. Now this function takes two arguments, rec and res, separated by comma, the first is this request, the second is a response. If you want to spell them out, that's fine. It doesn't matter. Okay, now what we do here is typically we do some processing, whatever, whatever, try to look up in the database, the messages, and ultimately, we're going to send back a response. And the way you can do that is with res, you call the res object, and dot send function like this, and you can pass whatever there. For example, if it's just a plain string, you can say hello there. And then going back, by the way, you got to restart, right, control C, do it again. Going back to the browser, let's see, what we got. We are here 3,001 slash messages. This is a GET request. I see hello there. If you want to inspect, try again with the dev tools open, network tab, filter all, you should be able to see a 200 for slash messages on the localhost 3,001. And like I told you, I was trying to show you this x powered by header, the response is like saying, hey, we were powered by express. Anyway, the response is just this plain text like that. And I think let me see the response content type is HTML, text HTML, if I care site, you have 8. Okay. So far, so good. Let me know if you're having trouble. Well, you need something. Okay. Great. By the way, you might also see people using dot JSON. Same thing. If you do JSON, like, object. So the send will recognize whatever if you try to pass an object like this, object name, hello, it will recognize that it passed it. By the way, you got to close the server restart. Going back here, let's say refresh should see a response. Hello. And this is Firefox live preview. Let's basically this make it bigger for you. Response basically raw. It's JSON. Okay, so basically, this is what we're going to build. It is a server. That when asked for a resource, we're going to reply with some JSON. Okay, so tax in the format JSON. You know, the traditional old days, people used to send back HTML and just server side render everything. But this is we're separating back in the front end. And the front end is building itself. Remember when we have a React application, a single page application, everything is constructed in the front end, the document. And then when we change pages, it's actually just rebuilding and manipulating the document to look like something else, which is a different quote page. And all those flown is going to do is request data from the back end in the JSON format. Of course, it does HP request and then receives that data in the body of the request, the response in JSON. That's, we might hear the term. It's a back end API JSON format. That kind of stuff is basically what we're doing. RESTful, by the way, too, we're going to hear RESTful. RESTful is just a way basically to name your paths. And usually we name it like this with the resource name. For example, if I want to get all the messages, I would name it with slash messages and then if you want to create a message, that would be post that we're going to do later, post slash messages and so on. It's basically, and it's simplest form is just the naming that we choose. Of course, you're going to choose, hey, there, whatever. And this is not RESTful at all. And the way they do that is so that if you want to get a specific message, you could add an endpoint like yet slash messages slash one, two, three for the message ID. So you see it's like a hierarchy. Okay, we're going through message resource. And if you want a specific one, slash the ID of that. Anyway, let's learn how to connect to the database. So we're going to need the PG module. So you go up there, require PG, and then put in a very const PG equals. By the way, let's compare again with the front end web client source app. If you notice the front end, we use import right from because this is like the new way of doing this, it's called ES modules, ECMAScript modules. And whereas the Node.js way is common JS, which is what they require. So people are trying to move towards this one, the import, but still Node.js is behind. And it's kind of hard to work, you know, usually we have worked with both of them. And yeah, that's not an easy thing, because in web development, they try to support the previous stuff as much as they can. So anyway, you can look that up yourself, ESM versus common JS. So when you're back end here, remember require with the const variable, when you're front end is report, whatever from, okay, anyway. So PG. So what we're going to do here, I think we're going to do a new. So PG.client, we can create an object from this and to create an object. Usually in JavaScript, traditionally, you could define a function that would be a blueprint for an object, which is basically in object oriented programming is a class that builds many objects. And usually you would say new before that. Okay, so you can create a new or instance, a new instance of a client with new PG.client, and then you can pass some options as an object, like that. And here we're going to say, okay, what is the database? pull underscore stack db2 that I'm using. What is the user pull stack user to I think, and what's the password don't copy please. And yeah, and this one should return the client itself so I can put in a variable PG client or whatever you want to call it. And that way we can use it. And then finally, we got to connect with PG client dot connect like this. But before I move on, I just want to go back to PG admin to show you why I put these values here. Right, if you're not aware. In the last lesson, we went and created the first created a user here. Right, we right click create login group will stack user in my case, a user two because I already had the other one. And then a creator the database will stack db sub two separated by underscore. Okay, so that's why and I set a password on that. Anyway, I take that and can pass as this configuration object here to the PG client. PG is just basically, we have the database server running postgres, right, you should have postgres running in your computer. And how can we connect to that and execute queries from JavaScript or Node.js. Well, we would have to write code to implement all of that by ourselves. But we don't want to reinvent the wheel. So what we're going to do is leverage the work somebody already did in order to accomplish that. So it just so happens that in the npm registry, right, let's go npm.js.com. This is where we download code that somebody else wrote libraries. And we can find a postgres one that's PG. You can see it's a postgres client. And this one has some code right if you go to their source code is open source. This is where all the code is. But basically, this allows us to connect to the database and execute queries. And it was written by somebody else. So we don't have to spend all the time writing it ourselves. Anyway, we pull that into our project by npm install PG in the terminal if you recall. I don't know if we have it here somewhere. There we go here. I installed PG. And that should install under node modules. PG. And the code is there. So in order for us to include that code, that functionality we do require here. And that way we cannot have access to that driver, right? It's a client. And when we do a new client here, create this new object that we can use to connect and ultimately execute queries. I hope that makes sense. All right, but this one connect actually returned a promise if you hover over it. So usually when we have a promise, you want to ensure first it executes and the connects usually can do a then and then I'm going to do something else with this callback function. So ideally, you want to move this everywhere they're inside like this. Oops, like that. Now if you don't want to don't like that nesting, you can do the following. Let me show you. You can use async await. So basically you can do await the keyword here. So basically that would wait for the promise here to would take have the promise. And when it returns a value, hey, okay, I'm okay, I connected it would go on execute the code after that. Now to do this, I need to have a sync function underlying it. So if I try to run it, it's going to complain await is only valid in a sync functions. So we got to wrap this whole thing in a sync function, let's call a setup app. And it could put it there. But then you would have to move this here as well. Oops, messed up my keys. You know how you work on Mac, you press command, I just did that instead of control because I'm a Windows right now. Anyway, I hope you can still see it. So you move everything here, there, fix the invitation. And then because it's a function definition, it won't call itself. So you got to call it outside like that. All of that just to have a sync function be able to use await. Of course, you can better organize all this stuff, usually would move all these route definitions to a separate file, and all that stuff. So it'd be very clean. Anyway, let's see if it's working. If you don't get any errors, I think it works. What did I miss? 26. Let's read the error. By the way, if you don't know how to debug, read the where the file is index, okay, line colon line 26, line 26, I'm missing what the closing parentheses here, like that, and it shouldn't be that one. There you go, fix that. Okay, try note again, it should have no problems connecting. If you see an error, that means something's wrong. Okay, ready to make a query? Okay. So let's go back to this endpoint for slash messages. Remember, when the user makes a request from the client get my HP colon slash slash local host colon 3001 slash messages slash messages, we're going to hit this function, meaning we're going to execute from the top to the bottom of the body. So first, we usually do query, right, ask the database database, please give me all the messages. Then you take that and reply, resend that. Okay, so how to make a query? Well, column of PG client, PG client, hey, has a function called dot query. And it can pass the query as the argument string here. So what's the query to we got the table messages, we want to select all the columns from messages. What's the query? Select star from messages, just like we did in the previous lesson, semicolon if you want. Now, if you do this, it returns a promise. By the way, you can VS code usually if you hover over it, it will try to give you the types. And the way I read this is you got to know here, I see this parenthesis. After the parenthesis, there's a colon, which is many this function returns a promise of this following type. But I'll like her about this, that's returning a promise. Remember, we did promise when we did the front end, if you recall, in the front end, we did messages.js, where we did fetch, fetch returns a promise, and response JSON returns a promise. So we always need dot then, to do something after the promise is fulfilled, because to column the database for data takes time. So it's promising you, hey, I'm going to give you something back, but please wait. But because the nature of JavaScript is asynchronous, if you were this, the program doesn't like hang here, it keeps going. Basically, this is executed, and it's going to go there, eventually find something. But it's going to keep going, despite that, it's going to send a response right away. If I don't do anything about waiting for this first. So usually what I could do is, okay, I only want to send when this form is fulfills, but to do that, I got to put a dot then here, call this function after it's been fulfilled. That is, we got the data from the database, then we got to move the rest and inside there, like that. And that's how you handle a promise. Now, I'm obviously not going to send hello here. I think this function is going to give us a rose. And then we can send back the rose. I think that should be okay. It's an array of objects, if I recall. Let's test it out. Kill the server, restart browser, go back here, refresh. There you go. Let's see what's going on. We might have messed up. Uh-oh. We messed up. We sent back the whole result. It's not rose. So let me show you the raw. This is the raw. Basically, what the callback function gets is the whole results from this query. And inside that, we got rows here. That's what we actually want, right? See it's an array of objects. Anyway, let's fix that. So here it's not really rows, it's just results, result. And then it's an object that has rows. So I can say result dot rows, like that, just to get the rows. Remember, kill the server and do it again. And if I refresh, there you go. You can see now, this is the raw, by the way, just a one-liner with a text format, informat.json. So Firefox has this feature where it makes a live document to make it nicer for us to visualize. So basically, it's an array of objects. And you see each object represents the rowing database, and each property is the column. Right? So we got all of them here. What would it look like in Chrome? If you ask Chrome users, Chrome-based edge people, let's see. There you go. Looks like this. So I can click 3D print. It's a function from Chrome that adds some annotation and spaces to better to help us visualize what's going on. I think like network, let's see if it has a live document view. I'll click all here. So this is what it looks like in Chrome in the response. Yeah, it looks a little better, but there is, yeah, it has a live preview as well, like Firefox. Anyway, we got the data in the endpoint. So going back to VS Code, let me teach you something about not having to ever have to kill the server and restart again. Node-mon, you ever heard, probably have used it. So let's install that and if you have installed dash dash save dash dev, Node-mon. The reason I use dash dash save dev is to separate this dependency for the dev dependencies with the dev dependencies that you're going to see. Basically, the package.json for server now has a section called dev dependencies, Node-mon there. Now, the reason I have it separate is because people like to separate what's needed for production versus what's needed only for development. And Node-mon is something as a tool for us to develop and not necessarily for production. In production, we don't want to be restarting the app all the time. That's why people separate, but strictly, you don't have to. You could have put Node-mon under dependencies, it would work the same way. Okay, now we've got to do the following. Okay, Node-mon was installing Node modules, and it adds a command in .bin as well. And this one, in my case, is windows.cmd and mac.pldinux is the other one. It's basically a command to call node-mon.js here under the Node-mon folder that was installed. Where is it? M-N-O-P. Node-mon.bin. See the command here? This is basically the Node-mon code that's executing. Anyway, I can type .slash Node-modules.bin and then Node-mon and then my file name. And it will call Node-mon. If you don't want to type this whole path, you just type npx Node-mon index.js. And there you go. Node-mon will listen to changes. Let me show you what's going to happen. If I go to index and I add a comment, hello, save it. You see what it did? Restarting due to changes automatically restarts it for us. All right. Now, if you ever forget that, you want to add that as npm script. So let's do that. fact.json under script. You're going to add, let's add a dev script here, for example. So when we run npm run dev, it will run the following command and that's going to be node-mon index.js. You don't need to have the npx here. So that way, whenever I need to start my development, I just say npm run dev and that in turn will call node-mon. You see here node-mon index.js. So that way, you don't have to remember that's node-mon that's executing or if you ever need to change from node-mon to something else, you would just change it here in the script and people will still use npm run dev without any change. Okay, enough of that. We got messages. Let's see how the front end will handle this. Let's go back. Web client, source pages, messages.js. We got here the component, remember, we got a react component messages and if I fold this because I don't care right now, there's a user fact, remember, the component is a function that returns some sort of template that looks like HTML, but it's actually called JSX, which is syntactic sugar for JavaScript function calls to react.create element. And after that's been rendered, that means the function was called, the document was updated for the user. It's going to call the function from user effect because there's an empty array, it's only called once after the first render and no more, otherwise it would be running after every render. And that call is calling fetch to retrieve data, right, it's going to make a get by default, htp request to some server here, this one that we use, it's a fake one. We don't want to do that anymore. Now we got our own. So we're going to do htp colon slash slash local host colon 2001 slash messages. If you recall, that's the end point we just built to retrieve messages from the database, the table of messages. Make sure it's HP not s, okay. If you make that mistake, like I did before, putting an s there, it's not going to work. And that's it. I don't think we have to change anything else except, let me see, maybe this part here. Right now, if you recall, our table, if I put the table here, definition on the side or up, let me see, put on the side. This is definition for messages table, got ID, comment, created add author, notice here, we're expecting what for messages, if I scroll all the way down, where we create the div with the messages, we do message dot comment, so that's fine. We've got ID as well. Okay, so I think this one has to change because I think we had to do this, because the fake back end didn't have the comment column. So I don't think we did that anymore, actually. We removed that. So let me make sure I'm doing the right, I think this one, right? Yeah. So post already in the right format that we expect. So now let's try it out. Remember, Nodemon is running here. And whatever change we make, on the back end is right there by the front end is also being listened to because we got a development server running. So let's see, back to, let me use Chrome, localhost 3000, go to messages. Oh, no, we got a problem. What is it? Let me see what's going on. We got a course problem. I can click on the console in the DevTools, access to file chat messages from origin has been blocked, no access, whatever, whatever. Basically, that's the problem with cross origin resource sharing that you might encounter a lot when you start new projects. That's because it's basically your, it wouldn't give you this problem if I had like the same domain, like here we have localhost 3000, the other one is 2001, if I had the same kind of, obviously, we're not using actual domains like hello.com. But basically, they would have to be hello.com on the server and the front end to make this work because right now it's the only same origin policy. If you want to read more about that, here's a resource. It's kind of annoying, but it's a way to protect from stuff. But basically, we want to allow cross origin. The way we do that is on the server side, our server has to send this header, access, control, allow origin. And basically, if you want to just allow one origin, that's our front end, you would specify the URL to that front end. If you want to allow everything, it's a star. So pretty much any website can call. Okay, so let's fix that easily with a module here. Basically, you can set the header if you want. Let me see if I can show you the manual way, and then I'll show you the metaware way. The manual way is go to index.js. And this is the endpoint, the function to handle that. Pretty much before we send anything, we have to set a header. It could be either before this or inside here, doesn't matter. To set a header, it should be header. Whereas you can use set, I think, or set header, either one like this. And you can give the name that they've required, access, control, allow origin like this. And you could put star if you want anything to be allowed. Let's try to see if it's working. You see the messages there? Basically, if you inspect network all, and let's bring refresh here. Actually, this one is front end. So let me go to XHR because that's XML-HP request, which is what fetch is doing. Let's inspect this one, click headers. We want to verify that the response sent by the server has some headers. This one, see that one? We set that one to star, which means, hey, we allow the origin, any origin. If you want a white list that you would do, basically, here you would, I think, if you put localhost 3,000, which is the front end, right? To only allow that one, you put it there. And let me see if it's still working. Yes, still working, right? No problem. See the messages here. And if I look at network, this one, I want to check the header for the response. It's still here with the specific one. Here, basically, you would have to do it for every single response to make it work. That's kind of annoying, right? What we do is we use a middleware. A middleware in Express is something that's put in between the request and the response that's to be sent. So, basically, if you think of it as a pipeline, water is flowing. And then, ultimately, it reaches the function here where you send back a response. But how can we always make sure to intercept the requests that are coming, all of them, and then make sure to set this header, and then that way, every single response will have it. Let's go up here after we do app. And to add a middleware, you say app.use, and then you pass a function that has rack, reds, and necks, three parameters. So, basically, what's going to happen is every time you get a request, it's going to pass through this function here. And it won't only let it through to this other one, for example, if you call next, that's the function you call. Hey, okay, you can go on to the next thing. Okay, so what we're going to do here, there, is move this here so that every single response will have this header set. So we get a request, pass through the middleware, set the header access control to this, and then go on to the next thing, which is basically this function here. And if there was another endpoint to be that other function, so on and so on. Okay. Now, if you don't want to do this yourself, there's a module called cores, so you can install that, let's go to the terminal, npm install cores, c or s. And then you would require here const cores. And basically, instead of this function, you call cores like this. So when you call cores, it's basically returning a function just like we had like this. That's doing a lot of extra stuff. Okay, basically, that's what it's doing. It returns a function definition for the middleware. And I think by default, it's going to be star. So if you were to change it, I think you got to change to origin to be HTTP, localhost 3000. But not a mistake. And let me comment this out and show you. Without, right? Let me put npm run dev. Go to the browser. I think that should do it. Network. By the way, I don't think I even need to see what's going on. It's running here. They got star right now, still there. Star. And if I change with origin as the object there, we don't want restart it. Refresh. Look it again. Now it's localhost 3000. Okay. So that's how you change through the middleware cores. Okay, so I think it's time for us to take a break. And I'll see you on the next one.
No comments yet (loading...)
No comments yet (loading...)
Did you like the lesson? 😆👍
Consider a donation to support our work: