An Interest In:
Web News this Week
- April 1, 2024
- March 31, 2024
- March 30, 2024
- March 29, 2024
- March 28, 2024
- March 27, 2024
- March 26, 2024
Building an Event Registration Page with Composition API and Serverless Functions
The Composition API was born out of the desire to offer Vue developers a different way of writing and organizing code while building Vue apps. It provided some flexibilities around how we build Vue applications that werent possible in the Options API, but like every other methodology, they all have trade-offs.
The Composition API at a high-level overview offers developers a different way of writing code that ensures that codebases remain legible, readable and easier to maintain even as it grows larger.
In this post, well look at how to collect data from a conference registration form with the Composition API and post it to a serverless function that will receive the request and return a response. You can do pretty much anything else you want in the function, like saving users to a database using Hasura, or handling authentications with Netlify Identity.
If youll like to code along, Ive prepared a starter repository here for you. Check out the start branch and build from there.
For visual context, this is what the form looks like at the end.
You should already have a src/components/Registration
file set up for you in the start
branch so well go ahead and walkthrough handling the form fields with the Composition API. Well have fields for name
, email
, track
, mobile
track and tickets
. This means that we need a way to handle state for these fields.
Reactivity in the Composition API
In the Options API, all the pieces of data in the data() option is tracked and made reactive in Vue by default. But, in the Composition API, all the data is static by default. This means that we need a way to make it reactive. The Composition API comes with the reactive and ref helper methods which are available by default in Vue 3. Wrapping the data we need in our Vue app with these methods ensures that they remain reactive across the app.
ref
ref provides us a way to make data reactive. For instance, if I wanted to track when a form is submitted, I could create a ref variable for it like so:
<script> import { ref } from 'vue' export default { setup() { const isUserRegistered = ref(false) return { isUserRegistered } } }</script>
By returning isUserRegistered
in the setup()
function, I have exposed it to the template.
Accessing ref values
To access the value of ref variables, you have to append .value
to it. Consider this example:
<script> import { ref } from 'vue' export default { setup() { const isUserRegistered = ref(false) const sayHi = () => { if (!isUserRegistered.value){ // say hi to the registered user : } } return { isUserRegistered, sayHi } } }</script>
This might seem like you need to write a lot of .value
s when using ref but that is not the case in the render context. When you return a ref
in the setup()
function, it automatically unwraps to the inner value and becomes accessible to the template. As a result, you wont need to append .value
to access a ref
in the template:
<template> <div v-if="!isUserRegistered"> <!-- more template thingy --> </div></template>
Reactive
Just like ref
, reactive also provides us with a way of keeping data reactive in Vue 3. Albeit different from ref, it achieves the same result. Lets demonstrate how the reactive
helper method works in the registration form:
<script> import { reactive } from 'vue' export default { setup() { const formData = reactive({ name: "", email: "", }) return { formData } } }</script>
formData
in the setup()
function above is a reactive object that contains all the pieces of data supplied by the user. We return it in the setup()
function to expose it for use in the template. Speaking about the template, this is how well use it there:
<template> <div> <h1>Let's JAM in Space!</h1> <p> Register for the upcoming Jamstack conference in space! <br /> <strong>Free </strong>for one and <strong>$5 </strong> for 2+ tickets </p> <form> <label for="name">Name</label> <input id="name" v-model="formData.name" placeholder="Enter your name" /> <label for="email">Email </label> <input id="email" v-model="formData.email" placeholder="Enter your email" /> </form> </div></template>
You can immediately see why you may not want to keep binding data to the template using formData
as doing that could lead to a bloated markup when you have multiple properties inside the object. In my case, I decided to destructure formData
and get name
and email
directly from it like so:
return { ...formData // spread};//ORconst { name, email } = formData; // destructurereturn { name, email};
If we do that, then you might assume that name
and email
would be directly bound to the template so:
<template> <div> <form> <input v-model="name" placeholder="Enter your name" /> <input v-model="email" placeholder="Enter your email" /> </form> </div></template>
But unfortunately, thats not possible for one reason: spreading or destructuring the formData
object will remove reactivity from the different pieces of data inside the object. It suffices to say that it seems the reactive object cannot be destructured or spread directly with the spread operator. What do we do then?
toRefs
With respect to the snippet above, toRefs
is a helper method that allows us to achieve the spread effect on the formData
object while retaining reactivity for the different pieces of data inside it. In our case, we can use it to wrap the formData
object like so:
<script> import { reactive, toRefs } from 'vue' export default { setup() { const formData = reactive({ name: "", email: "", // other piece of data }) return { ...toRefs(formData) } } }</script>
With this, we can go ahead and use name
and email
directly in the template like we wanted to do here.
Computed
Computed properties in the Composition API work the same way they do in the Options API. However, they have a slightly different syntax. Imagine that I have an imaginary coupon
that gives users with 2 or more tickets a $3 discount from the total price of their ticket. If that was the case, then I would use a computed property to calculate the total price of the ticket like this:
<script> import { computed, reactive, toRefs } from 'vue' export default { setup() { const formData = reactive({ price: 0, tickets: 0, coupon: 3, discountedPrice: computed(() => { if (formData.tickets > 1) { return formData.price - formData.coupon; } else { return 0 } }); // other pieces of data }) return { ...toRefs(formData), } } }</script>
discountedPrice
in the snippet above is a computed property that tracks all of its dependencies (formData.price
and formData.coupon
).
Heres an even more interesting scenario. Lets introduce a tickets
property to the formData
object, and calculate price
based on how many tickets are selected. 1 ticket = $0 (free) while 2 or more tickets will be a flat rate of $5. Computed properties shines in this regard as you can see below:
<script> import { computed, reactive, toRefs } from 'vue' export default { setup() { const formData = reactive({ tickets: 0, coupon: 3, price: computed(() => { if (formData.tickets > 1) { return 5 - formData.coupon } else { return 0 } }) }) return { ...toRefs(formData) } } }</script>
Here, the computed property price
is tracking both coupon
and tickets
and ensures that anytime any of the values change, it will update automatically to capture the new changes. Bonus Point: You dont even need to have a separate discountedPrice
property anymore.
Methods
Methods in the Composition API are just regular functions defined in setup()
. As the last step to creating and using them, you have to always return it in setup()
so that it is exposed to the template. In our case, I want to create a method that takes all the information provided in the form and post it to a serverless function (which doesnt exist yet). Heres how to handle it in the Composition API:
<script>import { reactive, ref, toRefs } from 'vue'export default { setup() { const formData = reactive({ name: "", email: "", tickets: 0, price: 0 }) const isUserRegistered = ref(false) // method const registerUser = () => { // "/.netlify/functions/register" is the path to my serverless function fetch("/.netlify/functions/register", { method:"POST", body:JSON.stringify(formData) }) .then((response) => response.json()) .then(body => { // do something with the response isUserRegistered.value = true }) } return { ...toRefs(formData), isUserRegistered, registerUser } } }</script><template> <button @click.prevent="registerUser" type="submit">Register</button></template>
Remember, methods in the Composition API are normal JavaScript functions. No special syntax needed. The notable thing here is that just like everything else you need in the template, you have to return it in the setup()
function.
Serverless function
Serverless functions make it possible for developers to run a server without the overhead that come with fully managing a server. More-so, it comes with fewer cost implications as it only executes on demand. If this tutorial is your first look at serverless functions, I would recommend this awesome intro to serverless functions course by Jason Lengstorf.
A general rule of thumb for creating serverless functions is that it exports a function called handler
and returns a response. The response must be an object containing at least a statusCode
that matches a valid HTTP response code and a body
that is a string by default. At the barest minimum, this is a valid serverless function:
exports.handler = async (event, ctx) => { return { statusCode: 200, body: "Hello World" };};
event
The event argument in the function above is an object that contains all the information you need to know about the request. Heres a quick look at the structure:
{ path: '/.netlify/functions/register', httpMethod: 'POST', queryStringParameters: {}, multiValueQueryStringParameters: {}, headers: {}, multiValueHeaders: {} body: {}, isBase64Encoded: false}
This can be very useful to perform all sorts of operations in the function. Like validating the request methods, getting request query parameters, using data from the request body etc. When working with serverless functions, the event argument is your single source of truth for information about the request.
context
The second argument is context
. It is an object that provides broader information about the request. In it, you will find information like:
The name of the function that was called
If Netlify identity is present
What the client context is and
Lots of other information that you will rarely need, but provided for you regardless.
Ill go ahead and link you up with this doc that explains it in even more detail.
Now that we know what a serverless function looks like, lets make one. Create a functions/register.js
file in the root of your project and update it with this snippet:
// export a function called handlerexports.handler = async (event, ctx) => { // receive the request event and get the user's details from it const { name, email, track, mobileTrack, price } = JSON.parse(event.body); // Things you can do here! // create a user object and do what you want with, like: // Save user to a database // Authenticate user // Send event details to user's email // etc. const newUserDetails = { username: name, email: email, track: track, mobileTrack: mobileTrack, price: price }; // Send response back to the client return { statusCode: 200, body: JSON.stringify(newUserDetails) };};
Serverless functions help us perform server-side operations without maintaining a dedicated server. That is what we can do here. The form data sent from the client can be handled however you want in the function. You can save to your database, do server-side validation, handle authentication, roles etc. Talk about dynamic Jamstack? serverless functions is the way to go!
Finally, youll need to create a netlify.toml
file where you tell Netlify where your functions folder is. This helps Netlify locate your functions and deploy them for you along with the rest of your site.
[build]functions = "functions"
This site is hosted here on Netlify and you can play around with the repo yourself here on GitHub. I tried and failed to keep this post under 2k words, but I do hope you found some useful information here on both the Composition API and serverless functions.
More resources
Original Link: https://dev.to/kenny_io/building-an-event-registration-page-with-composition-api-and-serverless-functions-4dii
![Share on Facebook](https://www.webnuz.com/images/site/facebook_icon.png)
Dev To
![Dev To](https://www.webnuz.com/uploads/feeder_images/devto-logo.png)
More About this Source Visit Dev To