Uncaught (in promise) AxiosError {message: 'Request failed with status code 400', name: 'AxiosError', code: 'ERR_BAD_REQUEST - axios

I've followed the alchemy NFT marketplace course (https://www.youtube.com/watch?v=y6JfVdcJh1k&t=262s and https://github.com/alchemyplatform/RTW3-Week7-NFT-Marketplace) successfully but somehow the app stopped working and I am now getting an axis error which appears to be coming from the axios get request for the NFT tokenURI (IPFS pinata link containing the NFT metadata) in Marketplace.js coming from the line:
let meta = await axios.get(tokenURI);
I have been looking for a solution for two days and can not figure out why it is not working anymore. Any assistance would be greatly appreciated.
I am getting the below error:
https://gateway.pinata.cloud/ipfs/QmVEA6DxgG6QiPB56E6gP6V7AfeF5D82TXrNML7fzSFPV5
Marketplace.js:69
xhr.js:220 GET https://gateway.pinata.cloud/ipfs/QmVEA6DxgG6QiPB56E6gP6V7AfeF5D82TXrNML7fzSFPV5 400
dispatchXhrRequest # xhr.js:220
xhrAdapter # xhr.js:16
dispatchRequest # dispatchRequest.js:58
request # Axios.js:109
Axios.<computed> # Axios.js:131
wrap # bind.js:9
(anonymous) # Marketplace.js:70
await in (anonymous) (async)
getAllNFTs # Marketplace.js:63
await in getAllNFTs (async)
Marketplace # Marketplace.js:95
renderWithHooks # react-dom.development.js:16305
mountIndeterminateComponent # react-dom.development.js:20074
beginWork # react-dom.development.js:21587
beginWork$1 # react-dom.development.js:27426
performUnitOfWork # react-dom.development.js:26557
workLoopSync # react-dom.development.js:26466
renderRootSync # react-dom.development.js:26434
performSyncWorkOnRoot # react-dom.development.js:26085
flushSyncCallbacks # react-dom.development.js:12042
(anonymous) # react-dom.development.js:25651
Marketplace.js:91 Uncaught (in promise) AxiosError {message: 'Request failed with status code 400', name: 'AxiosError', code: 'ERR_BAD_REQUEST', config: {…}, request: XMLHttpRequest, …}
getAllNFTs # Marketplace.js:91
await in getAllNFTs (async)
Marketplace # Marketplace.js:95
renderWithHooks # react-dom.development.js:16305
mountIndeterminateComponent # react-dom.development.js:20074
beginWork # react-dom.development.js:21587
beginWork$1 # react-dom.development.js:27426
performUnitOfWork # react-dom.development.js:26557
workLoopSync # react-dom.development.js:26466
renderRootSync # react-dom.development.js:26434
performSyncWorkOnRoot # react-dom.development.js:26085
flushSyncCallbacks # react-dom.development.js:12042
(anonymous) # react-dom.development.js:25651
xhr.js:220 GET https://gateway.pinata.cloud/ipfs/QmVEA6DxgG6QiPB56E6gP6V7AfeF5D82TXrNML7fzSFPV5 400
dispatchXhrRequest # xhr.js:220
xhrAdapter # xhr.js:16
dispatchRequest # dispatchRequest.js:58
request # Axios.js:109
Axios.<computed> # Axios.js:131
wrap # bind.js:9
(anonymous) # Marketplace.js:70
await in (anonymous) (async)
getAllNFTs # Marketplace.js:63
await in getAllNFTs (async)
Marketplace # Marketplace.js:95
renderWithHooks # react-dom.development.js:16305
mountIndeterminateComponent # react-dom.development.js:20145
beginWork # react-dom.development.js:21587
beginWork$1 # react-dom.development.js:27426
performUnitOfWork # react-dom.development.js:26557
workLoopSync # react-dom.development.js:26466
renderRootSync # react-dom.development.js:26434
performSyncWorkOnRoot # react-dom.development.js:26085
flushSyncCallbacks # react-dom.development.js:12042
(anonymous) # react-dom.development.js:25651
Marketplace.js:91 Uncaught (in promise) AxiosError {message: 'Request failed with status code 400', name: 'AxiosError', code: 'ERR_BAD_REQUEST', config: {…}, request: XMLHttpRequest, …}
See below the code from the Marketplace.js file:
import Navbar from "./Navbar";
import NFTTile from "./NFTTile";
// import MarketplaceJSON from "../Marketplace_goerli.json";
import MarketplaceJSON from "../Marketplace_localhost.json";
import axios from "axios";
import { useState } from "react";
export default function Marketplace() {
const sampleData = [
{
name: "NFT#1",
description: "Alchemy's First NFT",
website: "http://axieinfinity.io",
image:
"https://gateway.pinata.cloud/ipfs/QmTsRJX7r5gyubjkdmzFrKQhHv74p5wT9LdeF1m3RTqrE5",
price: "0.03ETH",
currentlySelling: "True",
address: "0xe81Bf5A757CB4f7F82a2F23b1e59bE45c33c5b13",
},
{
name: "NFT#2",
description: "Alchemy's Second NFT",
website: "http://axieinfinity.io",
image:
"https://gateway.pinata.cloud/ipfs/QmdhoL9K8my2vi3fej97foiqGmJ389SMs55oC5EdkrxF2M",
price: "0.03ETH",
currentlySelling: "True",
address: "0xe81Bf5A757C4f7F82a2F23b1e59bE45c33c5b13",
},
{
name: "NFT#3",
description: "Alchemy's Third NFT",
website: "http://axieinfinity.io",
image:
"https://gateway.pinata.cloud/ipfs/QmTsRJX7r5gyubjkdmzFrKQhHv74p5wT9LdeF1m3RTqrE5",
price: "0.03ETH",
currentlySelling: "True",
address: "0xe81Bf5A757C4f7F82a2F23b1e59bE45c33c5b13",
},
];
const [data, updateData] = useState(sampleData);
const [dataFetched, updateFetched] = useState(false);
async function getAllNFTs() {
const ethers = require("ethers");
//After adding your Hardhat network to your metamask, this code will get providers and signers
const provider = new ethers.providers.Web3Provider(window.ethereum);
const signer = provider.getSigner();
//Pull the deployed contract instance
let contract = new ethers.Contract(
MarketplaceJSON.address,
MarketplaceJSON.abi,
signer
);
//create an NFT Token
let transaction = await contract.getAllNFTs();
//Fetch all the details of every NFT from the contract and display
const items = await Promise.all(
transaction.map(async (i) => {
const tokenURI = await contract.tokenURI(i.tokenId);
console.log(tokenURI);
let meta = await axios.get(tokenURI);
meta = meta.data;
console.log(` The tokenURI metadata are: ${meta}`);
let price = ethers.utils.formatUnits(i.price.toString(), "ether");
let item = {
price,
tokenId: i.tokenId.toNumber(),
seller: i.seller,
owner: i.owner,
image: meta.image,
name: meta.name,
description: meta.description,
};
return item;
})
);
updateFetched(true);
updateData(items);
}
if (!dataFetched) getAllNFTs();
return (
<div>
<Navbar></Navbar>
<div className="flex flex-col place-items-center mt-20">
<div className="md:text-xl font-bold text-white">Top NFTs</div>
<div className="flex mt-5 justify-between flex-wrap max-w-screen-xl text-center">
{data.map((value, index) => {
return <NFTTile data={value} key={index}></NFTTile>;
})}
</div>
</div>
</div>
);
}

the error might be related to this: how-to-fix-400-errors-with-dedicated-gateways
when you make a request to pinata you have to add this header:
const res = await axios.get(tokenURI, {
headers: {
'Accept': 'text/plain'
}
})

Related

Vite not resolving file path when passed into function

I am using Vite to bundle an application, and in the index.html of one of my subpages, I have a function as follows:
var scriptTag = document.createElement("script");
scriptTag.src = "main.dart.js"; // change to app
scriptTag.type = "application/javascript"; // change to app
document.body.append(scriptTag);
Which gives the following error in the web console:
http://localhost:5000/app/main.dart.js net::ERR_ABORTED 404 (Not Found)
n # app.e9ec45f4.js:1
(anonymous) # app.e9ec45f4.js:1
setTimeout (async)
(anonymous) # app.e9ec45f4.js:1
load (async)
(anonymous) # app.e9ec45f4.js:1
Vite is not resolving this paths. I am assuming this is because Vite recognizes them as string inputs to a function and not a reference to a file. Is there any way to get Vite to resolve paths that are used in non-import functions?
Below are the relevant files in my directory structure:
src:
- index.html
- app:
- index.html
- main.dart.js
Here is my vite.config.js:
export default defineConfig({
root: "src",
publicDir: "../public",
build: {
emptyOutDir: true,
outDir: "../dist/web",
rollupOptions: {
input: {
main: "src/index.html",
app: "src/app/index.html",
},
external: ["assets", "splash/style.css"],
},
// optimizeDeps: {
// exclude: ["app/flutter_service_worker.js"],
// },
},
resolve: {
alias: {
vue: "vue/dist/vue.esm-bundler.js",
},
},
define: {
"process.env": process.env,
},
plugins: [
VitePWA({
strategies: "injectManifest",
srcDir: "app",
filename: "flutter_service_worker.js",
injectRegister: "null",
}),
],
});
Thanks

ApiGateway: Only one base path mapping is allowed if the base path is empty

Creating an API Gateway I get this error:
api-mapping (apimappingXXXXXXX) Only one base path mapping is allowed
if the base path is empty. (Service: AmazonApiGateway; Status Code:
409; Error Code: ConflictException;
where my code is:
// External API Gateway
const externalApi = new apigateway.RestApi(this, 'external-api-gw',
{
apiKeySourceType: apigateway.ApiKeySourceType.AUTHORIZER,
restApiName: 'external-api',
deploy: false,
endpointConfiguration: {
...
},
policy: new iam.PolicyDocument({
statements: [
..
],
}),
]
})
}
);
const domainName = externalApi.addDomainName('domain-name', {
domainName: props.apigatewayRecordName + '.' + props.hostedZone,
certificate: existingCertificate,
endpointType: apigateway.EndpointType.REGIONAL,
});
const myApiGateway = new route53targets.ApiGateway(externalApi);
// deployment
const apiDeployment = new apigateway.Deployment(this, 'deployment', {
api: externalApi
});
// stage
const apiStage = new apigateway.Stage(this, 'stage', {
stageName: 'api',
accessLogDestination: new apigateway.LogGroupLogDestination(logGroup),
accessLogFormat: apigateway.AccessLogFormat.jsonWithStandardFields(),
loggingLevel: apigateway.MethodLoggingLevel.INFO,
dataTraceEnabled: true,
deployment: apiDeployment
});
externalApi.deploymentStage = apiStage;
domainName.addBasePathMapping(externalApi, { basePath: 'api', stage: apiStage} );
It seems that an empty base path mapping is created automatically and the second one cannot be added.
Any suggestions, please?
As mentioned in comments, Below you can find the working code snippet:
Create CfnDomainName:
// import relevant data from ssm
const certificateArn = ssm.StringParameter.valueFromLookup(this, 'CertificateArn');
const domainNameURL = ssm.StringParameter.valueFromLookup(this, 'ApiCustomDomainUrl');
const certificate = cert.Certificate.fromCertificateArn(this, 'Certificate', certificateArn);
// create DomainName
const domainName = new apigateway.DomainName(this, 'DomainName', {
domainName: domainNameURL,
certificate: certificate ,
endpointType: apigateway.EndpointType.REGIONAL,
});
Add base path mapping:
// create the api
const api = new apigateway.RestApi(this, id, {
restApiName: 'API GW ' + id,
deployOptions: {
stageName: 'dev',
},
endpointTypes: [apigateway.EndpointType.REGIONAL]
});
// add new base path to domain name
new apigateway.BasePathMapping(this, 'my-mapping', {
domainName: domainName,
restApi: api,
basePath: 'my-mapping'
});
// add new base path to domain name
new apigateway.BasePathMapping(this, 'my-mapping-two', {
domainName: domainName,
restApi: api,
basePath: 'my-mapping-two'
});
More about BasePathMapping , DomainName.
Not sure if something changed over the versions, but this does not work with 1.57 of the CDK.
Will generate: "Error: API does not define a default name"

