Back

Error handling from SSR to CSR

  • 0
  • Self Hosted
  • Auth
  • General
  • React Native
Faye
15 May, 2024, 09:22

(by the way, if you return return NextResponse.json(error) instead, you only need to make if statements like if data.type ==)

TL;DR
Developers were discussing error handling using server-side rendering (SSR) to client-side rendering (CSR) with Node-Appwrite in a Next.js project. They shared code examples for creating different client types based on server and API route requirements. Tips were given on structuring files and routes correctly, with emphasis on API routes needing to be in the /app/api folder. A specific API route example was provided to handle user sign-in and setting cookies. Recommendations included using the proper SDK tag and leveraging API routes over server actions for better stability. Additional details were given on handling errors like invalid credentials or blocked users in the context of a login
Faye
15 May, 2024, 09:22

api does not require pages

xmaniaxz
15 May, 2024, 09:23

oh? then i would have to read up how that works exactly. Thank you though and ill try to get this functional

Faye
15 May, 2024, 09:23

api is kind of it's own thing, now called "route handlers" https://nextjs.org/docs/app/building-your-application/routing/route-handlers

Faye
15 May, 2024, 09:24

(still needs to be in the /app folder though)

xmaniaxz
15 May, 2024, 09:24

ooooh so since i have it in src/app/util/node-appwrite.js I should be able to call it using fetch(/util/node-appwrite)?

Faye
15 May, 2024, 09:24

api routes need to be in /app/api folder

xmaniaxz
15 May, 2024, 09:25

gotcha thanks!

Faye
15 May, 2024, 09:25

otherwise it will not work correctly

Faye
15 May, 2024, 09:25

also, if you use any edge runtime (like cloudflare pages or vercel), they will automatically optimize these routes for you, as long as you use /api

xmaniaxz
15 May, 2024, 09:25

ok. Well im selfhosted so i dont make use of either.

Faye
15 May, 2024, 09:26
xmaniaxz
15 May, 2024, 09:30

will do. One last question. I currently have all my server functions in 1 file. Do i need to make new files for every function?

xmaniaxz
15 May, 2024, 09:30

asking because i have 35 functions that would have to be converted.

Faye
15 May, 2024, 09:33

You do not.

For example my folder structure for server actions is:

/src/app -- stuff here /src/utils/actions/category/specificName.ts

Category would be for example "user" or "account", where the file you can name whatever you want, but this is more of organizational purposes

Where my /src/utils/actions/user/account.ts file would look like this:

TypeScript
'use server'
import { createSessionServerClient } from '@/app/appwrite-session'
import { Models } from 'node-appwrite'

export async function changeEmail(email: string, password: string) {
  try {
    const { account } = await createSessionServerClient()
    return await account.updateEmail(email, password)
  } catch (error) {
    return JSON.parse(JSON.stringify(error))
  }
}

export async function changePassword(
  newPassword: string,
  currentPassword: string
) {
  try {
    const { account } = await createSessionServerClient()
    return await account.updatePassword(newPassword, currentPassword)
  } catch (error) {
    return JSON.parse(JSON.stringify(error))
  }
}

export async function changePreferences(body: Models.Preferences) {
  try {
    const { account } = await createSessionServerClient()
    return await account.updatePrefs(body)
  } catch (error) {
    return JSON.parse(JSON.stringify(error))
  }
}

export async function changeProfileUrl(profileUrl: string) {
  try {
    const { account, databases } = await createSessionServerClient()
    const userMe = await account.get()

    return await databases.updateDocument('hp_db', 'userdata', userMe?.$id, {
      profileUrl: profileUrl,
    })
  } catch (error) {
    return JSON.parse(JSON.stringify(error))
  }
}

As you can see, it's only specific to the user part

Faye
15 May, 2024, 09:33

This clears up some things, if you ever get an error in your file, your entire file will probably break

xmaniaxz
15 May, 2024, 09:35

Alright I would have to read this over couple of times to make sense of it but I think i can apply this.

xmaniaxz
15 May, 2024, 09:35

