How to override AWS Amplify Api domain endpoint - aws-amplify

I have added a custom domain to the API Gateway due to CORS/Cookies/Infosec and other fun reasons.
I then added the following code to hack the correct domain into my Amplify configuration:
import { Amplify, API } from "aws-amplify"
const myfunc () => {
const amplifyEndpoint = API._restApi._options.endpoints[0]
Amplify.configure({
aws_cloud_logic_custom: [
{
...amplifyEndpoint,
endpoint: process.env.REACT_APP_API_URL || amplifyEndpoint.endpoint,
},
]
})
const response = await API.post("MyApiNameHere", "/some-endpoint", {data:"here"})
}
This works but a) is this really the correct way to do it? and b) I'm seeing a weird issue whereby the first API.post request of the day from a user is missing the authorization & x-amz-security-token headers that I expect Amplify to be magically providing. If a user refreshes the page, the headers are sent and everything works as expected.
[edit] turns out my missing headers issue is unrelated to this override, so still need to get to the bottom of that!

The more correct place looks to be in the index.js:
import { Amplify, API } from "aws-amplify"
import awsExports from "./aws-exports"
Amplify.configure(awsExports)
const amplifyEndpoint = API._restApi._options.endpoints[0]
Amplify.configure({
aws_cloud_logic_custom: [
{
...amplifyEndpoint,
endpoint: process.env.REACT_APP_API_URL || amplifyEndpoint.endpoint,
},
]
})
That way it's done once - rather than needing to be done in each API call.
Naturally you would need some more complicated logic if you were dealing with multiple endpoints.

Related

how do you get request data within the new app directory?

I would like my nextjs13 app to serve content based on the subdomain / domain / slug / get_vars in the request.
I need to have access to the request data from within the new appfolder of nextjs 13, so that I can serve the right data on the server side.
e.g., sub-domain.my-domain.com/my-slug?my_var=1&another_var=2
How can I access the following data:
subdomain
domain
slug (this I can achieve using a folder wrapped in [])
get vars
Many thanks to any responders.
Accessing domain & subdomain using headers function:
import { headers } from 'next/headers'
const Page = () => {
const headersInstance = headers()
const [subdomain, domain] = headersInstance.get('host').split('.')
...
}
export default Page
Accessing slug through params prop:
const Page = ({ params: { slug } }) => {
console.log(slug)
...
}
export default Page
Accessing query parameters through searchParams prop (server-components):
Given sub-domain.my-domain.com/my-slug?my_var=1&another_var=2:
const Page = ({ searchParams }) => {
console.log(searchParams) // Logs { my_var: '1', another_var: '2' }
console.log(searchParams.my_var) // Logs 1
console.log(searchParams.another_var) // Logs 2
...
}
export default Page
NextJS 13 has a new router API for params.
You can check the client component documentation for the following methods as they also give examples on how to use it for server side purposes:
useSearchParams
useSelectedLayoutSegment
useSelectedLayoutSegments
Note that everything should be imported from 'next/navigation' (it was from 'next/router' before NextJS 13).
Regarding the domain and subdomain maybe the 'next/headers' documentation can help you.

Detecting new user signup in [...nextauth].js

I'm building an app with NextAuth's email provider as the sole means of user registration and login.
In local development everything worked fine, but when deploying the app to Vercel I keep getting Unhandled Promise Rejection errors from Mongo, so I decided to switch to NextAuth's unstable_getServerSession and everything is running very smoothly now.
Before making the switch I used an extra parameter to communicate whether the user was just logging in or newly signing up. Based on this, I sent different emails (a welcome email with login link vs. a shorter message with just the login link).
Here is how the [...nextauth].js file looked before:
export default async function auth(req, res) {
const signup = req.body.signup || false
return await NextAuth(req, res, {
adapter: MongoDBAdapter(clientPromise),
...
providers: [
EmailProvider({
...
sendVerificationRequest(server) {
customLogin(
server.identifier,
server.url,
server.provider, // passing the above data for email content
signup // custom parameter to decide which email to send
)
}
})
],
...
})
}
I adjusted the code sample from the documentation, but wasn't able to pass a custom parameter to it.
Here is my new code:
export const authOptions = {
adapter: MongoDBAdapter(promise),
...
providers: [
EmailProvider({
...
sendVerificationRequest(server) {
customLogin(
server.identifier,
server.url,
server.provider,
)
}
})
],
...
}
export default NextAuth(authOptions)
The customLogin function doesn't do anything except construction the different email options.
Among the things I have tried are wrapping authOptions in a handler function with req and res, setting up a separate API route, and passing parameters to the NextAuth function, but none of those worked.
Any advise on how to implement a custom parameter here would be highly appreciated.

