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

Unable to use Nuxt's error/redirect functionality when a query failed #42

Closed
ciscorn opened this issue Nov 12, 2017 · 23 comments
Closed

Comments

@ciscorn
Copy link

ciscorn commented Nov 12, 2017

I want to call the context.error({...}) to show the Nuxt's error page when a query failed (Item not found, etc.).

In asyncData(context) {...}, we can easily do that as context is always given.

However inside vue-apollo's smart queries, I can't find a way to access the error()

This feature request is available on Nuxt.js community (#c30)
@ciscorn ciscorn changed the title Is there any ways to show Nuxt's error page when a query failed? Any ways to show Nuxt's error page when a query failed? Nov 12, 2017
@ciscorn
Copy link
Author

ciscorn commented Nov 12, 2017

I just found that I can access the error function via this.$root (even on server-side).

Is it the right (or stable) way to use this.$root on server-side?

  apollo: {
    entry: {
      query: ENTRY_QUERY,
      error() { // or result(...)
        this.$root.error({'statusCode': 404, 'message': 'OK'})
      },
      variables: {
          // ...
      },
      prefetch: true,
    }
  },

Edit: This doesn't work in SSR.

@dohomi
Copy link
Contributor

dohomi commented Nov 13, 2017

Hi @ciscorn

I think there are several ways of doing it. I prefer to redirect the user inside of the result hook. But your way is also a possible way of doing it

@ciscorn
Copy link
Author

ciscorn commented Nov 13, 2017

@dohomi I noticed that my code above (and your suggestion) doesn't work in SSR because the result and error handlers are evaluated after SSR has done.

@dohomi
Copy link
Contributor

dohomi commented Nov 13, 2017

@ciscorn yes we discovered this. Its something you can track inside of vue-apollo it has not necessary something todo with this package.

Try wrap your code in

result({data}){
  this.$nextTick(() => {
     // here you can set context to your component
  })
}

@dohomi
Copy link
Contributor

dohomi commented Nov 13, 2017

Sorry I think I misread your question. Maybe @Akryum has a good idea how to solve this, I always wait for the result and then redirect the user to error pages

@ciscorn
Copy link
Author

ciscorn commented Nov 13, 2017

@dohomi Thanks. I think something (such as prefetchResult handler) should be implemented on vue-apollo to serve real 404/302 pages in SSR.

@ciscorn ciscorn changed the title Any ways to show Nuxt's error page when a query failed? Any ways to call Nuxt's error/redirect method when a query failed? Nov 13, 2017
@dohomi
Copy link
Contributor

dohomi commented Nov 13, 2017

@ciscorn please open an issue inside of vue-apollo package. This package just supersets the usage of vue-apollo and will not add any features to extend vue-apollo

@dohomi dohomi closed this as completed Nov 13, 2017
@ciscorn
Copy link
Author

ciscorn commented Nov 20, 2017

(Please ignore if this is irreverent)

I created a modified version of apollo-module just for testing.

https://github.com/ciscorn/nuxtjs-apollo-explicit-module

This solves the error/redirect problem and a (potential) concurrency issue without any modifications both to Nuxt and vue-apollo. (However it introduces breaking changes.)

Please read a brief explanation in my README.md.

@dohomi
Copy link
Contributor

dohomi commented Nov 20, 2017

@ciscorn what happens if you use:

  async fetch(context) {
    const result = await contxt.app.apolloProvider.defaultClient.query(YOUR_QUERY_OBJECT)
    // You can call context.error (or redirect) based on the result
  },

 //! without any apollo...

with this package? I do this on some parts and had no issues so far.

@ciscorn
Copy link
Author

ciscorn commented Nov 20, 2017

@dohomi @Akryum @atinux

(I'm sorry if I'm misunderstanding something but...)

Nuxt.js has a built-in functionality to return 404/403/302/301/etc HTTP responses with context.error(...) and context.redirect(...). However with the original @nuxtjs/apollo, prefetching is performed after the Nuxt has finished checking the error/redirect flags, so the Nuxt's context.error doesn't work at the time apollo-module's prefetching has done.

(I think #35 is a bit related to the same problem.)

With my modified version, I can return "real 404/403" HTTP responses to clients based on query results with the Nuxt's built-in functionality. I think it's important for SSR and SEO. Redirecting to /404 page or something are not so beautiful and it just returns 200. We should be able to return error and redirect HTTP responses to clients and search engine crawlers without URL changes. (Nuxt.js itself kindly supports this.)

With my modified version, I can do:

  async fetch({app, error}) {
    const prefetchResult = await app.apolloPrefetch(this)
    if (!prefetchResult.article.data.article) {
      error({statusCode: 404, message: "Item Not Found"})
    }
  },

And then clients receive 404 responses:

404

@dohomi
Copy link
Contributor

dohomi commented Nov 21, 2017

@ciscorn ok I understand now better. @Akryum what do you think about this approach?

@dohomi dohomi reopened this Nov 21, 2017
@ciscorn ciscorn changed the title Any ways to call Nuxt's error/redirect method when a query failed? Unable to return Nuxt's error/redirect response when a query failed Feb 13, 2018
@kavalcante
Copy link

Any news on this? Really want to use this implementation!

@dohomi
Copy link
Contributor

dohomi commented Apr 16, 2018

@kavalcante @ciscorn haven't had this implementation on my radar yet. You can gain same result with following code:

async asyncData({error, app, params}){
  const article = await app.apolloProvider.defaultClient.query({
    query: `someGql`,
    variables:{id: params.id}
  }).then(({data}) => data && data.Article)
  if(!article){
    return error({statusCode: 404, message: 'Not found'})
  }
  return {article}
}

Is there any reason why not using asncData directly, you would write actually less code to receive the same result. Setting up a fetch method is slightly redundant in my eyes. I'm not sure if its straight forward to decouple the query call and add the fetch statement to it. @Akryum I'd still be interested if you have any opinion as you have better knowledge in the vue-apollo client.

@kavalcante
Copy link

Looks a good implementation @dohomi, thanks for the example!

@jrobber
Copy link
Contributor

jrobber commented Apr 18, 2018

@dohomi One major reason to do ciscorn's implementation is that with your solution I have to do a query. Given this basic example of routing :

Pages
/product
_id.vue

The query is always sent before I can validate or asyncData (fetch isn't even invoked SSR). All I'd like to do is if there is no id param provided then re-route to the home page or something, but if apollo is added onto the component it does not work. If I have no apollo section on my vue component it works normally. I think the bug and issue belongs here because validate and errors are a Nuxt feature, not a Vue feature.

@dohomi
Copy link
Contributor

dohomi commented Apr 19, 2018

@jrobber sorry I am not sure if I follow correctly.. We are talking about query or fetching data from any component right? As Nuxt provides asnycData and you would not provide an _id param you can make a redirect in your asyncData before you would query your data:

asyncData({error, app, params, redirect}){
  if(!params.id){
    return redirect('/anywhere')
  }
  const article = await app.apolloProvider.defaultClient.query({
    query: `someGql`,
    variables:{id: params.id}
  }).then(({data}) => data && data.Article)
  if(!article){
    return error({statusCode: 404, message: 'Not found'})
  }
  return {article}
}

I'm not sure if I understand your concern correctly though..

@ciscorn
Copy link
Author

ciscorn commented Apr 23, 2018

My solution is a kind of dirty hack to avoid using beforeNuxtRender.

It would be the best if we can set up a hook here.

@ciscorn ciscorn changed the title Unable to return Nuxt's error/redirect response when a query failed Unable to use Nuxt's error/redirect functionality when a query failed May 11, 2018
@dohomi
Copy link
Contributor

dohomi commented Jun 7, 2018

As version 4 follows now a different approach I will close this issue. Most likely it does not solve your issue but maybe the best way would be to run a separate module for it.

@dohomi dohomi closed this as completed Jun 7, 2018
@aaronransley
Copy link

@dohomi, you mention a new approach as of version 4, but I'm not sure where to find more information on that approach. Would you mind pointing me towards some docs?

Thanks for all your work on @nuxtjs/apollo!

@dohomi
Copy link
Contributor

dohomi commented Dec 17, 2018

@aaronransley whats the exact issue you are facing?

@mccxiv
Copy link

mccxiv commented Aug 6, 2019

I see this issue is closed, does that mean smart queries are officially discouraged in favor of asyncData?

Right now I don't see a way to set the HTTP status code from the server side using a smart query, so instead we must use context.app.apolloProvider.defaultClient.query; definitely less elegant

@sebmor
Copy link

sebmor commented Aug 6, 2019

+1 Definitely would like to see this in the smart query as well.

@jsbroks
Copy link

jsbroks commented Dec 31, 2019

@aaronransley when using asyncData, the the data will not update with mutations(/changes to cache).

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

No branches or pull requests

8 participants