Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to use koa.js + next in firebase functions #1337

Closed
RezaRahmati opened this issue Jun 2, 2019 · 16 comments
Closed

How to use koa.js + next in firebase functions #1337

RezaRahmati opened this issue Jun 2, 2019 · 16 comments
Labels

Comments

@RezaRahmati
Copy link

RezaRahmati commented Jun 2, 2019

I want to use firebase functions to deploy the react application for shopify app

I am new to both next and koa

based on this repo the below code is how to host a simple react application in firebase

    const path = require('path')
    const functions = require('firebase-functions')
    const next = require('next')
    
    var dev = process.env.NODE_ENV !== 'production'
    var app = next({
      dev,
      conf: { distDir: `${path.relative(process.cwd(), __dirname)}/next` }
    })
    var handle = app.getRequestHandler()
    
    exports.next = functions.https.onRequest((req, res) => {
      console.log('File: ' + req.originalUrl) // log the page.js file that is being requested
      return app.prepare().then(() => handle(req, res))
    })

Which works correctly, no issue.

Then based on this tutorial from shopify I need to integrate koa and other dependencies in server.js, which in my case I believe it should be placed inside the firebase function. so I get to this code

   const path = require('path')
   const isomorphicFetch = require('isomorphic-fetch');
   const Koa = require('koa');
   const functions = require('firebase-functions')
   const next = require('next');
   const ShopifyConfig = require('./shopify.js');
   
   const { default: createShopifyAuth } = require('@shopify/koa-shopify-auth');
   const dotenv = require('dotenv');
   const { verifyRequest } = require('@shopify/koa-shopify-auth');
   const session = require('koa-session');
   
   dotenv.config();
   
   const port = parseInt(process.env.PORT, 10) || 3000;
   
   var dev = process.env.NODE_ENV !== 'production'
   var app = next({
     dev,
     conf: { distDir: `${path.relative(process.cwd(), __dirname)}/next` }
   })
   var handle = app.getRequestHandler()
   
   const server = new Koa();
   
   server.use(session(server));
   server.keys = [ShopifyConfig.secretKey];
   
   server.use(
     createShopifyAuth({
       apiKey: ShopifyConfig.key,
       secret: ShopifyConfig.secretKey,
       scopes: [],
       afterAuth(ctx) {
         const { shop, accessToken } = ctx.session;
         ctx.redirect('/');
       },
     }),
   );
   
   server.use(verifyRequest());
   
   server.use(async (ctx) => {
     await handle(ctx.req, ctx.res);
     ctx.respond = false;
     ctx.res.statusCode = 200;
   
   });
   
   exports.next = functions.https.onRequest((req, res) => {
     console.log('File: ' + req.originalUrl) // 

     // This is old code
     // return app.prepare().then(() => {
     //   handle(req, res);
     // })

     // I tried this #1
     // server.callback(req, res);
   })

   // I tried this #2
   // exports.next = functions.https.onRequest(server.callback);

   // I tried this #3
   // exports.next = functions.https.onRequest(server.callback());

   // I tried this #4
   exports.next = functions.https.onRequest((req, res) => {
     console.log('File: ' + req.originalUrl) 
   
     return app.prepare().then(() => {
       server.callback(req, res);
       //handle(req, res);
     })
   })

My question is now based on koa what code should be in functions.https.onRequest ?

I tried #1, #2, #3, as well as this post

1 -> I get request timeout

2 -> I get request timeout

3 -> I get Cannot access middleware of undefined

4 -> I get request timeout

@kvindascr
Copy link

@RezaRahmati server.callback is not the callback by itself, rather a function that generates the callback from your configuration I assumed.

You need to do this:

server.callback()(req, res);

That should do the trick I think.

@RezaRahmati
Copy link
Author

@kvindasAB thanks I will try, btw as I remember callback() was returning void not a function, however I try.

@fl0w
Copy link
Contributor

fl0w commented Jun 9, 2019

Application#callback returns a requestListener function compatible with node http.

@fl0w fl0w added the question label Jun 13, 2019
@gdayton
Copy link

gdayton commented Jun 21, 2019

@RezaRahmati Have you resolved this issue?

@RezaRahmati
Copy link
Author

RezaRahmati commented Jun 21, 2019

@gdayton I didn't tried it yet ;) I will try at weekend

@gdayton
Copy link

gdayton commented Jun 22, 2019

@RezaRahmati Ended up hosting the app on GCP AppEngine and will use Functions for other purposes

@fl0w
Copy link
Contributor

fl0w commented Jun 22, 2019

I'm going to close this as it seems to be answered and/or not an issue anymore. Please feel free to re-open if you're still having problems with this.

@fl0w fl0w closed this as completed Jun 22, 2019
@RezaRahmati
Copy link
Author

@kvindasAB Thanks
Your solution works

@paridigm
Copy link

const functions = require('firebase-functions');
const app = new Koa();

...

exports['http'] = functions.https.onRequest(app.callback());

@amardeepsingh20
Copy link

amardeepsingh20 commented Oct 14, 2019

@kvindasAB Thanks
Your solution works

Were you able to get the authentication part working? It seems to keep going in a loop and never authenticate.

