Get data from slug in Meteor / Apollo

Hi all,

I’m struggling to get my ‘slug’ prop to pass to my graphql query, I receive this message:

POST http://localhost:3000/graphql 400 (Bad Request)
HTTPFetchNetworkInterface.fetchFromRemoteEndpoint @ modules.js?hash=2b87763…:28082
(anonymous) @ modules.js?hash=2b87763…:28099
(anonymous) @ meteor.js?hash=e3f53db…:1105
modules.js?hash=2b87763…:37485 Error in observer.error 
Error

And here are the relevant bits of my code:

My route:

<Route path='/ad/:slug' component={ SingleAdvert } />

The component:

import React from 'react';
import { graphql } from 'react-apollo';
import { withRouter } from 'react-router';
import gql from 'graphql-tag';

class SingleAdvertComponent extends React.Component {

  constructor( props ) {
    super( props );
  }

  componentDidMount() {
    console.log( this.props.params.slug );
  }

  render() {
    return (
      <div className="cont">
        <h1 className="fw300 ttu tc">Advert!</h1>
      </div>
    );
  }
}

// Define the graphql query to retrieve the advert
const theAdvert = gql`
  query singleAdvert {
    singleAdvert ( slug: $slug ) {
      title,
      slug,
      type,
      image,
      excerpt,
      owner
    }
  }
`;

// Use the graphql container to run the query
const SingleAdvert = graphql( theAdvert, {
  options: ( { slug } ) => ({
    variables: { slug }
  }),
})( SingleAdvertComponent );

// Export the component
export default SingleAdvert;

The props are being passed into the SingleAdvertComponent properly, as the slug is being posted into the console. But I’ve tried a lot and can’t get the slug to go into the query.

I followed the guides and docs from Apollodata as you can probably see, but having no luck!

Any help will be appreciated as always.

Cheers :slight_smile:

Try this:

const theAdvert = gql`
  query singleAdvert ($slug: String) {
    singleAdvert ( slug: $slug ) {
      title,
      slug,
      type,
      image,
      excerpt,
      owner
    }
  }
`;

Hi @ric0 thanks for the suggestion! I’d already tried that, but it didn’t work (I also just put it back in, still no luck).

I hate to single anyone out, but @sashko you seem to be the dogs bollocks when it comes to helping with Apollo, any suggestions on your side?

Any other suggestions @ric0? Pulling my hair out a bit here as no idea what’s causing the error messages above :frowning:

Mhmm, very strange indeed.

Does this very same query work on localhost:3000/graphiql?

Bad Request 400 might be something about the formatting of the query.

On localhost:3000/graphiql you should get a more meaningful error.

Thanks for the help @ric0!

Ok, so this query:

{
  singleAdvert ( slug: "test-advert" ) {
    id
    image
    content
    excerpt
    owner
    title
    type
    slug
  }
}

at localhost:3000/graphiql (which should work as I have a slug with that value?) gives me the following:

{
  "errors": [
    {
      "message": "Unknown argument \"slug\" on field \"singleAdvert\" of type \"Query\".",
      "locations": [
        {
          "line": 2,
          "column": 17
        }
      ]
    }
  ]
}

So it might be the resolver function / schema. Which are:

singleAdvert( _, args ) {
  return Advert.findOne( { where: args } );
}

And

export default typeDefs = [`
type Advert {
  id: ID!
  type: String!
  title: String!
  slug: String!
  image: String!
  content: String!
  excerpt: String!
  owner: String!
}

type Query {
  adverts: [Advert]
  singleAdvert: Advert
}

type Mutation {
  createAdvert (
    type: String!
    title: String!
    slug: String!
    image: String!
    content: String!
    excerpt: String!
    owner: String!
  ): Advert
}

schema {
  query: Query
  mutation: Mutation
}
`];

Any more suggestions? Again many thanks for your help!

type Query {
  singleAdvert(slug: String): Advert
}
singleAdvert( _, args ) {
  return Advert.findOne( { where: args.slug } );
}

OR

singleAdvert( _, {slug} ) {
  return Advert.findOne( { where: slug } );
}
1 Like

Ok, pretty much there now but the query to the database isn’t quite right.

Here is the resolver now:

// Single advert display
singleAdvert( _, { slug } ) {
  return Advert.findOne( { where: { slug: slug } } );
},

But the resulting query to the database ends up like this (as an example):

SELECT "id" FROM "adverts" AS "advert" WHERE "advert"."slug" = 'a-test-advert' LIMIT 1;

Of course, it’s the “advert”.“slug” bit that’s wrong! It should just be “slug” and then it works.

Any idea why it’s doing this? Again many thanks for your help as I’d be way further behind without it :slight_smile:

[EDIT] I’m using Sequelize as the database connector. Here are their own docs for ‘where’. So the above ‘should’ work but doesn’t :cry:

Sorry, never used sequalize :stuck_out_tongue:

In any case try:

WHERE "advert.slug" = 'a-test-advert'

Hi @ric0,

Just letting you know I got this sorted! Here is my solution (bare in mind I use Sequelize, as mentioned above :slight_smile: ):

Resolver:

// Single advert display
singleAdvert( _, { slug } ) {
  return Advert.findOne({
    where: Sequelize.where( Sequelize.col( 'slug' ), slug )
  });
},

Then, because the resulting query doesn’t return an array (like a findAll does), the component stuff ends up like this:

SingleAdvertComponent.propTypes = {
  data: React.PropTypes.shape({
    singleAdvert: React.PropTypes.object,
  }).isRequired
};

// Define the graphql query to retrieve the advert
const theAdvert = gql`
  query singleAdvert ( $slug: String ) {
    singleAdvert ( slug: $slug ) {
      id,
      title,
      slug,
      type,
      image,
      content,
      owner
    }
  }
`;

// Use the graphql container to run the singleAdvert query
const SingleAdvert = graphql( theAdvert, {
  options: ( props ) => ({
    variables: {
      slug: props.params.slug
    }
  }),
})( SingleAdvertComponent );

// Export the component
export default SingleAdvert;

After that, you can access the content as you would any other object. HOWEVER, it will give an undefined error unless you do a check such as:

if( this.props.data.loading == false ) {
  const advert = this.props.data.singleAdvert;
  // Do some stuff
}

So yeah, all good! Thanks a lot for all your help and suggestions :slight_smile:

2 Likes

Happy to hear that :slight_smile:

And thank you for sharing here the final solution. I’m sure it’ll help other people, too.

1 Like