aws-amplify / amplify-js

A declarative JavaScript library for application development using cloud services.
https://docs.amplify.aws/lib/q/platform/js
Apache License 2.0
9.41k stars 2.11k forks source link

Server-Side Rendering (SSR) with Next.js #5435

Closed ericclemmons closed 3 years ago

ericclemmons commented 4 years ago

Given Next.js’ popularity, customer impact, and being a hybrid framework supporting both SSR & SSG, solving for Next.js first unblocks other frameworks (e.g. Gatsby, Nuxt).

There is additional work to be done for CLI & Console support (particularly around deployments), but this Epic focuses on JS support.

This feature is live! See the Getting Started tutorial and SSR docs for the latest!

Public Preview

We'd love your help testing out Amplify's API, Auth, and DataStore categories in your Next.js app!

  1. First, reinstall Amplify using the @preview tag on NPM:

    yarn add aws-amplify@preview
    # or
    npm install aws-amplify@preview --save
  2. If you're only accessing public data (e.g. API.graphql(listBlogs)), you're done! 😌

  3. For secure access the current user on the server, you'll need to scope Amplify to the current request (and only that request) using our new withSSRContext helper:

    diff --git a/my-next-app/pages/index.tsx b/my-next-app/pages/index.tsx
    index 22b0c471..d7ce454b 100644
    --- a/my-next-app/pages/index.tsx
    +++ b/my-next-app/pages/index.tsx
    @@ -1,6 +1,6 @@
     import { CognitoUser } from '@aws-amplify/auth'
     import { GRAPHQL_AUTH_MODE } from '@aws-amplify/api-graphql'
    -import { Amplify, API, Auth } from 'aws-amplify'
    +import { Amplify, withSSRContext } from 'aws-amplify'
     import { Authenticator } from 'aws-amplify-react'
     import { GetServerSideProps } from 'next'
     import Head from 'next/head'
    @@ -13,8 +13,6 @@ import { CreateTodoMutationVariables } from '../src/API'
    
     Amplify.configure(awsconfig)
    
     // 👇 Your frontend code is now "SSR-aware", giving the backend access to the current session
    +const { Auth, API } = withSSRContext()
    +
     export default function Home(props) {
    @@ -392,8 +390,6 @@ export default function Home(props: Props) {
     }
    
     export const getServerSideProps: GetServerSideProps = async (context) => {
       // 👇 Auth & API are now scoped to the _current_ user's session
    +  const { Auth, API } = withSSRContext(context)
    +

    For more information on withSSRContext, see https://github.com/aws-amplify/amplify-js/pull/6146.

  4. Last step! Let us know your experience in the comments below 👇

Milestones


Related milestone: https://github.com/aws-amplify/amplify-js/milestone/26 Related issues: #5101, #4178, #3741, #1613, #3278, #5121, #5097, #4972, #2230, #4990, #4851, #5293, #5435, #5322, #3854, #3053, #3348, #5138, #4311, #4305, #4207, #3037, #992

dabit3 commented 4 years ago

@ericclemmons you are the man.

sovattha commented 4 years ago

It took me a day to realize that Amplify does not work well with the SSR of Next.js.

Going to the competition (Auth0) for the time being.

dabit3 commented 4 years ago

@sovattha check back with us soon, this is already being developed and tested.

ericclemmons commented 4 years ago

@sovattha Do any of issues in https://github.com/aws-amplify/amplify-js/milestone/26 match your experience? withAuthenticator works with the latest release:

  1. Create or Update pages/_app.tsx with Amplify.configure:

    import '@aws-amplify/ui/dist/style.css'
    import Amplify from 'aws-amplify'
    import { AppProps } from 'next/app'
    
    import awsconfig from '../src/aws-exports'
    
    Amplify.configure(awsconfig)
    
    function MyApp({ Component, pageProps }: AppProps) {
     return <Component {...pageProps} />
    }
    
    export default MyApp
  2. Wrap pages/index.tsx with withAuthenticator:

    export default withAuthenticator(Home)

If you have any issues, feel free to create a new issue so I can track it here 🙏

sovattha commented 4 years ago

I'll keep an eye on your progress guys. The progress of the project is exciting. Thanks for noticing about the milestone.

alexandrzavalii commented 4 years ago

Hi @ericclemmons , thanks for taking a look at the issue! I still see the error in Next.js ReferenceError: window is not defined inside /@aws-amplify/ui-react/lib/components.js:8:76

I am using "aws-amplify": "^3.0.8", "@aws-amplify/ui-react": "^0.2.3" Should I be using unstable?

ericclemmons commented 4 years ago

@alexandrzavalii I saw the same thing here: https://github.com/aws-amplify/amplify-js/issues/5293#issuecomment-610673005 (But the app still works)

If your Next.js is getting a different TypeScript/compilation/breaking error, open up a new issue and tag me: @ericclemmons. I'm happy to take a look!

alexandrzavalii commented 4 years ago

@ericclemmons in Chrome console I got this error as well

        Error: Amplify has not been configured correctly.
            This error is typically caused by one of the following scenarios:

No idea if it is caused by SSR or sthg else.

But I do have the Authenticator rendered on the screen

ericclemmons commented 4 years ago

@alexandrzavalii Definitely open up an issue with some more about your usage (including how/where you're doing Amplify.configure). I have working examples that'll make their way into the docs once we thoroughly test it, but I'd like to unblock you if I can :)

alexandrzavalii commented 4 years ago

Hey @ericclemmons, Looking forward for your example! It would be very helpful to have SSR example. Like having a navbar rendering "signin" or "profile" depending on user status.

TimNZ commented 4 years ago

@ericclemmons I don't want to crap on anyone (or pick on you specifically), but I've spent many hours looking for best practice for AWS Amplify/Cognito on how to do authentication in the browser and pass user identifying token to server i.e. the most standard of JWT type stuff for standard REST calls that don't presume API Gateway + IAM auth on calls. Also people have been asking for guidance/support for SSR for years.

Surely there is a single doc/video on this somewhere?

I've finally sorted out extracting JWT version of Access token to pass in Authorization header, for decoding by Lambda functions, but finding out how to do all this was more painful than any other framework I've used in years.

Since Amplify by default doesn't store any session data in cookies, SSR doesn't have anything to work with. Even finding out this was pain.

Every other framework has this most basic of scenarios working pretty much out the box and well documented.

withAuthenticator doesn't address any of this, I'm unclear as to why you reference it above.

Appreciate your thoughts on this. I have read a lot of comments around the place that people have given up on Amplify because it's so hard.

ericclemmons commented 4 years ago

@TimNZ I hear you. I really do. When I joined Amplify in October, I was equally surprised that SSR wasn't addressed.

It sounds like you went through the same pain-points I did on Friday (lack of cookie support), but we're very close to having this resolved.

Regarding withAuthenticator, there are varying degrees of SSR support: withAuthenticator successfully renders out of the box (whereas it used to not!). Your case is more complex, since it relies on sharing session state between the client & the server so that the server can make privileged calls.

I'd love to know more about your use-cases so that they're not overlooked! Can you share more about this scenario (especially if you have sample code)?

how to do authentication in the browser and pass user identifying token to server i.e. the most standard of JWT type stuff for standard REST calls that don't presume API Gateway + IAM auth on calls.

TimNZ commented 4 years ago

@ericclemmons thanks for quick response.

The use case is the classic that every framework has a flow for:

For a lot of frameworks/stacks, that's a session cookie. That cookie might be httpOnly if it's returned by a server in a standard page flow structure i.e. not a SPA

I think the pattern I'm seeing with many people struggling is the Amplify documentation is shockingly silent on showing how this standard flow works using Amplify. Even 3rd party guides barely address it. Even 3rd party packages often are silent on it when they are providing a work-around for some aspect.

So many people are getting stuck on trying to get the system to work the way they are used to. Amplify is engineered to work with a complete end to end AWS stack.

In my case (which is typical), I have an API deployed on API Gateway/Lambda, deployed via Serverless.

I 'expected' to authenticate using Amplify - doing it manually e.g. Auth.signIn etc, and then I could get a identifying session/user token to pass to the server in API calls.

I had just presumed that the 'session token' would be in managed in a cookie so it was available in Lambda event.headers.

Having done traditional client/server dev, and SPA - Feathers JS, Sails etc, this is what everyone is expecting, and Amplify is making real hard to understand how to replicate the flow.

Ignoring XSS concerns, now I just might extract the ID or Access token as JWT and store it in a cookie on successful signIn. I can now process that in my Lambda via event.headers.cookie[''], and in Next.js getInitialProps for SSR

If I wanted to apply best practice for XSS mitigation I'd implement redirect flow to endpoint that set httpOnly cookie.

^^ standard stuff

So the issue is poor documentation on how to do the above which most people are expecting kind of just works, like how they are used to with other stacks.

I think this is the root problem.

What do you think?

crash7 commented 4 years ago

@TimNZ sorry to jump in the middle of your discussion with @ericclemmons, but I have more or less the same kind of scenarios and here are my two cents (based on my wall head banging):

a) you could create your own session and store it with an http only cookie (I have this workaround with a GraphQL server, it's not ideal but cognito handles all the auth and on successful auth, there is a login mutation that receives the jwt token, and the server verifies the token and updates de session)

b) since you are using api gateway, you could just add an authorizer and send the access token that cognito returns in the headers, validate it in the authorizer and if everything is OK, your function will be invoked. Again, not ideal because you need to add the authorizer.

Disclaimer: I don't use Amplify directly but I do use the aws cognito identify package that amplify uses under the hood, the main problem while doing SSRs is that we need to preload the cognito store with the data we read from the token (that gets passed in the headers) without putting a lot of if browser conditions.

TimNZ commented 4 years ago

@crash7

My comments are why are so many people struggling with scenarios they just expect to work, not that they can't be solved, once you understand things.

Now I got 'expert' through the pain, I know how to address it many ways.

And the Amplify documentation doesn't help because it just mostly presumes you'll use the full AWS end-to-end flow including IAM authorizer etc.

TimNZ commented 4 years ago

@ericclemmons just a final follow on from my comment.

I agree with the frustration of the OP https://github.com/aws-amplify/amplify-js/issues/3495

I'm already considering moving away from Cognito after 3 days of pain.

ericclemmons commented 4 years ago

I've updated the PR description with more information on how SSR support is progressing. If you have any feedback related to SSR support & features, please share!

If you have other feedback, you can raise an issue, start a discussion, or join our Discord community:

MontoyaAndres commented 4 years ago

Hey @ericclemmons how can we use the /pages/api/* routes with API.graphql 😲 can we use this feature right now?

ericclemmons commented 4 years ago

@MontoyaAndres Yes, so long as the data is public (e.g. not requiring auth credentials, which is in progress)! Here's a snippet from a working example of mine:

// pages/api/blogs.tsx
import API, { graphqlOperation, GraphQLResult } from '@aws-amplify/api-graphql';
import Amplify from 'aws-amplify';

import { ListBlogsQuery } from '../../src/API';
import { listBlogs } from '../../src/graphql/queries';

import awsConfig from '../../src/aws-exports';
Amplify.configure(awsConfig);

export default async function getBlogs(req, res) {
    const { data } = (await API.graphql(
        graphqlOperation(listBlogs)
    )) as GraphQLResult<ListBlogsQuery>;

    res.send(data.listBlogs.items);
}
adammanderson commented 4 years ago

@ericclemmons, really encouraging to see progress on SSR for Auth :smile: It's been overlooked for too long!

Any ETA on when we can get to use it?

svrcekmichal commented 4 years ago

@ericclemmons is somewhere available example repo where we can see what part of work is done and how to setup it all?

dtelaroli commented 4 years ago

+1

ericclemmons commented 4 years ago

@adammanderson @svrcekmichal Unfortunately, not public yet! I'm addressing security concerns and don't want to risk code getting adopted without those addressed 😅

mdegrees commented 4 years ago

@ericclemmons is there any hack to go around this issue https://github.com/aws-amplify/amplify-js/issues/5101 while waiting for this milestone to complete. I want to use Datastore with Next js in a non SSR way for the time being. Then go SSR when it's fully supported.


Edit: I posted a hack that happens to work for me: https://github.com/aws-amplify/amplify-js/issues/5101#issuecomment-653448655 @ericclemmons

svrcekmichal commented 4 years ago

@ericclemmons ok, no pressure, thanks for all the time you put into this :)

apoorvmote commented 4 years ago

Hey guys I am interested in using nextjs with amplify(auth and api). There was an update/release yesterday to amplify-js. How will I know that nextjs is supported in any release/update?? And how will I know which features(e.g. SSG, auth, api) of Nextjs are currently supported on any release/update??

ericclemmons commented 4 years ago

@apoorvmote You can continue following & commenting on this issue for progress: we'll update this once it's on latest.

🎉 Good news though! I just shipped a Next.js preview to aws-amplify@preview!

I've updated the description at the top (https://github.com/aws-amplify/amplify-js/issues/5435) with steps to get started. Auth, API, and DataStore are actively developed against, but I'm tracking other categories at the top as well.

Give it a go in your app & comment below on your experience 👇

firrae commented 4 years ago

This seems promising, and if done AND documented well this could be a great alternative to Auth0. We've been using Cognito at work and while I like the concept the documentation at times has been terrible. Though I find that a lot across Amazon development resources, so I hope this won't meet the same blocking points of "this doesn't seem to be documented, and if it is it's not obvious".

I'm happy I stumbled on this before I started a new project going the other route. Progress seems to be going well maybe I'll bite the bullet and try out Amplify before going another route.

Also, are there currently any plans, or updates, on how things like AppSync will work with SSR? API is fine, but AppSync is what I had begun to look at if I went the all AWS route.

apoorvmote commented 4 years ago

I am also building static blog with Nextjs. And I will be adding my own commenting system with dynamodb and graphql. Also will be building my own custom forum with SSR. Unfortunately because of some constraints I have to connect to appsync with rest api + lambda function. When will amplify start supporting faster and cheaper HTTP API?

ericclemmons commented 4 years ago

@firrae Currently we're focusing on Amplify-specific categories (e.g. Auth, API, and DataStore), which will be actively tested against Next.js.

apoorvmote commented 4 years ago

I have tested Auth with withSSRContext and it works as advertised. But I am using amp pages for loging in with amp-access. I need to build 3 Rest API endpoints

  1. /check-auth-status
  2. /login
  3. /logout

I make post request on each endpoint to get login status, submit login info and logout the user. Its pretty self explanatory. But the Auth Stores cognito user information in local storage on browser.

How do I check login status at rest API with lambda?

At endpoint /check-auth-status I am able to parse cookie but how do I do cognito auth with cookie inside the scope of AWS amplify.

Until amplify people enable cognito for amp-access I am just going to use OAuth on express directly and skip cognito alltogether. Probably use API key to access graphql or just use lambda auth on graphql.

ericclemmons commented 4 years ago

@apoorvmote Is this with Next.js? (https://nextjs.org/docs/api-reference/next/amp)

robertying commented 4 years ago

Thanks for the effort put into SSR. I wonder if this will work for the standalone version of amazon-cognito-identity-js?

apoorvmote commented 4 years ago

@apoorvmote Is this with Next.js? (https://nextjs.org/docs/api-reference/next/amp)

@ericclemmons Yes. So Next.js makes it easy to implement amp. So the original specification/documentation is available on https://amp.dev/ . I am looking to build basic text commenting system in amp. That requires amp-access component to authenticate users.

For authentication I need to store JWT into a cookie. Because amp doesn't support easy access to local storage. Because of recent developments on same-site cookie. The cookies will become more secure.

I don't know what is the priority for you guys to support amp. So I have started learning CDK, cloudformation. So I get to implement HTTP API with my custom amp authentication. I won't be using amplify for this project.

ericclemmons commented 4 years ago

@apoorvmote If you're using @preview (https://github.com/aws-amplify/amplify-js/issues/5435#issuecomment-655660103), /check-auth-status should be able to return the current user via something like:

import { Amplify, withSSRContext } from 'aws-amplify'
import { NextApiRequest, NextApiResponse } from 'next'

import awsconfig from 'src/aws-exports'

Amplify.configure(awsconfig)

export default async (req: NextApiRequest, res: NextApiResponse) => {
  const { Auth } = withSSRContext({ req })

  try {
    const user = await Auth.currentAuthenticatedUser()

    return res.status(200).json({ message: "Authenticated!" })
  } catch (error) {
    console.error(error)
    return res.status(500).json({ error })
  }
}

/login & /logout dedicated routes aren't supported as part of this preview because authentication is delegated to Cognito on the client.

Can you open a new issue as a Feature Request with your circumstance? It looks like amp-access (https://amp.dev/documentation/components/amp-access/?format=websites) would need explicit consideration as an authentication flow vs. SSR support alone via Next.js.

apoorvmote commented 4 years ago

@ericclemmons I tried something similar. Instead of building API I was testing getServerSideProps on login page just to verify if I am logged in on client then am I logged in on server? Something like following.


export const getServerSideProps: GetServerSideProps = async(context) => {

  const { Auth } = withSSRContext(context)

  let user: any = null 

  console.log('get server')

  try {

    user = await Auth.currentAuthenticatedUser()

    console.log('ssr user', user)

  } catch (err) {

    console.log('error', err)
  }

  return {
    props: {
      user: JSON.parse(JSON.stringify(user))
    }
  }
}

I was logged in on client but on server user was null. I was able to get user on the same page on client like follows.

useEffect(() => {
    async function getAuth() {

      try {

        const user = await Auth.currentAuthenticatedUser()

        console.log(user)

      } catch (err) {

        console.log('front end error', err)
      }
    }

    getAuth()

  }, [])

I am new to nextjs. So I don't know if I have implemented any of this wrong. I refreshed page many times. But there is user on client and user is null at the server.

Can you open a new issue as a Feature Request with your circumstance? It looks like amp-access would need explicit consideration as an authentication flow vs. SSR support alone via Next.js.

Yes I will open new issue.

The underlying issue is we all want better SEO. So google built amp that has built in best page experience. But developers pushed against google for forcing us to use amp and not use our favorite stack. So google launched core web vitals. So now amp is no longer the only option for better SEO. We can use our favorite stack and as long as we conform to core web vitals and other best practices explained at https://web.dev/ And we love amplify because it has best practices built in so we don't have think about it.

Now if you can deliver on that then I will give up this amp nonsense and use Nextjs directly with amplify. Until then I will build my own infrastructure with cdk and cloudformation and do server side rendering with nodejs and handlebarjs and use amp to build websites.

ericclemmons commented 4 years ago

@apoorvmote It sounds like you're doing all the right things! One last check: does your client-side code also use withSSRContext? Otherwise, the credentials aren't made available to the server:

import { Amplify, withSSRContext } from 'aws-amplify'
import awsconfig from 'src/aws-exports'

Amplify.configure(awsconfig)

const { Auth, API } = withSSRContext()

export default function Home() {

Otherwise, I'd need to check to see if Next.js' AMP behavior changes things somehow...

apoorvmote commented 4 years ago

@ericclemmons Does it make any difference with

import { Amplify, withSSRContext } from 'aws-amplify'
import config from '../src/aws-exports'

Amplify.configure(config)

export default function Homepage({ user }: iProps) {

  const { Auth } = withSSRContext()

vs

import { Amplify, withSSRContext } from 'aws-amplify'
import config from '../src/aws-exports'

Amplify.configure(config)

const { Auth } = withSSRContext()

export default function Homepage({ user }: iProps) {

Because I am using the first version.

ericclemmons commented 4 years ago

@apoorvmote You only need one instance of Auth on the client, so the first is preferred. The second version you're using would re-create Auth (and all of Amplify) with each re-render of Homepage.

Even though it's less optimal, you're doing the right thing: so long as the authentication flow completes successfully on the client, the server should then be able to access the current user.

apoorvmote commented 4 years ago

@ericclemmons Thanks for clarification. Nextjs does show some promising features. But I am working on to somehow make amp-access work with whatever technology that works. Then transfer the knowlege to upgrade to Nextjs with amplify. And twist Amplify to fit my workflow.

svrcekmichal commented 4 years ago

@ericclemmons I'm using similat setup to what @apoorvmote is using here with no luck to get user on sever side.

What I noticed is that when I console.log Auth class in browser, there's multiple cognito cookies in UniversalStorage, but when console logged in getServerSideProps, UniversalStorage's store is almost empty, with all the cognito cookies missing. Do you maybe have some example working repo somewhere?

Posting here also my code, I've got auth route and 2 separate routes, one with SSR and one client side. On client side I've got "Hi, svrcekmichal@gmail.com" message, on server "no user":

// /pages/user-client.tsx

Amplify.configure(awsConfig)

const { Auth } = withSSRContext()

export default function AuthPage() {
  const [loading, setLoading] = useState(true)
  const [user, setUser] = useState(null)

  useEffect(() => {

    async function getAuth() {
      try {
        setUser(await Auth.currentAuthenticatedUser())
        setLoading(false)
      } catch (e) {
        console.error(e)
        setLoading(false)
      }
    }

    getAuth()
  }, [])

  if (loading) {
    return 'Loading...'
  }

  if(!user) {
    return 'No user'
  }
  return (
    <h1>Hi, {user.attributes.email}</h1>
  )
}

and

// /pages/user-server.tsx

Amplify.configure(awsConfig)

export default function User({ user }) {
  if(!user) {
    return 'No user'
  }
  return (
    <h1>Hi, ${user.attributes.email}</h1>
  )
}

export const getServerSideProps: GetServerSideProps = async (context) => {
  const { Auth } = withSSRContext(context)
  let user = null

  try {
    user = await Auth.currentAuthenticatedUser()
  } catch (e) {
    console.error(e)
  }

  return {
    props: {
      user: JSON.parse(JSON.stringify(user))
    }
  }
}
apoorvmote commented 4 years ago

@ericclemmons I have bit of off topic suggestion. If I understand correctly you and others are working on Auth and API for NextJS with Amplify.

If you think about it then CDK and Amplify are very similar. If you and/or others could build CDK templates for using NextJS for Auth and API as you guys work on Amplify then it would be beneficial to lot of people(mainly me LOL). And you guys could upload them to aws-cdk-examples

I understood CDK lot faster by studying templates than reading documentation. Any partial template can save me a lot of time and headache.

Assuming I get amp-access working. I myself am planning to blog about bunch of CDK templates. Either way thanks for reading my suggestion.

asterikx commented 4 years ago

Is it possible to add withSSRContext to @aws-amplify/auth as well, so that you don't have to require the whole aws-amplify package in case you only need auth?

The aws-amplify package is huge: 113 kB uncompressed, 29 kB compressed!

ericclemmons commented 4 years ago

@asterikx I'll look into it. So we're comparing the same metrics, what steps are you taking to get those number? next build?

asterikx commented 4 years ago

@ericclemmons I got that number from the VSCode Import Cost extension. I'm not sure what the final impact on the bundle is.

My other regular dependencies have ~7-15 kB uncompressed, e.g. react has 6.3 kB, emotion(CSS-in-JS) has 15.4 kB. When you look at BundlePhobia, the numbers are even worse.

react@16.13.1: 6.3 kB/2.6 kB (minified/gzipped) emotion@10.0.27: 15.4 kB/5.8 kB (minified/gzipped) axios@0.19.2: 13.1 kB/4.4 kB (minified/gzipped) aws-amplify@3.0.18-preview.46: 852 kB/207 kB (minified/gzipped) aws-amplify@3.0.23: 931 kB/213 kB (minified/gzipped)

ericclemmons commented 4 years ago

@asterikx I would take those numbers with a grain of salt: the build output is what matters most and is where tree-shaking is visible.

Amplify v3 was built specifically with this in mind: https://twitter.com/ericclemmons/status/1240784212241846275

(Still, I am monitoring the impact of client-only aws-amplify vs. SSR aws-amplify with this PR)

ianmartorell commented 4 years ago

Hey @ericclemmons, thanks for the work you're putting into getting SSR working! If I understood correctly, all the improvements that are being made to make Amplify work with Next.js will still require the final app to be hosted using Vercel, since Amplify Console doesn't support SSR. Is that right? Or how would this integrate with Amplify Console? I'm currently developing a React SPA that doesn't use Next.js and looking for the recommended way to add SSR for SEO purposes.

m5r commented 4 years ago

If I understood correctly, all the improvements that are being made to make Amplify work with Next.js will still require the final app to be hosted using Vercel, since Amplify Console doesn't support SSR. Is that right?

Vercel is one way to host your app. You can leverage the Serverless framework or just host it wherever you want to by following their docs

ChristopheBougere commented 4 years ago

@ianmartorell you can upvote this issue for amplify console support ;) https://github.com/aws-amplify/amplify-console/issues/412

ianmartorell commented 4 years ago

Vercel is one way to host your app. You can leverage the Serverless framework or just host it wherever you want to by following their docs

@m5r Thanks for the Serverless blog post link! Although I'd really like to host my app with the Amplify Console since I'm already using Amplify for everything else. And going for a node.js server just because I need SSR when I've already gone the full serverless architecture route doesn't feel great :)

@ianmartorell you can upvote this issue for amplify console support ;) aws-amplify/amplify-console#412

@ChristopheBougere Done!