Serverless Framework and DynamoDB: Unexpected token in JSON at JSON.parse

Hi I followed this Serverless + AWS REST API tutorial and it went great, I got it to work.
Now, I'm trying to modify it but have hit a wall while trying to submit data into the DynamoDB table.
Using Postman to submit a valid JSON object I get a 502 response. If I test the function in Lambda, I get the following error:
{
"errorType": "SyntaxError",
"errorMessage": "Unexpected token o in JSON at position 1",
"trace": [
"SyntaxError: Unexpected token o in JSON at position 1",
" at JSON.parse (<anonymous>)",
" at Runtime.module.exports.submit [as handler] (/var/task/api/interview.js:11:28)",
" at Runtime.handleOnce (/var/runtime/Runtime.js:66:25)",
" at process._tickCallback (internal/process/next_tick.js:68:7)"
]
}
After searching for solutions, what I found out is that it seem like the event that is being passed as JSON.parse(event)is undefined.
Here's the serverless.yml:
service: interview
frameworkVersion: ">=1.1.0 <2.0.0"
provider:
name: aws
runtime: nodejs10.x
stage: dev
region: us-east-1
environment:
INTERVIEW_TABLE: ${self:service}-${opt:stage, self:provider.stage}
INTERVIEW_EMAIL_TABLE: "interview-email-${opt:stage, self:provider.stage}"
iamRoleStatements:
- Effect: Allow
Action:
- dynamodb:Query
- dynamodb:Scan
- dynamodb:GetItem
- dynamodb:PutItem
Resource: "*"
resources:
Resources:
CandidatesDynamoDbTable:
Type: 'AWS::DynamoDB::Table'
DeletionPolicy: Retain
Properties:
AttributeDefinitions:
-
AttributeName: "id"
AttributeType: "S"
KeySchema:
-
AttributeName: "id"
KeyType: "HASH"
ProvisionedThroughput:
ReadCapacityUnits: 1
WriteCapacityUnits: 1
StreamSpecification:
StreamViewType: "NEW_AND_OLD_IMAGES"
TableName: ${self:provider.environment.INTERVIEW_TABLE}
functions:
interviewSubmission:
handler: api/interview.submit
memorySize: 128
description: Submit interview information and starts interview process.
events:
- http:
path: interviews
method: post
and the interview.js
'use strict';
const uuid = require('uuid');
const AWS = require('aws-sdk');
AWS.config.setPromisesDependency(require('bluebird'));
const dynamoDb = new AWS.DynamoDB.DocumentClient();
module.exports.submit = (event, context, callback) => {
const requestBody = JSON.parse(event);
const fullname = requestBody.fullname;
const email = requestBody.email;
const test = requestBody.test;
const experience = requestBody.experience;
if (typeof fullname !== 'string' || typeof email !== 'string' || typeof experience !== 'number') {
console.error('Validation Failed');
callback(new Error('Couldn\'t submit interview because of validation errors.'));
return;
}
submitInterviewP(interviewInfo(fullname, email, experience, test))
.then(res => {
callback(null, {
statusCode: 200,
body: JSON.stringify({
message: `Sucessfully submitted interview with email ${email}`,
interviewId: res.id
})
});
})
.catch(err => {
console.log(err);
callback(null, {
statusCode: 500,
body: JSON.stringify({
message: `Unable to submit interview with email ${email}`
})
})
});
};
const submitInterviewP = interview => {
console.log('Submitting interview');
const interviewInfo = {
TableName: process.env.INTERVIEW_TABLE,
Item: interview,
};
return dynamoDb.put(interviewInfo).promise()
.then(res => interview);
};
const interviewInfo = (fullname, email, experience,test) => {
const timestamp = new Date().getTime();
return {
id: uuid.v1(),
fullname: fullname,
email: email,
experience: experience,
test: test,
submittedAt: timestamp,
updatedAt: timestamp,
};
};
If I replace the event param for a valid JSON object and then deploy again. I'm able to successfully insert the object into dynamoDB.
Any clues? Please let me know if there's anything I missing that could help.
Thanks!
API Gateway stringify the request body in event's body property.
Currently you are trying to parse event object const requestBody = JSON.parse(event); which is wrong. You need to parse event.body property:
const requestBody = JSON.parse(event.body);

