Generating the Rails 7 API
This video is going to cover how to set up a Rails 7 API. And if you stick around, I'll show you how to create a React app that communicates with this API. It'll pull a set of books back from the API and display it on a page using the React state. It's not a full React application, but it should at least give you a starting point if you're planning on using a Rails API with a JavaScript project.
So we're going to go ahead and we're going to start by creating the API right now. So say rails new, I'll call this the bookstore, and then I'll pass in --api. And we do that because that's what tells Rails to generate this as an API, so it doesn't create the views or any of that other noise. You know, open up our bookstore Rails app in VS Code.
I have my terminal open down here. I'll go ahead and close that. We then go into our Gemfile, and in our Gemfile, we're using Rails 7.0.1, like you can see right here, and Ruby 3.0.3. Uh, we'll then add a gem for the rack-cors. And this is just what allows us to whitelist our front end React application so that it can request data from the API, but other people can't. So it's just a set of security there.
Then go ahead and run bundle. Actually, we'll go ahead and we'll cd into the bookstore and then we'll run bundle, which should install the gem for us. We can then come into config and we can go into initializers and cors.rb.
Configuring CORS and Scaffolding a Resource
And then in here, I'll full screen Visual Studio Code real quick. We're going to uncomment this block right here, and we're going to replace this origins 'example.com'. You can replace it with just an asterisk, which will allow anyone to make a request to the API, or you can replace it with, like my autocomplete is suggesting here, the URL or the IP address of your front end client. In this case, React is going to start on port 3001 under localhost, which I already know, so I'm putting that inside of the origins. Of course, when I move this onto a production server, I'm going to have to change this to the actual URL of the production server or the IP for it.
Once we have this set up, we can go ahead and save and then we'll go ahead and we'll generate our scaffold. So for this, I'll type, oops, I'll type rails g scaffold. I'll actually full screen this and bump it up a couple times. We want to generate a scaffold for the books, and each book is going to have a title of type string and a body of type text. So we can go ahead and hit enter on that and then wait for that to finish. We can then minimize this again and we'll just run a rails db:migrate command to migrate the database. That will set up the back end of our back end.
Versioning the API with Namespaces
The next thing we need to do is create the routes for this. For that, we can go into config/routes.rb. And in here, all we need to do is set up some namespaces. And by convention, it's a good idea to say you want a namespace for your API and you also want to version it so that people can access the different versions without you making everything obsolete when you change something.
So for that, we'll say namespace :api then we put this inside of a do block with an end at the bottom. And then we need to do one more namespace for our version. So for this, we'll say :v1 do, and we can do an end right here. And I'll save this and it'll run the code formatter. This just puts our books inside of a scope namespace so that we can access it by going to for example /api/v1/books. That of course isn't working yet because we haven't set up the actual namespace or started the server yet.
The next thing we want to do here is in the app folder, in the controllers folder, we need to create a new folder. We'll call this api. Inside of api, we'll create another new folder. We'll call this v1. So you can already tell this is where our v1 controllers will go inside of our API. And then there, we actually just need to move our BooksController into that folder. Do you want to move this into v1? Yes, I do. Now we open up our v1 book controller, and at the top here where it says class blah blah blah, we need to actually say Api::V1::. That's just going to put the BooksController inside of that namespace, which is good. And now we'll go ahead and move this back over because I think we're actually done with the back end for now.
You might have to update some of these redirects when you do a create or an update action. I do have a video on that. I'll leave a link in the description for how to create like a full React API, um but in this case, our full Rails API. In this case, this is good enough for the sake of this tutorial.
Creating and Running the Frontend App
So the next thing we want to do is we want to come back to our console. We're inside of our Rails application in the console right now, and in here, we want to create the React app that we'll talk to this. For this, I'll type npx create-react-app, and I'll just call this, I don't know, bookable. Just something to work with. That'll go ahead and run the React generator for us.
Okay, now we can open this up inside of VS Code. If we go into our Rails app and go down to bookable, that will be our React application. So inside of this terminal right here, I'm going to go ahead and type rails s just to check if the server is working. It looks like it is. And then I'll try to go to this URL and that looks like it's working.
The next thing I'll do is I'll open up the React app in another terminal window. and inside of this other terminal window, I will then run npm run start, I believe, to start the server. And it says it's already running on 3000. You want to use another port? I'll type yes, and then it'll open that up automatically for me but it's going to do that in Chrome, which I don't want. So instead, I'm going to come over to my Brave and I'll refresh this page. And in here, we can see that the React app is running. It's of course not communicating with our API, but it is running.
Seeding Data and Structuring the React UI
And actually, now that I'm looking at this, let's go ahead and let's create a book real quick in our API. So let's open up our Rails console. In here, I'll just type Book. That looks like it's working so I'll do .create!. I'll give it a title that says My First Book and a body that says Hello World. And I'll remove that space. That looks like it worked. Let's change this one to My Second Book, and I'll just say Hello everyone in this, and that just gives us some data to work with. Now we can go ahead and start this again, and we should be up and running. So if I refresh this, here's our JSON data.
Now let's go ahead into our bookable app, open up our src, and then go into our App.js. Inside of here, I think we're probably going to just get rid of, let me make sure we're on the right page, get rid of this entire header file. And I'll go ahead and minimize this. I'll save that. That should cause this to refresh. And then in here, we'll just make a <h1> that says Hello, and that's just so we can see something on the screen. The next thing we should do is actually set up our API request. Um so let's do that real quick. Let's go over to our Node server right here. We'll stop it, and we'll just type npm i. I'll bump this up a bit, npm i axios, which is what we're going to be using for our API requests. Once that's done, we can just type npm run start again and start up the application. It'll once again ask us if we want to use a different port and then it'll open up a random window on my other monitor. And now we're good to go.
Now what we want to do is we want to import axios from axios. So that's grabbing it from our npm. You can also get rid of this import for the logo. And then below this, we actually need to import a different component. So let's open this up. Inside of source, I'm going to right click, click New Folder. I'll just call this components. And then inside of components, I will make the Books.js file. And then for this, I'll just type rfce, I'll hit enter and that'll generate our Books component. I'm going to change this to capital B Books. If you're wondering how I did that rfce thing, if you come down to extensions, it is this one right here. It's the ES7+ React/Redux/React-Native snippets extension. It just allows you to type like rfc and hit tab and it auto completes that for you.
Fetching API Data in React with Hooks
So let me move this back over and then give myself a bit more room over here. We have our books here. This is just where I want to display the list of books in the future. But for right now, we can just leave this alone and we have our app right here. So our app obviously needs to import Books from './components/Books'. And then inside of our function here, or I guess outside of our function, we want to declare our API URL. And if you had a store, this would normally live inside of your store. Like, let's say you're using Redux, you'd probably want to set this in there or something just so it's a bit more reusable. But here, we're just doing it with the const because it's, you know, similar to a basic JavaScript API in a sense.
So we have this const. The next thing we want to do is create a function to actually get the API data. For this, I'll say getApiData, and then we'll just return, you can see GitHub Copilot here is trying to help, axios.get(apiUrl), and then we'll do something like, I don't know, .then(response) and we'll just do response.data, something like that.
And then once we have that, we can then come into our App. And I guess we want to create a state for this. And it already knows what I'm planning on typing which is fancy but also unsettling. And for this, it's trying to suggest React.useState. Let's instead just use useState and come down to this one which will do the import for useState from React up here. And then inside of this, let's just initialize it to an empty array.
Next thing we should do is use an effect which is also going to be an import from React. So now we have useEffect up here. And then for the useEffect, we just want to create a quick function. We'll say let mounted = true; getApiData().then() and this data here will just say items. Inside of this, if mounted, then we want to set the books. And then we can actually come down to here and we'll say return and we want to return () => mounted = false. We, I don't think need this, actually. Now if we come down here we can close this, and because we only want this to run when the component's created, we can add in the extra empty brackets.
Displaying Data and Verifying the Connection
Now inside of our return, this is our actual render here, because we have our API call, but we need to do our actual render. Let's go ahead and let's say we have our Books, and we'll pass in our books as props and we'll just call them books in there. We can save that and come over to our Books.
A lot of books going on here, very confusing, I know. I'm sorry for that. We need to give our Books props. And then we can just go ahead and move into our div here. Let's start by saying <h1>These books are from the API</h1>. And then in here we'll just do props.books.map and I want to map each book. So just use a high order function here. And then we'll say, uh, let's return a div with the key equal to the book.id because we know that Rails gives it a book id. And then we'll give it, yep, we'll give it a <h2> title and it doesn't have an author but I'll accept this anyways and I'll change this to a body. And then I'll just close the div for the key. And that should be good, I believe. Now if we refresh, it should be getting the books from the API.
If you remember from our initial API over here, if I full screen this and I zoom in a bit, our initial API had a book with the title of My First Book, the body of Hello World. And it had a second title of My Second Book and Hello everyone. I believe if I come over here to our API and we just create one more just to check, we can do a Book.create and we'll say My Third Book and I'll just change this to Thanks for watching. We'll go ahead and we'll create that and then we'll start the server again, as someone hops onto Halo Infinite, and then we'll refresh our React API. And hopefully, we'll see My Third Book: Thanks for watching.
If you want to see more of this, I do know how to create a little bit more with the React app, or we could do the CRUD actions and add in a store. If you'd like that, feel free to leave a comment down below. But for now, thanks for watching and I'll see you in the next tutorial.