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

Feature: API for providing a path-builder function #69

Closed
HeyHugo opened this issue Feb 17, 2018 · 9 comments
Closed

Feature: API for providing a path-builder function #69

HeyHugo opened this issue Feb 17, 2018 · 9 comments

Comments

@HeyHugo
Copy link
Contributor

HeyHugo commented Feb 17, 2018

For usecases like #67 where you need to handle query string parameters that are optional you can't right now.

I've looked a bit at how bodyBuilder and bodyKey are used to allow custom body handling.

I propose that an optional argument of type function is added to the rest-directive pathBuilder that if set is used to build the path string. The function would take the variables object as input.

We can keep the current path parameter as is. Only if pathBuilder is provided it overrides.

Here is an example using the pathBuilder to handle query strings arg:

const query = gql`
  query FilterItems(
    $priceMin: Int
    $priceMax: Int
    $createPath: any
  ) {
    filterItems(priceMin: $priceMin, priceMax: $priceMax)
      @rest(type: "Item", pathBuilder: $createPath) {
      id
      name
      price
    }
  }
`
function createQueryStringPath(variables) {
  const qs = Object.keys(
    variables,
  ).reduce((acc, key): string => {
    if (variables[key] === null || variables[key] === undefined) {
      return acc;
    }
    if (acc === '') {
      return '?' + key + '=' + encodeURIComponent(variables[key].toString());
    }
    return acc + '&' + key + '=' + encodeURIComponent(variables[key].toString());
  }, '');
  return '/items' + qs;
}

client.query({
  query,
  variables: {
    priceMin: 5,
    priceMax: 20,
    createPath: createQueryStringPath
  }
});

I can try to make a PR if you like the idea.

@jslowack
Copy link
Contributor

I like the idea, but wouldn't it be more appropriate to create a query builder instead of a path builder? In this way we could use existing query builders as a parameter and we keep the path separated from the query string formatting function.

Modified code would look like this:

const query = gql`
  query FilterItems(
    $priceMin: Int
    $priceMax: Int
    $queryBuilder: any
  ) {
    filterItems(priceMin: $priceMin, priceMax: $priceMax)
      @rest(type: "Item", path: "items", queryBuilder: $queryBuilder) {
      id
      name
      price
    }
  }
import queryString from 'query-string';
client.query({
  query,
  variables: {
    priceMin: 5,
    priceMax: 20,
    queryBuilder: queryString.stringify
  }
});

Another (small) remark is that we should exclude our "builder function" out of the incoming variables parameter.

@fbartho
Copy link
Collaborator

fbartho commented Feb 17, 2018

@jslowack That assumes that the REST API you're working is structured cleanly to take parameters in the Query string. A pathBuilder would be slightly more generic as it could tweak the path or the query string appropriately for your REST API -- and as a fundamental tenet of apollo-link-rest we're assuming you're doing this because you can't necessarily change the backend at this time, and you might not even control the REST API.

HeyHugo added a commit to HeyHugo/apollo-link-rest that referenced this issue Feb 17, 2018
pathBuilder is a user provided function via a graphql variable to build up the path string. A use case it enables is having one or more optional query string parameters e.g:
"/items/filter?minPrice=5&maxPrice=20"
Here minPrice and maxPrice could be omitted

See proposal in apollographql#69 and the problem it solves in apollographql#67
@fbartho
Copy link
Collaborator

fbartho commented Feb 18, 2018

@HeyHugo, remember to use encodeURIComponent in your example code/unit test! (We want to be showing best practices in our examples :) )

@fbartho
Copy link
Collaborator

fbartho commented Feb 18, 2018

@jslowack Thinking more about what you were saying, would you mind elaborating about "existing query builders"? I don't know what you're referring to, so I don't know what reuse there would be valuable. Thanks!

@HeyHugo
Copy link
Contributor Author

HeyHugo commented Feb 18, 2018

Good idea @fbartho, thinking bout it maybe we'd want to always run encodeURIComponent on pathWithParams in the library code, or would it be confusing for people having uri-encoding they did not explicitly do themselves?

For the default path arg there is no uri-encoding happening currently.

@HeyHugo
Copy link
Contributor Author

HeyHugo commented Feb 18, 2018

Ah disregard my previous comment, I was mixing up encodeURIComponent and encodeURI.

If anything we would instead use encodeURI(uri + pathWithParams) but maybe thats not necessary.

@jslowack
Copy link
Contributor

@fbartho for example https://github.com/sindresorhus/query-string. I agree that a pathBuilder is more generic. I personally just don't like the idea of a graphQL query where the path (or endpoint) is generic..

we're assuming you're doing this because you can't necessarily change the backend at this time, and you might not even control the REST API

True! With this in mind, it makes more sense to create a path builder.

HeyHugo added a commit to HeyHugo/apollo-link-rest that referenced this issue Feb 18, 2018
pathBuilder is a user provided function via a graphql variable to build up the path string. A use case it enables is having one or more optional query string parameters e.g:
"/items/filter?minPrice=5&maxPrice=20"
Here minPrice and maxPrice could be omitted

See proposal in apollographql#69 and the problem it solves in apollographql#67
HeyHugo added a commit to HeyHugo/apollo-link-rest that referenced this issue Feb 18, 2018
pathBuilder is a user provided function via a graphql variable to build up the path string. A use case it enables is having one or more optional query string parameters e.g:
"/items/filter?minPrice=5&maxPrice=20"
Here minPrice and maxPrice could be omitted

See proposal in apollographql#69 and the problem it solves in apollographql#67
HeyHugo added a commit to HeyHugo/apollo-link-rest that referenced this issue Feb 18, 2018
pathBuilder is a user provided function via a graphql variable to build up the path string. A use case it enables is having one or more optional query string parameters e.g:
"/items/filter?minPrice=5&maxPrice=20"
Here minPrice and maxPrice could be omitted

See proposal in apollographql#69 and the problem it solves in apollographql#67
@fbartho fbartho changed the title Idea: API for providing a path builder function Feature: API for providing a path-builder function Feb 19, 2018
@fbartho
Copy link
Collaborator

fbartho commented Feb 19, 2018

@HeyHugo -- I thought about that, and I think @rest( is generally low level enough that it can't know if it should encode URIs automatically in the general case. Double-encoding would be a bad thing, and I don't think users could protect themselves if we did mangle it, so I'm going to say: treat query-strings as something to document, which is why I made my suggestion about your example calling encodeURIComponent

@fbartho
Copy link
Collaborator

fbartho commented Feb 19, 2018

Implemented via #70 !

@fbartho fbartho closed this as completed Feb 19, 2018
@fbartho fbartho added this to the v0.2.0 milestone Feb 23, 2018
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

3 participants