Reload page says that the page does not exist netlify

I have a website which contains kind of blog pages where people can post issues and other people can comment on them.
But when i go to an issue route it gets the data from firebase when the route is the same as the saved slug in the database (not a really good way to do it like this). The data is displayed to the browser but there is one major issue if you reload the page netlify says the page could not be found.
I am loading the data from mounted() lifecycle it might be better to do this on asyncdata()
Here is my code:
mounted() {
self = this;
const issues = firebase.database().ref('Issues/')
issues.once('value', function(snapshot){
snapshot.forEach(function(childSnapshot) {
const data = childSnapshot.exportVal()
if(self.$nuxt.$route.path == "/Issues/"+data.Slug || self.$nuxt.$route.path == "/issues/"+data.Slug ) {
self.allIssuetitels.push(data.Titel)
self.allIssueonderwerpen.push(data.Onderwerp)
self.allteksten.push(data.Tekst)
self.user = data.User
self.profielfoto = data.Profielfoto
self.Slug = data.Slug
}
})
})
const reacties = firebase.database().ref('/Reacties')
reacties.once('value', function(snapshot) {
snapshot.forEach(function(childSnapshot) {
const data = childSnapshot.exportVal()
if(self.$nuxt.$route.path == '/Issues/'+data.Slug || self.$nuxt.$route.path == '/issues/'+data.Slug) {
self.reaprofielfoto.push(data.Profielfoto)
self.reauser.push(data.User)
self.allreacties.push(data.Reactie)
}
})
})
},
When i test it local it doesn't give me the page not found error. Is there any way of fixing this issue?
Here is where it does not work:
https://angry-lalande-a5e5eb.netlify.app/issues/3
For something like this where you are enabling users to create new pages and to have lots of user-generated content that is frequently update, you'd be well-served to look into server-side rendering.
https://v2.vuejs.org/v2/guide/ssr.html
I'd suggest, if you want to do that, you should migrate over to Nuxt as it makes things like this much easier.
However, there are quite a few caveats with going SSR - notably you'll need to run and manage a server.
If you don't want to look into SSR, you could use dynamic routes as shown here
const router = new VueRouter({
routes: [
// dynamic segments start with a colon
{ path: '/issue/:id', component: Issue }
]
})
You could then have the Issue component display a skeleton loader or another loading indicator while the content is fetching.
https://vuetifyjs.com/en/components/skeleton-loaders/

Change url to default page next.js

I tried to find how to change the default page path (when you access the server on the "/" path) but couldn't find anything. I have a structure in the pages directory in the form index/index.jsx and I want this page to be returned by default when accessing the server. I did not find a similar question on this forum, maybe someone will need your help, except me.
The way pages structure works in Next.js is very opiniated. If you need to send a file from a different pages structure when accessing / you would need to configure your own little express server.
See this link for official doc.
You would then have something like :
// Some code
if (pathname === '/') {
app.render(req, res, '/index', query) // Or /index/index.jsx
}
// Some code
Also if you do not want to create your own express server, you could have an index.js that redirects to your index page with something like this :
import Router from 'next/router'
const Index = () => null
Index.getInitialProps = async ({ res }) => {
if (res) {
res.writeHead(302, {
Location: `/index`
})
res.end()
}
else
Router.push(`/index`)
return {}
}
export default Index

firebase hosting blocking script due to CORS issue

