I have this front-end code:
export const CreatePage = () => {
const auth = useContext(AuthContext)
const {request} = useHttp()
const [content, setContent] = useState('')
const [title, setTitle] = useState('')
const [lead, setLead] = useState('')
useEffect(() => {
window.M.updateTextFields()
},[])
const postHandler = async () => {
try {
const data = await request('/api/post/generate', 'POST', {title: title, lead: lead, content: content}, {
Authorization: `Bearer ${auth.token}`
})
console.log(data)
} catch (e) {}
}
And this back-end code:
router.post('/generate', auth, async (req, res) => {
try {
const baseURL = config.get('baseURL')
const {title, lead, content} = req.body
// if (!title || !lead || !content) {
// return res.status(422).json({error: 'Please, input ALL fields'})
// }
const Post = new Post({
title, lead, content, owner: req.body.user.userId // req.user.userId
})
await Post.save()
res.status(201).json({Post})
} catch (e) {
res.status(500).json({message: 'Something went wrong'})
}})
I've tried a lot of things, but I still get this error. I know this is a server-side error, but that's all I have been able to figure out.
P.S. If there are any questions about the code, I will add it later.
UPD: By the way, could it be a problem's reason? Console log:
[1] Proxy error: Could not proxy request /api/post/generate from localhost:3000 to http://localhost:5000.
Probably, it's because of cors, you just can't send request from different url's. Try to install cors and configure it:
const cors = require("cors");
app.use("/", require('./src/routes'));
app.use(cors({
origin: '*'
}))
Related
I am facing an issue regarding clickjacking prevention. I have implemented authentication and custom headers that contain headers that are requested by Shopify.
ctx.set('Content-Security-Policy', `frame-ancestors https://${ctx.query.shop} https://admin.shopify.com`);
ctx.res.setHeader(
"Content-Security-Policy",
`frame-ancestors https://${ctx.query.shop} https://admin.shopify.com;`
)
local environment headers:
[1]: https://i.stack.imgur.com/XBkW4.png
Production Environment response headers:
[2]: https://i.stack.imgur.com/YkfnA.png
It is working fine in my development environment but is not working in production.
my server.js file
/* eslint-disable #typescript-eslint/no-var-requires */
const dotenv = require('dotenv')
const Koa = require('koa')
const next = require('next')
const { default: createShopifyAuth } = require('#shopify/koa-shopify-auth')
const { verifyRequest } = require('#shopify/koa-shopify-auth')
const { default: Shopify, ApiVersion } = require('#shopify/shopify-api')
const { withSentry } = require('#sentry/nextjs')
const proxy = require('koa-proxy')
const Router = require('#koa/router')
const { checkForNewThemeSupport } = require('./checkfordawntheme')
dotenv.config()
const { PORT } = process.env
const { NODE_ENV } = process.env
const port = parseInt(PORT, 10) || 3000
const dev = NODE_ENV !== 'production'
const app = next({ dev })
const handle = withSentry(app.getRequestHandler())
if (!process.env.NEXT_PUBLIC_SHOPIFY_API_KEY || !process.env.SHOPIFY_API_SECRET_KEY) {
console.error('Missing api keys')
}
const SCOPES = [
'read_products',
'write_products',
'unauthenticated_read_product_listings',
'read_orders',
'read_script_tags',
'write_script_tags',
'read_themes'
]
Shopify.Context.initialize({
API_KEY: process.env.NEXT_PUBLIC_SHOPIFY_API_KEY,
API_SECRET_KEY: process.env.SHOPIFY_API_SECRET_KEY,
SCOPES,
HOST_NAME: process.env.SHOPIFY_APP_URL.replace(/https:\/\//, ''),
API_VERSION: ApiVersion.October20,
IS_EMBEDDED_APP: true,
SESSION_STORAGE: new Shopify.Session.MemorySessionStorage()
})
// TODO replace this with something serious
const ACTIVE_SHOPIFY_SHOPS = {}
const handleRequest = async (ctx) => {
await handle(ctx.req, ctx.res)
ctx.set('Content-Security-Policy', `frame-ancestors https://${ctx.query.shop} https://admin.shopify.com`);
ctx.res.setHeader(
"Content-Security-Policy",
`frame-ancestors https://${ctx.query.shop} https://admin.shopify.com;`
)
console.log("************* frame ancestor ********* ")
ctx.respond = false
ctx.res.statusCode = 200
}
app.prepare().then(() => {
const server = new Koa()
const router = new Router()
server.keys = [Shopify.Context.API_SECRET_KEY]
// online auth for app/user request
server.use(createShopifyAuth({
accessMode: 'online',
afterAuth(ctx) {
// Online access mode access token and shop available in ctx.state.shopify
const { shop } = ctx.state.shopify
const { host } = ctx.query
// Redirect to app with shop parameter upon auth
ctx.redirect(`/?shop=${shop}&host=${host}`)
}
}))
// offline auth for background tasks
server.use(createShopifyAuth({
accessMode: 'offline',
prefix: '/offline',
async afterAuth(ctx) {
const { shop, accessToken } = ctx.state.shopify
ACTIVE_SHOPIFY_SHOPS[shop] = true
// APP_UNINSTALLED webhook to make sure merchants go through OAuth if they reinstall it
const response = await Shopify.Webhooks.Registry.register({
shop,
accessToken,
path: '/webhooks',
topic: 'APP_UNINSTALLED',
webhookHandler: async (topic, shop) => delete ACTIVE_SHOPIFY_SHOPS[shop]
})
if (!response.success) {
console.error(`Failed to register APP_UNINSTALLED webhook: ${response.result}`)
}
ctx.redirect(`/auth?shop=${shop}`)
}
}))
router.get('/', async (ctx) => {
const { shop } = ctx.query
if (ACTIVE_SHOPIFY_SHOPS[shop] === undefined) {
ctx.redirect(`/offline/auth?shop=${shop}`)
} else {
await handleRequest(ctx)
}
})
router.get('(/_next/static/.*)', handleRequest)
router.get('/_next/webpack-hmr', handleRequest)
router.get('/(.*).js', handleRequest)
router.get('/login', verifyRequest(), handleRequest)
router.get('/register', verifyRequest(), handleRequest)
router.post(
'/webhooks',
async (ctx) => {
try {
await Shopify.Webhooks.Registry.process(ctx.req, ctx.res)
} catch (error) {
console.error(`Failed to process webhook: ${error}`)
}
}
)
router.post(
'/graphql',
verifyRequest({ returnHeader: true }),
async (ctx) => {
await Shopify.Utils.graphqlProxy(ctx.req, ctx.res)
}
)
router.get(
'/checkfor20',
verifyRequest(),
async (ctx) => {
try {
const hasCartAppBlock = await checkForNewThemeSupport(ctx)
ctx.body = JSON.stringify({ hasCartAppBlock })
ctx.status = 200
} catch (error) {
console.error(`Failed to check for theme: ${error}`)
}
}
)
server.use(router.allowedMethods())
server.use(router.routes())
server.use(proxy({
host: process.env.NEXT_PUBLIC_TREEPOINTS_API_URL,
match: /^\/********-api\/\w*/,
map: (path) => path?.split(process.env.NEXT_PUBLIC_TREEPOINTS_API_PROXY_URL)?.[1] || path
}))
// eslint-disable-next-line no-console
server.listen(port, () => console.log(`> Ready on http://localhost:${port}`))
})
App development framework: nextjs
deployment server: Heroku
Any help would be appreciated.
I have this API, and I am trying to get the query I pass in the URL (such as products?page=1&limit=10) but I keep getting an empty object
const handler = nc().use(Cors());
handler.get(async (req, res) => {
await db.connect();
console.log(req.query)
const products = await Product.paginate({}, { page: 1, limit: 30 });
res.send(products);
});
export default handler;
console.log(req.query.page, req.query.limit)
You can pass any props to your api
const desiredId = 'xyz'
'https://yourAPI/getSomething?any_name_you_want='+ desiredId
//in your api
console.log(req.query.any_name_you_want)
Well, I have somehow managed to do it even though it probably isn't the best way. It works though and my main focus is not the backend, so I guess it's good enough
In redux toolkit query:
endpoints: (builder) => ({
getAllProducts: builder.query({
query: (page = 1) => `${baseUrl}?page=${page}`,
}),
In my index.js
const router = useRouter();
const [page, setPage] = useState(1);
const { data, isLoading, error } = useGetAllProductsQuery(page);
const handlePaginationChange = (e, value) => {
e.preventDefault();
setPage(value);
router.push(`/products?page=${value}`);
};
and my API route:
const handler = nc().use(Cors());
handler.get(async (req, res) => {
await db.connect();
const products = await Product.paginate({}, { page: req.query.page, limit: 9 });
res.send(products);
});
Run the Shopify CLI but still is very difficult to do anything.
Would like to retrieve 10 articles from Shopify between those id's but I am getting an error that URLSearchParams is not recognized.
Pretty sure that is something really easy.
The full code below is where I am at the moment.
index.js
import { Heading, Page } from "#shopify/polaris";
const Index = () => (
<Page
title='Trustpilot Aggreggation Uploader'
primaryAction={{
content: 'Update Metafields',
onAction: () =>
{
console.log('appliying products');
var limit = 10;
var sinceId = '0,921728736';
const product = async (limit, sinceId) => {
const res = await fetch(
"/products?" +
new URLSearchParams({
limit,
since_id: sinceId,
})
);
return await res.json();
};
}
}}
/>
);
export default Index;
server.js
import "#babel/polyfill";
import dotenv from "dotenv";
import "isomorphic-fetch";
import createShopifyAuth, { verifyRequest } from "#shopify/koa-shopify-auth";
import Shopify, { ApiVersion } from "#shopify/shopify-api";
import Koa from "koa";
import next from "next";
import Router from "koa-router";
dotenv.config();
const port = parseInt(process.env.PORT, 10) || 8081;
const dev = process.env.NODE_ENV !== "production";
const app = next({
dev,
});
const handle = app.getRequestHandler();
Shopify.Context.initialize({
API_KEY: process.env.SHOPIFY_API_KEY,
API_SECRET_KEY: process.env.SHOPIFY_API_SECRET,
SCOPES: process.env.SCOPES.split(","),
HOST_NAME: process.env.HOST.replace(/https:\/\//, ""),
API_VERSION: ApiVersion.October20,
IS_EMBEDDED_APP: true,
// This should be replaced with your preferred storage strategy
SESSION_STORAGE: new Shopify.Session.MemorySessionStorage(),
});
// Storing the currently active shops in memory will force them to re-login when your server restarts. You should
// persist this object in your app.
const ACTIVE_SHOPIFY_SHOPS = {};
app.prepare().then(async () => {
const server = new Koa();
const router = new Router();
server.keys = [Shopify.Context.API_SECRET_KEY];
server.use(
createShopifyAuth({
async afterAuth(ctx) {
// Access token and shop available in ctx.state.shopify
const { shop, accessToken, scope } = ctx.state.shopify;
ACTIVE_SHOPIFY_SHOPS[shop] = scope;
const response = await Shopify.Webhooks.Registry.register({
shop,
accessToken,
path: "/webhooks",
topic: "APP_UNINSTALLED",
webhookHandler: async (topic, shop, body) =>
delete ACTIVE_SHOPIFY_SHOPS[shop],
});
if (!response.success) {
console.log(
`Failed to register APP_UNINSTALLED webhook: ${response.result}`
);
}
// Redirect to app with shop parameter upon auth
ctx.redirect(`/?shop=${shop}`);
},
})
);
const handleRequest = async (ctx) => {
await handle(ctx.req, ctx.res);
ctx.respond = false;
ctx.res.statusCode = 200;
};
router.get("/", async (ctx) => {
const shop = ctx.query.shop;
// This shop hasn't been seen yet, go through OAuth to create a session
if (ACTIVE_SHOPIFY_SHOPS[shop] === undefined) {
ctx.redirect(`/auth?shop=${shop}`);
} else {
await handleRequest(ctx);
}
});
router.get("/products", async (ctx) => {
try {
const { shop, accessToken } = ctx.session;
const res = await fetch( 'https://${SHOPIFY_API_KEY}:${accessToken}#${shop}/admin/api/2020-10/products.json?${new URLSearchParams(
ctx.request.query
)}'
);
ctx.body = await res.json();
ctx.status = 200;
} catch (error) {
console.log('Failed to process products: ${error}');
}
});
router.post(
"/graphql",
verifyRequest({ returnHeader: true }),
async (ctx, next) => {
await Shopify.Utils.graphqlProxy(ctx.req, ctx.res);
}
);
router.get("(/_next/static/.*)", handleRequest); // Static content is clear
router.get("/_next/webpack-hmr", handleRequest); // Webpack content is clear
router.get("(.*)", verifyRequest(), handleRequest); // Everything else must have sessions
server.use(router.allowedMethods());
server.use(router.routes());
server.listen(port, () => {
console.log(`> Ready on http://localhost:${port}`);
});
});
Please beware that URLSearchParams class was added as a Global Object only on Node v10.
On older versions of Node you have to import it first:
import { URLSearchParams } from 'url';
global.URLSearchParams = URLSearchParams
I have a button that lauches a fetch to my API that uses KOA and JWT. The javascript for the fetch initiated on click is:
<script>
function loginButton(user, pass) {
fetch('http://localhost:5454/api/login', {
method: "post",
headers: {
'Content-Type': "application/json"
},
body: JSON.stringify({
username: user,
password: pass
})
})
.then( (response) => {
console.log("Success")
})
.catch(e => console.log(e));
}
</script>
The code for my Authentication is:
router.post(`${BASE_URL}/login`, async (ctx) => {
const reqUsername = ctx.request.body.username
const reqPassword = ctx.request.body.password
const unauthorized = (ctx) => {
ctx.status = 401
ctx.body = {
error: 'Invalid username or password'
}
}
let attemptingUser
try {
attemptingUser = await Employee.findOne({ where: { username: reqUsername }})
if (attemptingUser != null && attemptingUser.password === reqPassword) {
ctx.status = 200
ctx.body = {
username: attemptingUser.username,
given_name: attemptingUser.given_name,
role: attemptingUser.role,
created_at: attemptingUser.createdAt,
updated_at: attemptingUser.updatedAt,
}
const token = jwt.sign({ username: attemptingUser.username, role: attemptingUser.role }, SECRET)
ctx.set("X-Auth", token)
} else {
unauthorized(ctx)
}
} catch(err) {
console.error(err)
console.error(`Failed to find username: ${reqUsername}`)
unauthorized(ctx)
}
})
The code for my KOA initiation is:
require('dotenv').config()
const Koa = require('koa')
const Router = require('koa-router')
const bodyParser = require('koa-bodyparser')
const baseRoutes = require('./routes')
const cors = require('#koa/cors');
const PORT = process.env.PORT || 8080
const app = new Koa()
app.use(bodyParser())
app.use(baseRoutes.routes())
app.use(cors());
app.listen(PORT, () => {
console.log(`Server listening on ${PORT}`)
})
Im using Port 8080 for my http-server and port 5454 for my npm server. I am getting a Failed to Fetch in the catch of the Fetch, as well as a CORS error related to not having a Access-Control-Allow-Origin header in the response header. I've tried a couple things and am ready to have a new set of eyes look at it, any tips?
Edit: I am successfully receiving the token in the X-Auth header, but for some reason it’s still throwing errors and I’d like to get them resolved before it spirals out of control.
I'm trying to test a service that uses the #google/maps client for getting directions data.
Here is a simplified version of the service:
'use strict'
const dotenv = require('dotenv')
const GoogleMaps = require('#google/maps')
dotenv.config()
const {GOOGLE_API_KEY: key} = process.env
const client = GoogleMaps.createClient({key, Promise})
const getData = exports.getData = async function({origin, destination}) {
try {
const options = {
origin,
destination,
mode: 'transit',
transit_mode: ['bus', 'rail']
}
const res = await client.directions(options).asPromise()
return res
} catch (err) {
throw err
}
}
And here is a test file to show the case:
'use strict'
const dotenv = require('dotenv')
const nock = require('nock')
const gdService = require('./gd.service')
dotenv.config()
const {GOOGLE_API_KEY: key} = process.env
const response = {json: {name: 'custom'}}
const origin = {lat: 51.5187516, lng: -0.0836314}
const destination = {lat: 51.52018, lng: -0.0998361}
const opts = {origin, destination}
nock('https://maps.googleapis.com')
.get('/maps/api/directions/json')
.query({
origin: `${origin.lat},${origin.lng}`,
destination: `${destination.lat},${destination.lng}`,
mode: 'transit',
transit_mode: 'bus|rail',
key
})
.reply(200, response)
gdService.getData(opts)
.then(res => {
console.log(res.json) // it's undefined!
})
.catch(err => {
console.error(err)
})
What I expect is to get the defined response as a response of the service method invocation. But I get undefined. Why is that?
After reading the source of #google/maps client, I figured out that I had to provide nock with the following reply header:
...
nock('https://maps.googleapis.com')
.defaultReplyHeaders({
'Content-Type': 'application/json; charset=UTF-8'
})
.get('/maps/api/directions/json')
...