Error Creating View from API route
Hello fellow dailyCo workers,
I am working on a NextJs app, and following the guide here: Use Next.js API routes to create Daily video chat rooms. However, a call to the API returned this error. I have done a lot of searching online to find an answer to no avail. Here is the error and related file contents:
error - SyntaxError: Unexpected token '<', "<!DOCTYPE "... is not valid JSON at JSON.parse (<anonymous>) at packageData (node:internal/deps/undici/undici:6456:23) at specConsumeBody (node:internal/deps/undici/undici:6434:14) at process.processTicksAndRejections (node:internal/process/task_queues:95:5) at async handler (webpack-internal:///(api)/./pages/api/room/index.js:26:26) at async Object.apiResolver (path-to-local-dir) at async DevServer.runApi (path-to-local-dir) at async Object.fn (path-to-local-dir) at async Router.execute (path-to-local-dir) at async DevServer.run (path-to-local-dir) { page: '/api/room'
Here is what my api file looks like:
export default async function handler(req, res) { if (req.method === "POST") { const options = { method: "POST", headers: { Accept: "application/json", "Content-Type": "application/json", Authorization: `Bearer ${process.env.DAILY_API_KEY}`, }, body: JSON.stringify({ properties: { enable_prejoin_ui: true, enable_network_ui: true, enable_screenshare: true, enable_chat: true, exp: Math.round(Date.now() / 1000) + 300, eject_at_room_exp: true, }, }), }; const dailyRes = await fetch(`${process.env.DAILY_DOMAIN}/rooms`, options); const response = await dailyRes.json(); if (response.error) { return res.status(500).json(response.error); } return res.status(200).json(response); } return res.status(500); }
Please note that the API_KEY and DOMAIN from my env
file is exactly as it is shown here. Can someone help? Thanks in advance
Best Answer
-
Hey @ChrisBB ,
Can you confirm the value of the variable
DAILY_DOMAIN
?In the example from the page you linked, there's a minor difference around the endpoint URL:
const dailyRes = await fetch( `${process.env.DAILY_REST_DOMAIN}/rooms`, options );
In this case, the URL for
DAILY_REST_DOMAIN
would behttps://api.daily.co/v1/
and not the Daily subdomain chosen during account creation.API requests are made to
https://api.daily.co/v1
, while room URLs contain your subdomain.0
Answers
-
@daily_joey - Thanks for the prompt response, and suggestion. I was using
mycompanyname.daily.co
rather thank the one above. The fix is in - thanks. However, I have another issue - there are two instances of the video player. I was expecting just one (please see the attached image)How can I resolve this?
0 -
@ChrisBB it's hard to say without seeing the code for your client implementation but it seems like you might be instantiating the Daily Prebuilt iFrame multiple times unintentionally.
A typical call flow might create the frame and
join()
, then at the end of a sessionleave()
thendestroy()
to clean up the iFrame created by Daily. If you can share a code snippet that includes thecreateFrame
method and how it is called, we can take a look.0 -
Hello @daily_joey , Thanks again for the prompt response. Below is a copy of the code :
import Call from "./Call"; import Home from "./Home"; import { useState } from "react"; export default function ActivePool({ id, isConfigured = false }) { const [room, setRoom] = useState(null); const [expiry, setExpiry] = useState(null); const [callFrame, setCallFrame] = useState(null); return ( <> <div className="min-h-full"> <main className="py-10"> <div className="mx-auto mt-8 grid max-w-3xl grid-cols-1 gap-6 sm:px-6 lg:max-w-7xl lg:grid-flow-col-dense lg:grid-cols-1"> <div className="space-y-6 lg:col-span-2 lg:col-start-1"> {/* Video section*/} <section aria-labelledby="applicant-information-title"> <div className="bg-white shadow sm:rounded-lg"> <div className="border-t border-gray-200 px-4 py-5 sm:px-6"> <dl className="grid grid-cols-1 gap-x-4 gap-y-8 sm:grid-cols-2"> <div className="sm:col-span-2"> <dt className="text-sm font-medium text-gray-500"> About </dt> <dd className="mt-1 text-sm text-gray-900"> {/* Video Lives here */} {room ? ( <Call room={room} expiry={expiry} setRoom={setRoom} setCallFrame={setCallFrame} callFrame={callFrame} /> ) : ( <Home setRoom={setRoom} setExpiry={setExpiry} isConfigured={isConfigured} /> )} </dd> </div> </dl> </div> </div> </section> </div> </div> </main> </div> </> ); }
I'm thinking that it's rendering cos of the Call/Home, but that came from the Next.js snippet from one of your tutorials. Please advice how to restructure this
0 -
Hello @daily_joey , My last question was flagged for some reason, but Tasha from your team unflagged it. Should I expect a response today. Thanks. Also, please keep in mind that I am using NextJS framework. Can you explain how to use the
.join
as I cant find any tutorial on using daily.co with the framework. Thanks in advance.1 -
Your tutorial on this page (https://www.daily.co/blog/use-next-api-routes-to-create-daily-rooms-dynamically/) is poorly written. I am getting an error `ReferenceError: useCallback is not defined` via `components/Call.js` following the steps from the docs. A few other lines of codes could have been written better, more clearly as well. Sorry for venting my frustrations on the thread.
0 -
Along with the above code snippet (march 19th), here is the code for the
Call
component:import { useCallback, useEffect, useRef, useState } from "react"; // import Button from "@custom/shared/components/Button"; // import { // Card, // CardBody, // CardHeader, // CardFooter, // } from "@custom/shared/components/Card"; // import { TextInput } from "@custom/shared/components/Input"; import DailyIframe from "@daily-co/daily-js"; import { writeText } from "clipboard-polyfill"; import ExpiryTimer from "./ExpiryTimer"; const CALL_OPTIONS = { showLeaveButton: true, iframeStyle: { height: "100%", width: "100%", aspectRatio: 16 / 9, minwidth: "400px", maxWidth: "920px", border: "0", borderRadius: "12px", }, }; export function Call({ room, setRoom, callFrame, setCallFrame, expiry }) { const callRef = useRef(null); const [isLinkCopied, setIsLinkCopied] = useState(false); const handleCopyClick = useCallback(() => { writeText(room); setIsLinkCopied(true); setTimeout(() => setIsLinkCopied(false), 5000); }, [room, isLinkCopied]); const createAndJoinCall = useCallback(() => { const newCallFrame = DailyIframe.createFrame( callRef?.current, CALL_OPTIONS ); setCallFrame(newCallFrame); newCallFrame.join({ url: room }); const leaveCall = () => { setRoom(null); setCallFrame(null); callFrame.destroy(); }; newCallFrame.on("left-meeting", leaveCall); }, [room, setCallFrame]); /** * Initiate Daily iframe creation on component render if it doesn't already exist */ useEffect(() => { if (callFrame) return; createAndJoinCall(); }, [callFrame, createAndJoinCall]); return ( <div> <div className="call-container"> {/* Daily iframe container */} <div ref={callRef} className="call" /> <div> <div>Copy and share the URL to invite others</div> <div> <label htmlFor="copy-url"></label> <input type="text" id="copy-url" placeholder="Copy this room URL" value={room} pattern="^(https:\/\/)?[\w.-]+(\.(daily\.(co)))+[\/\/]+[\w.-]+$" /> <button onClick={handleCopyClick}> {isLinkCopied ? "Copied!" : `Copy room URL`} </button> </div> <div> {expiry && ( <div> Room expires in: <ExpiryTimer expiry={expiry} /> </div> )} </div> </div> <style jsx>{` .call-container { display: flex; align-items: center; gap: var(--spacing-md); } .call-container :global(.call) { width: 100%; } .call-container :global(.button) { margin-top: var(--spacing-md); } .call-container :global(.card) { max-width: 300px; max-height: 400px; } .call-container :global(.card-footer) { align-items: center; gap: var(--spacing-xxs); } .call-container :global(.countdown) { position: static; border-radius: var(--radius-sm); } @media only screen and (max-width: 750px) { .call-container { flex-direction: column; } } `}</style> </div> </div> ); } export default Call;
The issue again is that the call video is displaying twice on the page
0 -
Hi @ChrisBB , thanks for the additional code - it looks like everything should be working, so I've asked my teammates to take a look. We'll also work on reviewing the demo you've been referencing, as it's one of our older ones.
1 -
Hello Joey,
Please circle back with response from your team. Thank you for your support
0