POST https://ipfs.infura.io:5001/ipfs/api/v0/add?stream-channels=true&progress=false 403 (Forbidden). HTTPError: ipfs method not supported - reactjs

Below is how i create the client.
import { create as ipfsHttpClient } from 'ipfs-http-client';
const projectId = 'xx';
const projectSecret = 'xx';
const auth = `Basic ${Buffer.from(`${projectId}:${projectSecret}`).toString('base64')}`;
const options = {
host: 'ipfs.infura.io',
protocol: 'https',
port: 5001,
apiPath: '/ipfs/api/v0',
headers: {
authorization: auth,
},
};
const dedicatedEndPoint = 'https://xx.infura-ipfs.io';
const client = ipfsHttpClient(options);
Here is the function that will be called from front-end that takes in a file, uploads to IPFS and returns URL. Please note that the "ipfsHTTPClient()" is just the create function.
const uploadToIPFS = async (file) => {
try {
const added = await client.add({ content: file });
const url = `${dedicatedEndPoint}${added.path}`;
return url;
} catch (error) {
console.log('Error uploading file to IPFS: ', error);
}
};
The error I am getting is
POST https://ipfs.infura.io:5001/ipfs/api/v0/add?stream-channels=true&progress=false 403 (Forbidden)
When i console log the error it says the IPFS method is not supported.
On the IPFS forum, i have seen someone say that add function does not work anymore but i have also seen people using it and it working. Im not sure whats wrong here.
Here is how i call the function on front-end
const { uploadToIPFS } = useContext(NFTContext);
// function called from useDropzone
const onDrop = useCallback(async (acceptedFile) => {
const url = await uploadToIPFS(acceptedFile[0]);
setFileUrl(url);
}, []);

All the above code is correct and the error was from Next.js
Needed to add
images: {
domains: ['xx.infura-ipfs.io'],
},
to the next.config.js file.

