GraphQL becomes the one and only mediator between your frontend and your backend.
Tom Preston-Werner - RedwoodJS with Tom Preston-Werner
|I - Redwood Philosophies||Part 1 - Setup|
|II - Full Stack React||Part 2 - Routes|
|III - Jamstack||Part 3 - Prisma|
|IV - Serverless||Part 4 - CRUD|
|Part 5 - Contact|
|Part 6 - GraphQL|
|Part 7 - Deploy|
|Part 8 - Auth|
In part 5 we generated a contact page and took input from the user. In this part we'll connect our contact form to our database so we can persist the data entered into the form.
To modify our database we'll go to our
schema.prisma file and add a
yarn redwood db save to create a migration schema.
yarn rw db save
It will automatically assign your migration a name.
This will create another
migrations directory with a schema file, README, and
steps.json file like we saw in part 3.
yarn redwood db up to apply that migration to the database.
yarn rw db up
This will output the database actions applied after the migration, which includes one
Lastly the Prisma Client is generated.
yarn redwood generate sdl contact to create the schema definition language for the contact form.
yarn rw g sdl contact
This will create an sdl in your
graphql folder and a resolver in your
We created three files:
We'll look at our schema definition language first.
The sdl has two types:
And two inputs:
We need to create our own mutation. We don't get this by default because the sdl generator doesn't know what we plan to do with the schema.
Mutation type will be called
createContact. The input is
CreateContactInput! and it returns
Now we'll look at our
contacts service. It has a resolver for the
Query type from our sdl.
We'll create a resolver for
input from the browser and adds it to the database.
ContactPage file we'll add the mutation and assign it to
CREATE_CONTACT. It is a common convention to use all caps for our mutations.
We will just return the
id since the user will not see this.
Make sure to import
useMutation at the top of the file.
ContactPage component we'll call
useMutation(). We pass an object
create with variables that are defined in
The input is the actual object containing the
data which is assigned to
variables and passed to the
create() function inside
We are now ready to enter our data. Enter a name, email, and message and click the Save button.
Our form gives us the following object which we saw in the previous part.
We can now check to make sure it was saved. Remember all the way back in part 1 when we said there was something else running on
This is how we access the graphiQL interface. Click the graphql link.
GraphiQL is like an IDE for your GraphQL queries. On the left side you'll enter a query, and after clicking the middle play button the response will appear on the right side.
We'll create a
contact query that will return all the
contacts in the database.
We'll ask for the
Click the play button and on the right side you'll receive a
data object containing whatever your entered into your form.
data object contains a
contacts array with objects containing the form input.
There's a few more things we can add to our form to make the user experience a little better.
- We want to give the user some immediate feedback after they click the save button.
- We also want to put in safeguards in case the user feels like clicking the save button many times in fast succession.
To do this we'll add a
loading object after
loading will be true while the mutation is being performed, and will change to false when the mutation is complete.
We will add
disabled to the
Submit button and pass it the
While the mutation is in progress disabled is true, and once it is complete it will change to false. To test this out go to your Network tab in your browsers devtools. Here we can simulate slow 3G.
Enter some more data and click the Save button.
Now when you click the Save button it will be greyed out for a moment while the input is saved to the database.
Another problem with this form is the input sticks around on the page even after it is submitted. It would be better if we cleared the fields after submitting. We can do this by importing
ContactPage component we'll create a
formMethods variable and assign it the
useForm() function that we just imported.
<Form> we'll add
formMethods and pass it
formMethods as a prop.
This gives us access to the reset function. In
useMutation we'll add a second parameter, which is a callback called
When the mutation is complete we'll call
formMethods.reset() and display an
Thanks for telling me stuff about my things! To test this in the browser, enter some more data and click the Save button.
First the alert message appears on the screen. After clicking OK the form will be cleared.
Another thing we can improve is the label. Right now it is just defaulting to whatever is entered as the
name attribute in
<Label>. We can add a closing
</Label> tag and enter something between the tags to change the label. We'll capitalize the labels.
Check your form for the changes.
In the next part we'll finally deploy our project to the internet with Netlify and Heroku.