Is there any way to go around cors?

Do i really need cors, can i just not use it, if so, how?

It’s a browser feature, you can probably disable it but it would be only for your browser, not for your users.

To solve CORS you have to make your API accept requests coming from the domain of your project (weweb domain while editing or using preview, your domain once published).

If you don’t have the hand on the API and the service don’t provide a way to enter a kind of domain whitelist, then you can still use our proxy toggle on collection and rest api action, we will perform the request server side to bypass CORS.

But be aware, if you have a CORS issue and can’t resolve it through an API/service configuration, it probably mean the API is not made to be accessed from a browser/frontend.
If the API require a private api key to be accessed, then you shouldn’t made the request from your frontend at all.

Okey, it has to work for all browser, to explain my case in short i have weweb as front end, supabase as back end, and a script that is deployed as an edge function in supabase. I have cors headers in this script:

‘Access-Control-Allow-Origin’: ‘https://editor.weweb.io’,
‘Access-Control-Allow-Methods’: ‘POST, OPTIONS’,
‘Access-Control-Allow-Headers’: ‘Content-Type, Authorization’,

So its ment for the development mode first, and then I’ll change it to my custom domain later

I ran this same script in my CLI with the open ai API and it worked fine so i know that the connection is working, its just when trying to access it using weweb i have this issue and looks like it is the cors thing.

Anything odd or specific you see or notice that is worng?

Please share the part of the code in your edge function where you are returning the CORS headers

Most of the time the issue is the code doesn’t not return the headers for the “OPTIONS” request method for exemple.

Here it is:

async function handler(req: Request): Promise<Response> {
  if (req.method === 'OPTIONS') {
    // Handle CORS preflight requests
    return new Response(null, {
      status: 204,
      headers: {
        'Access-Control-Allow-Origin': 'https://cdn.weweb.io/components/',
        'Access-Control-Allow-Methods': 'POST, OPTIONS',
        'Access-Control-Allow-Headers': 'Content-Type, Authorization',
      },
    });
  }

It should be https://editor.weweb.io to make your request work in the editor

And for the published one, if you don’t have any domain attached yet, you should also add https://<project-id>.weweb-preview.io

Like this: ‘Access-Control-Allow-Origin’: ‘https://cdn.weweb.io/components/, https://.weweb-preview.io’,

I’m still expiriencing the same issue after deploying the edge function again to supabase

anything wrong you can see in this screenshot of my invoke edge function?

You added https://cdn.weweb.io/components/

as I said, it should be https://editor.weweb.io

I tried that now, i’m still getting this error: message: “Failed to send a request to the Edge Function”

Can you open the console and share the error message please ? The issue should be explained inside

(not the network tab, the console, you should have a message containing something like “has been blocked by CORS policy”)

From what I see on the documentation the CORS headers should be returned for both the OPTIONS response and for the final response

As I don’t have the whole code I’m not sure you’re also returning the CORS headers in the final response

Okey

This is from the console:

This is the code in the index.ts file

import { serve } from './deps.ts';
import { Configuration, OpenAIApi } from './deps.ts';

// Initialize the OpenAI API client with the API key from environment variables
const configuration = new Configuration({
  apiKey: Deno.env.get('OPENAI_API_KEY'),
});
const openai = new OpenAIApi(configuration);

// Define the handler function for incoming HTTP requests
async function handler(req: Request): Promise<Response> {
  if (req.method === 'OPTIONS') {
    // Handle CORS preflight requests
    return new Response(null, {
      status: 204,
      headers: {
        'Access-Control-Allow-Origin': 'https://editor.weweb.io, https://.weweb-preview.io',
        'Access-Control-Allow-Methods': 'POST, OPTIONS',
        'Access-Control-Allow-Headers': 'Content-Type, Authorization',
      },
    });
  }

  if (req.method !== 'POST') {
    return new Response('Method Not Allowed', { status: 405 });
  }

  try {
    // Hardcoding the image URL as per your instruction
    const imageUrl = "https://i.imgur.com/dzb3jEc.png";

    const requestBody = {
      model: "gpt-4o",
      messages: [
        {
          role: "user",
          content: [
            { type: "text", text: "What’s in this image?" },
            {
              type: "image_url",
              image_url: { url: imageUrl }
            }
          ]
        }
      ]
    };

    const response = await fetch('https://api.openai.com/v1/chat/completions', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'Authorization': `Bearer ${Deno.env.get('OPENAI_API_KEY')}`,
      },
      body: JSON.stringify(requestBody),
    });

    if (!response.ok) {
      const errorDetails = await response.text();
      return new Response(`Failed to analyze the image: ${response.status} ${response.statusText} - ${errorDetails}`, { 
        status: 500,
        headers: {
          'Access-Control-Allow-Origin': '*',
          'Content-Type': 'application/json',
        },
      });
    }

    const responseData = await response.json();
    const result = responseData.choices[0].message.content;

    // Prettify the result
    const prettifiedResult = result.split('\n').map(line => line.trim()).join('\n');

    return new Response(JSON.stringify({ result: prettifiedResult }), {
      status: 200,
      headers: {
        'Access-Control-Allow-Origin': '*',
        'Content-Type': 'application/json',
      },
    });
  } catch (error) {
    return new Response(`Failed to analyze the image: ${error.message}`, {
      status: 500,
      headers: {
        'Access-Control-Allow-Origin': '*',
        'Content-Type': 'application/json',
      },
    });
  }
}