Cannot read property 'getCompilationErrors' of undefined

I'm having issues setting up an express server instance on serverless with nextJs. I keep getting a Cannot read property 'getCompilationErrors' of undefined when running the server function. It seems to be an issue with app.render.
When running debug it seems to be coming from within nextJs
Server.js
const express = require('express');
const path = require('path');
const dev = process.env.NODE_ENV !== 'production';
const next = require('next');
const pathMatch = require('path-match');
const app = next({ dev });
const handle = app.getRequestHandler();
const { parse } = require('url');
const server = express();
const route = pathMatch();
server.use('/_next', express.static(path.join(__dirname, '.next')));
server.get('/', (req, res) => app.render(req, res, '/'));
server.get('*', (req, res) => handle(req, res));
module.exports = server;
index.js
const sls = require('serverless-http')
const binaryMimeTypes = require('./binaryMimeTypes')
const server = require('./server')
module.exports.server = sls(server, {
binary: binaryMimeTypes
});
Serverless.yml
service: ssr-react-next
provider:
name: aws
runtime: nodejs8.10
stage: ${self:custom.secrets.NODE_ENV}
region: us-east-1
environment:
NODE_ENV: ${self:custom.secrets.NODE_ENV}
functions:
server:
handler: index.server
events:
- http: ANY /
- http: ANY /{proxy+}
plugins:
- serverless-apigw-binary
- serverless-domain-manager
custom:
secrets: ${file(secrets.json)}
apigwBinary:
types:
- '*/*'
customDomain:
domainName: ${self:custom.secrets.DOMAIN}
basePath: ''
stage: ${self:custom.secrets.NODE_ENV}
createRoute53Record: true
# endpointType: 'regional'
# if the ACM certificate is created in a region except for `'us-east-1'` you need `endpointType: 'regional'`
Figured a way around this, just needed to prepare the app with async
server.use(async(req, res, next) => {
await app.prepare();
next();
})
Did you add this in the server.js so it looks like this?
server.js after server.use('/_next', express.static(path.join(__dirname, '.next')))
server.use(async(req, res, next) => {
await app.prepare();
next();
})

