The Ultimate Guide to Server Actions in NextJs 13 with Error Handling & Validation Using Zod

Sdílet
Vložit
  • čas přidán 2. 08. 2024
  • In this video, we'll learn how to use the new server actions in NextJs 13 by building a Guestbook page on our site. We'll also look at error handling and data validation using Zod.
    👉🏼 The Ultimate NextJs Course
    🔗 www.hamedbahram.io/courses/ne...
    👉🏼 Project code (check out the `server-actions` branch)
    🔗 github.com/HamedBahram/nextjs...
    Chapters:
    0:00 Intro
    0:30 Definition
    2:35 Creation
    8:46 Invocation
    13:35 Progressive Enhancement
    14:46 Revalidation
    15:00 Validation
    16:00 Using cookies & headers
    16:15 Other enhancements
    17:00 Glossary
    17:36 Project setup
    20:35 Refactoring to use server actions
    27:30 Error handling
    30:40 Data validation with ZOD
    39:36 Outro

Komentáře • 78

  • @gr8tbigtreehugger
    @gr8tbigtreehugger Před rokem +2

    Many thanks for this super helpful and timely video - was planning to learn and do exactly this today!

  • @og2t
    @og2t Před 11 měsíci +1

    Exactly what I needed in the right time, thx a lot for this Hamed.

  • @zrios
    @zrios Před rokem +2

    Amazing!! I used to implement Formik and Yup in client components but this approach is awesome, quicker and easier.
    Thanks for share

    • @hamedbahram
      @hamedbahram  Před rokem

      Glad to hear that! Same here, I used to use Formik + yup 💯

  • @kyle-andrewgovinder9902
    @kyle-andrewgovinder9902 Před 9 měsíci +1

    Fantastic video
    Love all of your work
    Always learn so much

    • @hamedbahram
      @hamedbahram  Před 9 měsíci

      Glad to hear that. I appreciate your support 🙏🏼

  • @user-ss2ni7jj9r
    @user-ss2ni7jj9r Před 10 měsíci

    Khely Goooooliiii, Damet garm❤

  • @JiNx-yf1ef
    @JiNx-yf1ef Před rokem

    Thank you so much 🙏 , I have learned a lot of things from you 🙏

    • @hamedbahram
      @hamedbahram  Před rokem

      Happy to hear that! I appreciate your comment.

  • @reiniervarkevisser
    @reiniervarkevisser Před rokem +1

    Thanks for this.👏

  • @ahmedhussin5704
    @ahmedhussin5704 Před 10 měsíci +1

    Amazing tutorial .

  • @Happyday-nn6rh
    @Happyday-nn6rh Před rokem +1

    very helpful video ❤‍🔥 and is updating video that is nice

  • @moteteletsa2034
    @moteteletsa2034 Před rokem +3

    Thank you so much for a wonderful video. It has added so much value in my understanding of Server Actions. Nonetheless, I am really struggling with using redirect when using server actions. Instead of updating the current page on which the form is, I need to redirect user to the next page. Can you show us how we can do that? Thank you for your good content as always.

    • @hamedbahram
      @hamedbahram  Před rokem

      You're welcome! I'm glad you found the videos helpful. In order to redirect the user to a different page you can use the `redirect` function from `next/navigation`. You can read more about it here => nextjs.org/docs/app/api-reference/functions/redirect

  • @bySFer
    @bySFer Před 8 měsíci +1

    Hey Hamed, I was watching your informative CZcams video discussing the updates in Next.js 14. I'd love to learn more from your detailed notes in Notion about these updates. Would you mind sharing them with me? 🙂

    • @hamedbahram
      @hamedbahram  Před 8 měsíci

      That was a lesson from my NextJs course. I'll publish the notes as a blog post at some point. Hopefully in the near future.

  • @elvisc
    @elvisc Před 3 měsíci +1

    Great stuff! One question: In your implementation towards the end, the "client side" validation still needs to go through the server action. Is there a way to do client side validation without calling the server action, while keeping the "action" prop in the element? The reason for keeping the action prop in the form element is so that this is the only way the `useFormState` from react-dom can track the form state.

    • @hamedbahram
      @hamedbahram  Před 3 měsíci

      Good question, I believe you can create a client action from where you validate and call the server action.

  • @alvinacosta2312
    @alvinacosta2312 Před 10 měsíci +1

    how to change route after adding a guest? if for example my guest list and add form are on separate pages? thanks!!

    • @hamedbahram
      @hamedbahram  Před 10 měsíci

      You can call the `redirect` function from `next/navigation` to change routes.

  • @nicolasrodi3138
    @nicolasrodi3138 Před 9 měsíci +1

    How would you lay out the structure for adding a delete button for each todo? In terms of a server action that calls a db function for that and passing it to the button, or which way would you prefer to set that up? Thanks in advance.

    • @hamedbahram
      @hamedbahram  Před 9 měsíci

      You can use a `formAction` prop on the button, or wrap the button in a form with the `action` prop. Both would do the same thing.

  • @mohammadheydari9400
    @mohammadheydari9400 Před rokem +1

    Thanks for your video.
    I have a question about how secure is to use server action in client components. If i protect a client page using NextAuth, is there any way someone access to server actions that can be called from that page?

    • @hamedbahram
      @hamedbahram  Před rokem +1

      Good question! I wouldn't recommend server actions for production yet. But generally speaking once stable, it would be safe to pass server actions to the client. I'd recommend defining your actions in a separate file marked with 'use server' and use a middleware to intercept requests for authentication.

  • @gustavoseabra7495
    @gustavoseabra7495 Před 11 měsíci +1

    Hi Hamed!
    I have a server page with two components that fetch independently, if an error occurs in the fetch of one component and the other manages to get the data normally, I would like only the component with the error to display the error and the reset opportunity. If both have fetch error i want to show the error independently and each one have their own reset. Is it possible? I still haven't come up with a good solution

    • @hamedbahram
      @hamedbahram  Před 11 měsíci +1

      You have wrap each component with separate error boundaries. You can use the `react-error-boundary` package for that.

  • @mrbanana6969
    @mrbanana6969 Před rokem +3

    Thanks for the great video, very informative - I learned a lot.
    I am wondering if you or anyone else is having problems with propagating errors in the production builds? So everything works fine in dev, but when I run the production server and throw an error in a server action I am met with this error in the error boundary: "An error occurred in the Server Components render. The specific message is omitted in production builds to avoid leaking sensitive details. A digest property is included on this error instance which may provide additional details about the nature of the error."
    This happens both for client components and server components calling the same server action. Around 38:00 when you convert the GuestBookEntryForm to a client component and are able to propagate the errors to the client, I see you are running pnpm dev but did it also work on the production build? Sorry for the text wall - was a tricky one to articulate

    • @hamedbahram
      @hamedbahram  Před rokem +1

      The error message you're seeing in production is intentional and how error boundaries work in the app router. Regarding server actions, if you're returning the error instead of throwing it you should be able to handle it client-side.

    • @user-lb6xe8ct2r
      @user-lb6xe8ct2r Před 10 měsíci +1

      @@hamedbahram Same issue here.
      I've tried throw and return and both rendered the same digest message.
      At the moment the solution I'm using is returning json object containing my response (created a custom ServerResponse kind of like the NextResponse but containing a success, message, code, ... ), but don't know if that is actually best practice here.

    • @hamedbahram
      @hamedbahram  Před 10 měsíci +1

      @@user-lb6xe8ct2r That's a valid way of digesting your errors for sure.

    • @user-lb6xe8ct2r
      @user-lb6xe8ct2r Před 10 měsíci +1

      @@hamedbahram thanks!

    • @gustavoseabra7495
      @gustavoseabra7495 Před 10 měsíci +1

      ​@@hamedbahram Hello Hamed, I'm experiencing the same issue. I've created a custom error class for cases of unauthenticated users, and in the catch block, if the response status is 401, I throw this error. In client-side pages, I get the expected result, but in server-side pages, I encounter the same problem as they mentioned above (in production). Do you suggest a better way to handle this in server components? . Sorry if my question is repetitive.

  • @user-bh9dj1jx8r
    @user-bh9dj1jx8r Před 2 měsíci +1

    Thanks for great explanation!!
    I have a question though.
    I got that server-action runs independently of JS but i woner that if execution of server-action starts until after hydration is done. Or even execution of server-action(ex. asynchronous fetch logic or sth) runs also independently of hydration?
    The reason i m curious about this is at the end of the video, u said server-action is queued until hydration being done

    • @hamedbahram
      @hamedbahram  Před 2 měsíci +1

      If your form is a client component, then the server action execution is cued until after the hydration. But if you form is also server side then server actions can be immediately executed.

    • @user-bh9dj1jx8r
      @user-bh9dj1jx8r Před 2 měsíci

      @@hamedbahram wow thx for replying@!! It's interesting execution of server-action when to starts depends on where the form tag is(client or server component🫢)
      Thank u so much:))

  • @user-kh3ru2et7c
    @user-kh3ru2et7c Před 8 měsíci +1

    Hi Hamed,
    I'm just wondering you are throwing the error from the server action.
    How can we handle that ?

    • @hamedbahram
      @hamedbahram  Před 8 měsíci

      Watch the error handing section :)

  • @tomaslanda1317
    @tomaslanda1317 Před rokem +1

    So server actions will replace swr or reactQuery?

    • @hamedbahram
      @hamedbahram  Před rokem +1

      Yes if you were using those to mutate data :) also the fact that we can now fetch data on the server, reduces the need for those packages on the client.

  • @liketocode
    @liketocode Před rokem

    Hi Hamed. Great video. When handling local errors, though you do not define the server action in the client component, at 35:50 , the defined client function is asynchronous, so as to await the response of the server action addEntry(), and this produces a React runtime error:
    `Unhandled Runtime Error
    Error: async/await is not yet supported in Client Components.`

    • @hamedbahram
      @hamedbahram  Před rokem

      The error you're receiving is likely because you have turned your client component into an async component (function). Defining an async client-side action (function) won't cause an error.

    • @liketocode
      @liketocode Před rokem

      My client component (function) is not async: 'export default function Form(){...}'. The error message itself says 'async/await inside a client component is not supported'?

    • @hamedbahram
      @hamedbahram  Před rokem

      @@liketocode Hmm 🤔can you clone my code and confirm that you're still getting the same error?

  • @ahmedhassan_saver
    @ahmedhassan_saver Před rokem +1

    Thanks very much
    Can you share notion link

    • @hamedbahram
      @hamedbahram  Před rokem

      You're welcome. I recommend using the docs as a reference. The notion page is just a summary. You can find all the examples in the docs.

  • @abbaskareem5281
    @abbaskareem5281 Před rokem +1

    pardon me for this question if it's sound silly, server action is mutate data on server what if the server is a django-rest-framework server ? I mean another server not next js node server . I hope you understand what I mean. and thank you sir.

    • @hamedbahram
      @hamedbahram  Před rokem

      Anytime man, that's a good question. With a different backend server, you'd have to use route handlers (API endpoints). You won't be able to use server actions.

    • @brunocascio
      @brunocascio Před 11 měsíci +1

      @@hamedbahram Why not? in the server action you can just call other backends... It's like a BFF approach

    • @hamedbahram
      @hamedbahram  Před 11 měsíci

      @@brunocascio That's right you can call other backends from your server action. However I think the question was not using the server on NextJs - rather using the django backend.

  • @imkir4n
    @imkir4n Před rokem +1

    😃

  • @samislam2746
    @samislam2746 Před 5 měsíci

    I tried to send a POST request using Postman to my server action, in the browser it works, but in postman it doesn't, it just replies back with the HTML, and my console.log() message is not being printed in the terminal as if there is No POST request was sent. why is this?

    • @hamedbahram
      @hamedbahram  Před 5 měsíci +1

      It's meant to only work through your frontend in the browser.

    • @samislam2746
      @samislam2746 Před 5 měsíci +1

      @@hamedbahram
      I discovered how. It sends an id and some other arguments as form data in the request headers.

  • @camembertsucreausucre3440

    why you dont use server component for the form ?

    • @hamedbahram
      @hamedbahram  Před rokem

      You can definitely use a server component for the form.

    • @camembertsucreausucre3440
      @camembertsucreausucre3440 Před rokem +1

      @@hamedbahram Ok thank you, is it better to validate first on the client side, and if zod doesn't find an error, then run our server action ?

    • @hamedbahram
      @hamedbahram  Před rokem +1

      @@camembertsucreausucre3440 Absolutely!

  • @usamecoban2582
    @usamecoban2582 Před 7 měsíci +1

    Setting a cookie on server actions doesnt work. Its only working on middlewares and route handlers. Thats what I understand by testing it. I can only read the cookies on server actions.
    I was trying to refresh session token on server actions, tried everything but none is worked

    • @hamedbahram
      @hamedbahram  Před 7 měsíci

      Did you use the `cookies` function from `next/headers`? example ↓
      ```
      'use server'
      import { cookies } from 'next/headers'
      export async function exampleAction() {
      // Set cookie
      cookies().set('token', '123')
      }
      ```

    • @usamecoban2582
      @usamecoban2582 Před 7 měsíci

      @@hamedbahram yes I did, im using seperate backend, sending request from server action then trying to update cookies by using the response data.Maybe it's related to seperate backend ?

    • @hamedbahram
      @hamedbahram  Před 7 měsíci

      @@usamecoban2582 Hmm 🤔so is it that you can't see the cookie you're settng in the server action in your separate backend?

    • @usamecoban2582
      @usamecoban2582 Před 7 měsíci

      @@hamedbahram No, just getting an error (Error: Cookies can only be modified in a Server Action or Route Handler.) when I try to update cookies. Imagine that you have a method in actions.ts file marked as "use server" at the top of the file. If I call this method from server components it fails, but if its called from client components it works. its not server actions anymore when its called from server components. That's what I understand from this test
      My case was sending a request to my seperate backend using server actions. If the response has set-cookie header, i just want to update cookies. But it seems like after response is received its not server actions anymore.

    • @hamedbahram
      @hamedbahram  Před 7 měsíci

      @@usamecoban2582 How are you calling the server action from your server component?

  • @ClarkHilll
    @ClarkHilll Před rokem

    *PromoSM*

  • @hofimastah
    @hofimastah Před rokem +2

    const { error: zodError } = GuestEntrySchema.safeParse({ name, message })
    gives me
    Property 'error' does not exist on type 'SafeParseReturnType'.ts(2339)

    • @hamedbahram
      @hamedbahram  Před rokem +1

      Try the following, this should solve the problem:
      ```
      const result = GuestEntrySchema.safeParse({ name, message })
      if (result.success === false) {
      result.error
      }
      ```

    • @hofimastah
      @hofimastah Před rokem +1

      @@hamedbahram many thanks!

    • @hamedbahram
      @hamedbahram  Před rokem

      @@hofimastah You're welcome.