// Start the server and listen for requests
serve(handler);

The message is saying you have two values but only one is allowed.

So you can try to keep only https://editor.weweb.io and it should works for the editor.

As you also need to authorise the published app you may prefer use the ‘*’ instead of specifying a domain. This is what you’re doing in the response headers below.

You also need to add the 'Access-Control-Allow-Headers': 'Content-Type, Authorization', line in your headers response, it’s missing

return new Response(JSON.stringify({ result: prettifiedResult }), {
      status: 200,
      headers: {
        'Access-Control-Allow-Origin': '*',
        'Content-Type': 'application/json',
        // MISSING Access-Control-Allow-Headers
      },
    });

I changed it to this now ‘Access-Control-Allow-Origin’: ‘*’

I’m not following 100% on the second part

this is my current code it has the Access-Control-Allow-Origin, Access-Control-Allow-Methods and Access-Control-Allow-Headers. It has the Access-Control-Allow-Headers with content-type and Auth

but not the: ‘Content-Type’: ‘application/json’, that you are providing above, is that the only line I need to add to my current code?

return new Response(null, {
      status: 204,
      headers: {
        'Access-Control-Allow-Origin': '*',
        'Access-Control-Allow-Methods': 'POST, OPTIONS',
        'Access-Control-Allow-Headers': 'Content-Type, Authorization',
      },
    });

This is the Response to the OPTIONS request, but you also have to add it on the Response of the POST request, and in the Response in the catch too.

Every time you create a new Response, you should add the same CORS headers

If you search “new Response” in your code, you have 5 lines where you create a Response, but only the first one has the correct headers with the ‘Access-Control-Allow-Headers’

Okey, that makes sense

I’ve added the ACAH header now to the ones missing it

import { serve } from './deps.ts';
import { Configuration, OpenAIApi } from './deps.ts';

// Initialize the OpenAI API client with the API key from environment variables
const configuration = new Configuration({
  apiKey: Deno.env.get('OPENAI_API_KEY'),
});
const openai = new OpenAIApi(configuration);

// Define the handler function for incoming HTTP requests
async function handler(req: Request): Promise<Response> {
  if (req.method === 'OPTIONS') {
    // Handle CORS preflight requests
    return new Response(null, {
      status: 204,
      headers: {
        'Access-Control-Allow-Origin': '*',
        'Access-Control-Allow-Methods': 'POST, OPTIONS',
        'Access-Control-Allow-Headers': 'Content-Type, Authorization',
      },
    });
  }

  if (req.method !== 'POST') {
    return new Response('Method Not Allowed', { status: 405 });
  }

  try {
    // Hardcoding the image URL as per your instruction
    const imageUrl = "https://i.imgur.com/dzb3jEc.png";

    const requestBody = {
      model: "gpt-4o",
      messages: [
        {
          role: "user",
          content: [
            { type: "text", text: "What’s in this image?" },
            {
              type: "image_url",
              image_url: { url: imageUrl }
            }
          ]
        }
      ]
    };

    const response = await fetch('https://api.openai.com/v1/chat/completions', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'Authorization': `Bearer ${Deno.env.get('OPENAI_API_KEY')}`,
        'Access-Control-Allow-Headers': 'Content-Type, Authorization',
      },
      body: JSON.stringify(requestBody),
    });

    if (!response.ok) {
      const errorDetails = await response.text();
      return new Response(`Failed to analyze the image: ${response.status} ${response.statusText} - ${errorDetails}`, { 
        status: 500,
        headers: {
          'Access-Control-Allow-Origin': '*',
          'Content-Type': 'application/json',
          'Access-Control-Allow-Headers': 'Content-Type, Authorization',
        },
      });
    }

    const responseData = await response.json();
    const result = responseData.choices[0].message.content;

    // Prettify the result
    const prettifiedResult = result.split('\n').map(line => line.trim()).join('\n');

    return new Response(JSON.stringify({ result: prettifiedResult }), {
      status: 200,
      headers: {
        'Access-Control-Allow-Origin': '*',
        'Content-Type': 'application/json',
        'Access-Control-Allow-Headers': 'Content-Type, Authorization',
      },
    });
  } catch (error) {
    return new Response(`Failed to analyze the image: ${error.message}`, {
      status: 500,
      headers: {
        'Access-Control-Allow-Origin': '*',
        'Content-Type': 'application/json',
        'Access-Control-Allow-Headers': 'Content-Type, Authorization',
      },
    });
  }
}

// Start the server and listen for requests
serve(handler);

But still getting the same error

It’s not the same error as you can read it. It say “x-client-info” is not allowed by your “Access-Control-Allow-Headers” header, you can try to add it.

You have the recommended setup provided by the supabase documentation

Now its working, it was the ACAH: needed to contain: Auth, x client, apikey and content type,

Thanks for the help and the patient @Alexis

1 Like