createShopifyAuth({
       apiKey: ShopifyConfig.key,
       secret: ShopifyConfig.secretKey,
       scopes: [],
       afterAuth(ctx) {
         const { shop, accessToken } = ctx.session;
         ctx.redirect('/');
       },
     }),

This does not seem to be creating the /auth and /auth/callback routes properly in the firebase cloud functions environment. Any ideas?

@Sotacan
Copy link

Sotacan commented Dec 22, 2019

@kvindasAB Thanks
Your solution works

Were you able to get the authentication part working? It seems to keep going in a loop and never authenticate.

createShopifyAuth({
       apiKey: ShopifyConfig.key,
       secret: ShopifyConfig.secretKey,
       scopes: [],
       afterAuth(ctx) {
         const { shop, accessToken } = ctx.session;
         ctx.redirect('/');
       },
     }),

This does not seem to be creating the /auth and /auth/callback routes properly in the firebase cloud functions environment. Any ideas?

ever find a solution?

i have gotten a little farther into this and will have a fix soon i hope haha

@Sotacan
Copy link

Sotacan commented Dec 22, 2019

Wow, if you have the auth loop... Please save yourself the time from feeling like a scrub and forgetting firebase session management is different and just install this:

https://community.shopify.com/c/Shopify-Apps/Just-Released-Koa-Firebase-Session-Store/td-p/609260

thank me later

@miroo93
Copy link

miroo93 commented May 22, 2020

Was anyone here able to make Shopify OAuth process work with Firebase functions?
I'd love to see a snippet of that code that make the magic happens, I tried many variations and constantly failed... I am getting an infinite redirect loop now.
Help would be greatly appreciated.
Thanks!

@paridigm
Copy link

Personally, I ended up just making it from scratch after wasting about 2 weeks trying to get the Shopify sample w/ shopify libs to work in firebase...

Took about a half day to get it working. Shopify has great sample code, so it wasn't too bad at all,
https://shopify.dev/tutorials/authenticate-with-oauth

NOTE: you can use crypto.createHmac and cryto.timingSafeEqual in node for HMAC verification.

Also, (I think) firebase only supports session cookies with an underscore, like "_session". So, that's one of the reasons it doesn't work (amongst others)... Fundamentally I think there are so many issues with the Shopify sample app because firebase functions aren't really raw node servers (which is what the Shopify libs are made for). Firebase functions are node apps that (sort of) are already inside an express middleware that runs after a bunch of other middlewares like body parser, form data parser, etc.

Hope this helps!

@amardeepsingh20
Copy link

amardeepsingh20 commented May 24, 2020

Actually, I did get it to work long back! There are multiple issues at different levels, after wasting (or using) a lot of time I was able to get it to work. Your missing piece of puzzle is that Next.js will not work with Koa server with Firebase in 'dev' mode! It will work fine in production mode. To test it out, build your Nextjs app with npm run build (which should execute next build) and then try with Firebase functions.

In your server.js file, you can export the server like

// functions/server.js
.
..
...
module.exports = server;

The firebase function should look like this:

// functions/index.js
const server = require("./server");
exports.cloudNext = functions.https.onRequest(async (req, res) => {
  return server.callback()(req, res);
});

For development you can create a separate local server like below to serve your nextjs app in dev mode

// dev-server.js
const server = require("./functions/server");
const port = parseInt(process.env.PORT, 10) || 5000;
server.listen(port, () => {
    console.log(`> Ready on http://localhost:${port}`);
});

Let me know if face any issue.

Was anyone here able to make Shopify OAuth process work with Firebase functions?
I'd love to see a snippet of that code that make the magic happens, I tried many variations and constantly failed... I am getting an infinite redirect loop now.
Help would be greatly appreciated.
Thanks!

@sbzi1020
Copy link

Actually, I did get it to work long back! There are multiple issues at different levels, after wasting (or using) a lot of time I was able to get it to work. Your missing piece of puzzle is that Next.js will not work with Koa server with Firebase in 'dev' mode! It will work fine in production mode. To test it out, build your Nextjs app with npm run build (which should execute next build) and then try with Firebase functions.

In your server.js file, you can export the server like

// functions/server.js
.
..
...
module.exports = server;

The firebase function should look like this:

// functions/index.js
const server = require("./server");
exports.cloudNext = functions.https.onRequest(async (req, res) => {
  return server.callback()(req, res);
});

For development you can create a separate local server like below to serve your nextjs app in dev mode

// dev-server.js
const server = require("./functions/server");
const port = parseInt(process.env.PORT, 10) || 5000;
server.listen(port, () => {
    console.log(`> Ready on http://localhost:${port}`);
});

Let me know if face any issue.

Was anyone here able to make Shopify OAuth process work with Firebase functions?
I'd love to see a snippet of that code that make the magic happens, I tried many variations and constantly failed... I am getting an infinite redirect loop now.
Help would be greatly appreciated.
Thanks!

@amardeepsingh20 Hi there, I'm currently working on Shopify custom app with @shopify/koa-shopify-auth and want to serve in Firebase hosting, facing the same issue (can't finish the Shopify auth process). Is that possible for you to paste the entire server.js and your functions/index.js here to have a look, that will be a great help for me, thank you SO MUCH!!!!:)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

9 participants