I have resolved this problem
so make sure first you have installed buffer
npm install --save buffer
then import it in your file
import {Buffer} from 'buffer';
then it works successfully
import { create } from "ipfs-http-client";
import { Buffer } from "buffer";
const projectId = "YOUR_INFURA_PROJECT_ID";
const projectSecret = "YOUR_INFURA_PROJECT_SECRET";
const auth = `Basic ${Buffer.from(`${projectId}:${projectSecret}`).toString(
"base64"
)}`;
const client = create({
host: "ipfs.infura.io",
port: 5001,
protocol: "https",
apiPath: "/api/v0",
headers: {
authorization: auth,
},
});
const uploadFiles = async (e) => {
e.preventDefault();
setUploading(true);
if (text !== "") {
try {
const added = await client.add(text);
setDescriptionUrl(added.path);
} catch (error) {
toast.warn("error to uploading text");
}
}

Related

Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client in nextJS

The code works properly and redirects to the stripe checkout page but after deployment, it doesn't. I'm getting the status 500 when trying to checkout but the cart items and amount get posted in stripe logs with the status unpaid.
Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
at new NodeError (node:internal/errors:387:5)
at ServerResponse.setHeader (node:_http_outgoing:603:11)
at NodeNextResponse.setHeader (C:\Users\subash\OneDrive\Desktop\ecommerce\ecommerce\node_modules\next\dist\server\base-http\node.js:56:19)
Here's the code
lib/getStripe.js
import {loadStripe} from '#stripe/stripe-js';
let stripePromise;
const getStripe = () => {
if(!stripePromise){
stripePromise = loadStripe(process.env.NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY);
}
return stripePromise;
}
export default getStripe;
cart.js
const handleCheckout = async () => {
const stripe = await getStripe();
const response = await fetch('/api/stripe', {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(cartItems)
});
if (response.statusCode === 500) return;
const data = await response.json();
toast.loading("Redirecting...");
stripe.redirectToCheckout({ sessionId: data.id });
};
pages/api/stripe.js
import Stripe from 'stripe';
const stripe = new Stripe(process.env.NEXT_PUBLIC_STRIPE_SECRET_KEY);
export default async function handler(req, res) {
if (req.method === 'POST') {
try {
// Create Checkout Sessions from body params.
const params = {
submit_type :'pay',
mode:'payment',
payment_method_types:['card'],
shipping_address_collection: {
allowed_countries: ['IN'],
},
shipping_options: [
{shipping_rate: '...'}
],
line_items: req.body.map((item)=>{
const img = item.image[0].asset._ref;
const newImage = img.replace('image-','https://cdn.sanity.io/..../').replace('-webp','.webp');
return {
price_data:{
currency:'inr',
product_data:{
name:item.name,
images:[newImage],
},
unit_amount:item.price*100,
},
adjustable_quantity:{
enabled:true,
minimum:1
},
quantity:item.quantity
}
}),
success_url: `${req.headers.origin}/success`,
cancel_url: `${req.headers.origin}`,
}
const session = await stripe.checkout.sessions.create(params);
res.status(200).json(session);
res.redirect(303, session.url);
} catch (err) {
res.status(err.statusCode || 500).json(err.message);
}
} else {
res.setHeader('Allow', 'POST');
console.log("error");
res.status(405).end('Method Not Allowed');
}
}
You're still using the legacy Checkout integration with redirectToCheckout instead you should look at the new integration path for Next.js that you can find here. If you want more info about migrating from the legacy integration you can check the Checkout migration guide here.

Why does my API return "You are not subscribed to this APi" even with the X-RapidAPI-Key?

The link to my rapidAPI is below
https://rapidapi.com/ytdlfree/api/youtube-v31?utm_source=youtube.com%2FJavaScriptMastery
This is my RAPID API code:
import axios from "axios";
const BASE_URL = 'https://youtube-v31.p.rapidapi.com';
const options = {
params: {
maxResults: '50'
},
headers: {
'X-RapidAPI-Key': process.env.REACT_APP_RAPID_API_KEY,
'X-RapidAPI-Host': 'youtube-v31.p.rapidapi.com'
}
};
export const fetchFromAPI = async(url) =>{
const { data } = await axios.get(`${BASE_URL}/${url}`, options);
return data;
}
This is for fetching the data:
import { fetchFromAPI } from '../utils/fetchFromAPI';
const Feed = () => {
const [selectedCategory, setSelectedCategory] = useState('New');
const [videos, setVideos] = useState([]);
useEffect (() =>{
fetchFromAPI(`search?part=snippet&q=${selectedCategory}`)
.then((data) => setVideos(data.items))
.catch(error => {
if (error.response) {
// Request made but the server responded with an error
console.log(error.response.data);
console.log(error.response.status);
console.log(error.response.headers);
} else if (error.request) {
// Request made but no response is received from the server.
console.log(error.request);
} else {
// Error occured while setting up the request
console.log('Error', error.message);
}
});
I saved my API key to the .env file at the root directory of this application but it kept showing message:
You are not subscribed to this API
[[Prototype]]
Object
How can I solve this?
First you need to subscribe API key..
Second , use env variable like this ..
**REACT_APP_RAPID_API_KEY = '9fbc4844e8msfdf8absdzgd3ffp182459jsdfdsf909d079cdds'**
don't put semicolon or anything at the end of env variable like this ..
REACT_APP_RAPID_API_KEY = '9fbc4844e8msfdf8absdzgd3ffp182459jsdfdsf909d079cdds';
Also , try to log the env variable in the console like ..
console.log(process.env.REACT_APP_RAPID_API_KEY);
try to restart the server after changing env file ...
yarn start / npm start

Axios mock adapter server returns a 404 ERROR

I have data in a local JSON file; to query that data, I'm using axios-mock-adapter. But for some reason, it's giving 404 not found. Not sure what I'm missing
Exact error: GET http://localhost:3000/api/results 404 (Not Found)
I have created a db folder with all the files below.
mock.js file
const MockAdapter = require('axios-mock-adapter');
const axios = require('axios');
const Mock = new MockAdapter(axios.create());
export default Mock;
index.js file
import Mock from './mock';
import './db/database';
Mock.onAny().passThrough();
database.js file
import Mock from "../mock";
const database = {
results: {
books: [
name: "loren ipsum",
],
},
};
Mock.onGet("/api/results").reply((config) => {
const response = database.results;
console.log("mock results", response);
return [200, response];
});
and then in my components:
I am querying it like this:
const [books, setBooks] = useState([]);
useEffect(() => {
async function fetchData() {
const request = await axios.get("/api/results").then((response) => {
console.log("res", response.data);
console.log("request", request);
setBooks(request);
});
return request;
}
fetchData();
}, []);

You did not provide an API key. You need to provide your API key in the Authorization header

im getting this error when i try to use the my checkout function using Stripe:
You did not provide an API key. You need to provide your API key in the Authorization header, using Bearer auth (e.g. 'Authorization: Bearer YOUR_SECRET_KEY'). See https://stripe.com/docs/api#authentication for details, or we can help at https://support.stripe.com/.
I also tried to use a if check to check for the stripe key, but i got an error that said the key did not exist .
checkout function:
const handleCheckOut = async () => {
const stripe = await getStripe();
const response = await fetch("/api/stripe", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.STRIPE_SECRET_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify(cartItems),
});
if (response.statusCode === 500) return;
const data = await response.json();
toast.loading("Redirecting...");
stripe.redirectToCheckout({ sessionId: data.id });
};
Even though im passing the Stripe api secret key as Authorization header it is still not woking
getStripe.js
import { loadStripe } from "#stripe/stripe-js";
let stripePromise;
const getStripe = () => {
if (!stripePromise) {
stripePromise = loadStripe(`${process.env.STRIPE_PUBLIC_KEY}`);
}
return stripePromise;
};
export default getStripe;
api/stripe.js
import Stripe from "stripe";
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY);
export default async function handler(req, res) {
console.log(req.body.cartItems);
if (req.method === "POST") {
try {
const params = {
submit_type: "pay",
mode: "payment",
payment_method_type: ["card"],
billing_address_collection: "auto",
// formas de envio
shipping_options: [
{ shipping_rate: "shr_1LJo2EHt0s8JSRoPQEDeHfo5" },
{ shipping_rate: "shr_1LJo3ZHt0s8JSRoP8uVNJhwS" },
],
line_items: req.body.map((item) => {
const img = item.image[0].asset._ref;
const newImage = img
.replace(
"image-",
"https://cdn.sanity.io/images/psdgq2wv/production/"
)
.replace("-webp", ".webp");
return {
price_data: {
currency: "usd",
product_data: {
name: item.name,
images: [newImage],
},
unit_amount: item.price * 100,
adjustable_quantity: {
enabled: true,
minimum: 1,
},
quantity: item.quantity,
},
};
}),
// success_url: `${req.headers.origin}/?success=true`,
// cancel_url: `${req.headers.origin}/?canceled=true`,
};
// Create Checkout Sessions from body params.
const session = await stripe.checkout.sessions.create(params);
res.status(200).json(session);
} catch (err) {
res.status(err.statusCode || 500).json(err.message);
}
} else {
res.setHeader("Allow", "POST");
res.status(405).end("Method Not Allowed");
}
}
I do not think that you need to send this: Authorization: Bearer ${process.env.STRIPE_SECRET_KEY},. I think the issue is here
const getStripe = () => {
if (!stripePromise) {
stripePromise = loadStripe(`${process.env.STRIPE_PUBLIC_KEY}`);
}
return stripePromise;
};
since you are on client side, process.env.STRIPE_PUBLIC_KEY will be undefined. because by default environment variables from .env files load to server. check this out: whats-the-difference-between-exposing-environment-variables-in-nextjs-through
You have to define your env variable
NEXT_PUBLIC_STRIPE_API_KEY=xxxxxxxxxxxxxxx
then use it in getStripe:
stripePromise = loadStripe(process.env.NEXT_PUBLIC_STRIPE_API_KEY);

How to handle error format in Redux-toolkit rtk-query graphql application

I'm developing an application based on redux-toolkit rtk-query and graphql.
I use graphql-codegen to generate the reducers starting from the graphql schema and everything working as expected.
Now i have a problem to handle errors. Has i understand redux-toolkit raise custom error with a specific format like this
{
name: "Error",
message: "System error",
stack:
'Error: System error: {"response":{"errors":[{"message":"System error","locations":[{"line":3,"column":3}],"path":["completaAttivita"],"extensions":{"errorCode":505,"classification":"VALIDATION","errorMessage":"Messaggio di errore","verboseErrorMessage":"it.cmrc.sid.backend.exception.CustomException: I riferimenti contabili non sono piĆ¹ validi","causedBy":"No Cause!"}}],"data":{"completaAttivita":null},"status":200,"headers":{"map":{"content-length":"398","content-type":"application/json"}}},"request":{"query":"\\n mutation completaAttivita($taskName: TipoAttivita, $taskId: String, $determinaId: BigInteger, $revisione: Boolean, $nota: NotaInputInput, $avanzaStatoDetermina: Boolean, $attribuzioniOrizzontali: AttribuzioniOrizzontaliInputInput, $firmaInput: FirmaInputInput, $roles: [String]) {\\n completaAttivita(\\n taskName: $taskName\\n taskId: $taskId\\n determinaId: $determinaId\\n revisione: $revisione\\n nota: $nota\\n avanzaStatoDetermina: $avanzaStatoDetermina\\n attribuzioniOrizzontali: $attribuzioniOrizzontali\\n firmaInput: $firmaInput\\n roles: $roles\\n ) {\\n id\\n }\\n}\\n ","variables":{"taskId":"24ac495b-46ca-42f4-9be2-fd92f0398114","determinaId":1342,"taskName":"firmaDirigente","firmaInput":{"username":"fdfs","password":"fdsf","otp":"fdsdf"}}}}\n at eval (webpack-internal:///../../node_modules/graphql-request/dist/index.js:354:31)\n at step (webpack-internal:///../../node_modules/graphql-request/dist/index.js:63:23)\n at Object.eval [as next] (webpack-internal:///../../node_modules/graphql-request/dist/index.js:44:53)\n at fulfilled (webpack-internal:///../../node_modules/graphql-request/dist/index.js:35:58)'
};
But my graphql endpoint return this
{
errors: [
{
message: "System error",
locations: [{ line: 3, column: 3 }],
path: ["completaAttivita"],
extensions: {
errorCode: 505,
classification: "VALIDATION",
errorMessage: "Messaggio di errore",
verboseErrorMessage:
"it.cmrc.sid.backend.exception.CustomException: Messaggio di errore",
causedBy: "No Cause!"
}
}
],
data: { completaAttivita: null }
};
Using rtk-query and the autogenerated client i have no access to the complete response from server.
And i need to extract the error messagge in the exceptions object.
From redix-toolkit documentation i understand that i need to catch the error and call rejectwithvalue() from a createAsyncThunk but i dont'undertand of to do that.
Here the base api object
import { createApi } from '#reduxjs/toolkit/query/react';
import { graphqlRequestBaseQuery } from './base-request';
import { GraphQLClient } from 'graphql-request';
import { getSession } from 'next-auth/react';
export const client = new GraphQLClient(
`${process.env.NEXT_PUBLIC_API_URL}/graphql`,
{
credentials: 'same-origin',
headers: {
Accept: 'application/json'
}
}
);
export const api = createApi({
baseQuery: graphqlRequestBaseQuery({
client,
prepareHeaders: async (headers, { getState }) => {
const session = await getSession();
if (session) {
headers.set('Authorization', `Bearer ${session?.access_token}`);
}
return headers;
}
}),
endpoints: () => ({}),
refetchOnMountOrArgChange: true
});
Thanks to #phry for merge my solution.
#rtk-query/graphql-request-base-query (version > 2.1.0) introduce a new configuration to handle errors format. Here a small explanation.
Typization
graphqlRequestBaseQuery<CustomErrorFormat>
Custom Error handler
...
customErrors: (props: ClientError) => CustomErrorFormat
...
Full example https://codesandbox.io/s/headless-microservice-uzujqb?file=/src/App.tsx
import { createApi } from '#reduxjs/toolkit/query/react';
import { graphqlRequestBaseQuery } from '#rtk-query/graphql-request-base-query';
import { ClientError, GraphQLClient } from 'graphql-request';
import { getSession } from 'next-auth/react';
export const client = new GraphQLClient(
`${process.env.NEXT_PUBLIC_API_URL}/graphql`,
{
credentials: 'same-origin',
headers: {
Accept: 'application/json'
}
}
);
export const api = createApi({
baseQuery: graphqlRequestBaseQuery<
Partial<ClientError & { errorCode: number }>
>({
client,
prepareHeaders: async (headers, { getState }) => {
const session = await getSession();
if (session) {
headers.set('Authorization', `Bearer ${session?.access_token}`);
}
return headers;
},
customErrors: ({ name, stack, response }) => {
const { errorMessage = '', errorCode = 500 } = response?.errors?.length
? response?.errors[0]?.extensions
: {};
return {
name,
message: errorMessage,
errorCode,
stack
};
}
}),
endpoints: () => ({}),
refetchOnMountOrArgChange: true
});
You can always write a wrapper around your baseQuery to reformat it:
const originalBaseQuery = graphqlRequestBaseQuery(...)
const wrappedBaseQuery = async (...args) => {
const result = await originalBaseQuery(...args);
if (result.error) {
// modify `result.error` here however you want
}
return result
}
It could also be necessary that you need to try..catch for that:
const originalBaseQuery = graphqlRequestBaseQuery(...)
const wrappedBaseQuery = async (...args) => {
try {
return await originalBaseQuery(...args);
} catch (e) {
// modify your error here
return { error: e.foo.bar }
}
}
I think this just slipped by when I was writing graphqlRequestBaseQuery and so far nobody has asked about it. If you have found a nice pattern of handling this, a pull request against graphqlRequestBaseQuery would also be very welcome.

Resources