Thank you very much for your time and patience

Faye
15 May, 2024, 09:37

Also, here is a good example of the appwrite.ts file:

TypeScript
import {
  Client,
  Account,
  Teams,
  Functions,
  Databases,
  Storage,
  Messaging,
  Locale,
  Avatars,
} from 'node-appwrite'
import { headers } from 'next/headers'

export async function createSessionServerClient() {
  const headersList = headers()
  const cookieHeader = headersList.get('cookie')
  const cookies = cookieHeader ? cookieHeader.split('; ') : []
  const sessionCookie = cookies.find((cookie) => cookie.startsWith('a_session'))

  const client = new Client()
    .setEndpoint(`${process.env.NEXT_PUBLIC_API_URL}/v1`)
    .setProject(process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID)

  if (sessionCookie) {
    client.setSession(sessionCookie.split('=')[1])
  }

  return {
    get account() {
      return new Account(client)
    },
    get teams() {
      return new Teams(client)
    },
    get databases() {
      return new Databases(client)
    },
    get storage() {
      return new Storage(client)
    },
    get functions() {
      return new Functions(client)
    },
    get messaging() {
      return new Messaging(client)
    },
    get locale() {
      return new Locale(client)
    },
    get avatars() {
      return new Avatars(client)
    },
  }
}

export async function createSessionClient(request: any) {
  const client = new Client()
    .setEndpoint(`${process.env.NEXT_PUBLIC_API_URL}/v1`)
    .setProject(process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID)

  const session = request.cookies.get(
    `a_session_${process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID}`
  )

  if (session) {
    client.setSession(session.value)
  }

  return {
    get account() {
      return new Account(client)
    },
    get teams() {
      return new Teams(client)
    },
    get databases() {
      return new Databases(client)
    },
    get storage() {
      return new Storage(client)
    },
    get functions() {
      return new Functions(client)
    },
    get messaging() {
      return new Messaging(client)
    },
    get locale() {
      return new Locale(client)
    },
    get avatars() {
      return new Avatars(client)
    },
  }
}

export async function createAdminClient() {
  const client = new Client()
    .setEndpoint(`${process.env.NEXT_PUBLIC_API_URL}/v1`)
    .setProject(process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID)
    .setKey(process.env.APPWRITE_API_KEY)

  return {
    get account() {
      return new Account(client)
    },
    get teams() {
      return new Teams(client)
    },
    get databases() {
      return new Databases(client)
    },
    get storage() {
      return new Storage(client)
    },
    get functions() {
      return new Functions(client)
    },
    get messaging() {
      return new Messaging(client)
    },
    get locale() {
      return new Locale(client)
    },
    get avatars() {
      return new Avatars(client)
    },
  }
}

createSessionServerClient will be used the most in my case, for example on any page that is on the server, you can just do:

TypeScript
  const { account } = await createSessionServerClient()
  const userData = await account.get()

-- createSessionClient is kind of for using api route handler requests, mostly not needed if you don't really use any api routes

and createAdminClient for admin stuffs

Faye
15 May, 2024, 09:37

I saw you are using const session = cookies().get(userCookie);, which is displayed in the docs, but this is very incorrect, as cookies().get cannot read HTTPOnly cookies, lol.

xmaniaxz
15 May, 2024, 09:38

-_- xD well thanks for letting me know.

Faye
15 May, 2024, 09:38

HTTPOnly cookies can only be read from the headers, so it's 100% sure that the token only gets sent to the server and not to clients

xmaniaxz
15 May, 2024, 09:38

i will adjust that.

Faye
15 May, 2024, 09:39

Just do add to this, the code I sent here for the api route does create a httponly cookie, hence why I said it

Faye
15 May, 2024, 09:49

If your issue has been solved, please add [SOLVED] to the beginning of the title. Happy Appwriting! :appwriterocket:

Reply

Reply to this thread by joining our Discord

Reply on Discord

Need support?

Join our Discord

Get community support by joining our Discord server.

Join Discord

Get premium support

Join Appwrite Pro and get email support from our team.

Learn more