How to make serializer get called

I'm using ember cli
ember 1.12.0
ember data 1.0.0-beta.18
router.js:
import Ember from 'ember';
import config from './config/environment';
var Router = Ember.Router.extend({
location: config.locationType
});
Router.map(function() {
this.route('datasource');
});
//export default Router;
export default Router;
routes/datasource.js:
import Ember from 'ember';
export default Ember.Route.extend({
model: function() {
// the model is an Array of all of the posts
// fetched from this url
return Ember.$.ajax('/datasource/');
//return [{'datasource': '1'}, {'datasource': '2'}];
}
});
adapters/application.js:
import DS from 'ember-data';
export default DS.Adapter.extend({
// ...your code here
});
models/datasource.js:
import DS from 'ember-data';
export default DS.Model.extend({
dsn: DS.attr()
});
serializers/datasource.js:
import DS from 'ember-data';
export default DS.RESTSerializer.extend({
extractArray: function(store, type, payload) {
var datasources = payload._items;
payload = {datasources: datasources};
return this._super(store, type, payload);
}
});
Ie my api returns the list of items inside the key _items.
But it looks like the serializer is never executed,
What should I do to make the serializer take effect?
This is the error -
Uncaught Error: Assertion Failed: The value that #each loops over must be an Array. You passed '{_items: [object Object],[object Object], _links: [object Object], _meta: [object Object]}' (wrapped in (generated datasource controller))Ember.default.assert # ember.debug.js:4854exports.default.CollectionView.default.extend._assertArrayLike # ember.debug.js:38837(anonymous function) # ember.debug.js:37836ContainerView.default.extend.init # ember.debug.js:37804superWrapper # ember.debug.js:17426superFunction # ember.debug.js:13805mixin.Mixin.create.init # ember.debug.js:38898superWrapper # ember.debug.js:17426superFunction # ember.debug.js:13805exports.default.CollectionView.default.extend.init # ember.debug.js:38832superWrapper # ember.debug.js:17426Class # ember.debug.js:30649ClassMixinProps.create # ember.debug.js:31071mixin.Mixin.create.createChildView # ember.debug.js:35755merge.default.appendChild # ember.debug.js:39847mixin.Mixin.create.appendChild # ember.debug.js:35697appendTemplatedView # ember.debug.js:8051viewHelper # ember.debug.js:7559collectionHelper # ember.debug.js:6410eachHelper # ember.debug.js:6598block # ember.debug.js:7807render # datasource.js:89renderHTMLBarsTemplate # ember.debug.js:8491renderView # ember.debug.js:8463renderView # ember.debug.js:35400mixin.Mixin.create.render # ember.debug.js:35423EmberRenderer_createElement # ember.debug.js:37468Renderer_renderTree # ember.debug.js:9140scheduledRenderTree # ember.debug.js:9216Queue.invoke # ember.debug.js:878Queue.flush # ember.debug.js:943DeferredActionQueues.flush # ember.debug.js:748Backburner.end # ember.debug.js:173(anonymous function) # ember.debug.js:576
In the model hook of your route you are doing a ajax call instead of calling the store to find records. With the ajax call you are bypassing your store and so the serializer will never be called to serialize the payload returned from your server.
In order to pass the payload to the store you can do:
// route
model: function() {
var store = this.store;
return Ember.$.ajax('/datasource/').then(function(payload) {
store.pushPayload('datasource', payload);
});
}
Alternatively you can call the store to do the call to your back-end so you don't have to do a ajax call yourself (not sure if it was your intention to do a custom call for some reason):
// route
model: function() {
return this.store.find('datasource');
}