I am using firebase hosting to host few scripts and trying to access them from another site. it naturally gets blocked due to CORS issues. based on my research on other forum threads etc i modified the firebase.json as below
{
"hosting": {
"public": "public",
"ignore": [
"firebase.json",
"**/.*",
"**/node_modules/**"
],
"headers": [ {
"source" : "**",
"headers" : [ {
"key" : "Access-Control-Allow-Origin",
"value" : "*"
} ]
}]
}
}
which essentially allow any url to access the resources hosted here. however, on trying to run my site i still see below
Access to XMLHttpRequest at 'https://oracle-bot-sdk.firebaseapp.com//loader.json'
from origin 'https://insurance-bot.moblize.it' has been blocked by CORS policy:
No 'Access-Control-Allow-Origin' header is present on the requested resource.
what else is needed?
In addition to your firebase.json changes for cors, your firebase functions http / https function needs to also include the cors plugin.
Example
const cors = require('cors')({origin: true});
const functions = require('firebase-functions');
const app = functions.https.onRequest((req, res) => {
cors(req, res, () => {
// Your app stuff here
// Send Response
res.status(200).send(<response data>);
});
});
Express App Example
import express from "express";
const cors = require('cors')({origin: true});
const app = express();
app.get('**', (req, res) => {
cors(req, res, () => {
// Your App Here
// Send response
res.status(200).send(<response data>);
});
});
More documentation Serve Dynamic Content with Cloud Functions - Create an HTTP function to your Hosting site (Cors is not mentioned in the documentation btw)
Is the site (https://insurance-bot.moblize.it/) that is calling to https://oracle-bot-sdk.firebaseapp.com a Firebase hosted app?
I only ask because with version 4.2+ of Firebase Tools allows you to setup Multisite hosting using the same Firebase Project. I am not sure if that would help your situation out at all. Just wanted to mention it.
In the error message:
insurance-bot.moblize.it/:1 Failed to load https://oracle-bot-sdk.firebaseapp.com//loader.json: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'https://insurance-bot.moblize.it' is therefore not allowed access.
I noticed an extra '/' in https://oracle-bot-sdk.firebaseapp.com//loader.json. I doubt that is the issue, but wanted to mention it.
There is something that you could try. Similar to the answers above but a little different:
"headers": [
{
"source": "*",
"headers": [
{
"key": "Access-Control-Allow-Origin",
"value": "*"
}
]
}
]
Also I would read some of the info here: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#Access-Control-Allow-Origin If you have not already.
I hope I was able to help in some way. Let me know.
My guess that you've mixed up firebase hosting and firebase cloud functions. Firebase hosting is made for hosting static websites and web apps. As you try to access from your website that is hosted on different domain your configuration for hosting is not applied. You mentioned that you host some scripts and it sounds like cloud functions. And good old CORS headers can help to your cloud functions like:
exports.corsEnabledFunction = (req, res) => {
res.set("Access-Control-Allow-Origin", "*");
res.set("Access-Control-Allow-Methods", "GET");
res.set("Access-Control-Allow-Headers", "Content-Type");
res.set("Access-Control-Max-Age", "3600");
// Continue with function code
...
}
More info: https://cloud.google.com/functions/docs/writing/http#handling_cors_requests
Make sure you have the Blaze or Flame plan, I think Spark plan blocks external access, maybe for the same reason as it does with cloud functions
Cloud Functions for Firebase - Billing account not configured
Go to the Google Cloud Console: https://console.cloud.google.com/functions/
Click the checkbox next to the function on which you want to grant access.
Click Show Info Panel in the top right corner to show the Permissions tab.
Click Add member.
In the New members field, type allUsers.
Select the role Cloud Functions > Cloud Functions Invoker from the Select a role drop-down menu.
Click Save.
taken from: https://github.com/firebase/firebase-functions/issues/645#issuecomment-605835353
This was the best solution for me as posted above
Go to the Google Cloud Console: https://console.cloud.google.com/functions/
Click the checkbox next to the function on which you want to grant access.
Click Show Info Panel in the top right corner to show the Permissions tab.
Click Add member.
In the New members field, type allUsers.
Select the role Cloud Functions > Cloud Functions Invoker from the Select a role drop-down menu.
Click Save.
taken from: https://github.com/firebase/firebase-functions/issues/645#issuecomment-605835353
Try pasting this as it's directly from the documentation, Customize Hosting Behavior:
"hosting": {
// Add the "headers" section within "hosting".
"headers": [ {
"source" : "**/*.#(eot|otf|ttf|ttc|woff|font.css)",
"headers" : [ {
"key" : "Access-Control-Allow-Origin",
"value" : "*"
} ]
}
}
Firebase hosting CORS doesn't work WITH custom domain.
However, CORS API works with https://yyyyyyy.web.app/ or firebaseapp.com domain

Resources