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

Add pathBuilder argument to @rest directive #70

Merged
merged 1 commit into from
Feb 19, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 79 additions & 0 deletions src/__tests__/restLink.ts
Original file line number Diff line number Diff line change
Expand Up @@ -772,6 +772,85 @@ describe('Query single call', () => {
post: { ...postWithNest, __typename: 'Post' },
});
});

it('can build the path using pathBuilder', async () => {
expect.assertions(1);

const link = new RestLink({ uri: '/api' });
const posts = [{ id: '1', title: 'Love apollo' }];
fetchMock.get('/api/posts?status=published', posts);

const postTitleQuery = gql`
query postTitle($pathFunction: any, $status: String) {
posts(status: $status) @rest(type: "Post", pathBuilder: $pathFunction) {
id
title
}
}
`;

function createPostsPath(variables) {
const qs = Object.keys(
variables,
).reduce((acc: string, key: string): string => {
if (variables[key] === null || variables[key] === undefined) {
return acc;
}
if (acc === '') {
return '?' + key + '=' + encodeURIComponent(String(variables[key]));
}
return (
acc + '&' + key + '=' + encodeURIComponent(String(variables[key]))
);
}, '');
return '/posts' + qs;
}

const { data } = await makePromise<Result>(
execute(link, {
operationName: 'postTitle',
query: postTitleQuery,
variables: {
status: 'published',
pathFunction: createPostsPath,
},
}),
);

expect(data).toMatchObject({
posts: [{ ...posts[0], __typename: 'Post' }],
});
});

it('throws if missing both path and pathBuilder', async () => {
expect.assertions(1);

const link = new RestLink({ uri: '/api' });
const post = { id: '1', title: 'Love apollo' };
fetchMock.get('/api/post/1', post);

const postTitleQuery = gql`
query postTitle {
post @rest(type: "Post") {
id
title
}
}
`;

try {
await makePromise<Result>(
execute(link, {
operationName: 'postTitle',
query: postTitleQuery,
}),
);
} catch (error) {
expect(error.message).toBe(
'Parmeter "path" or "pathBuilder" must be set in @rest directive',
);
}
});
});

describe('Query multiple calls', () => {
Expand Down
43 changes: 33 additions & 10 deletions src/restLink.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,12 +107,18 @@ export namespace RestLink {
/** What GraphQL type to name the response */
type?: string;
/** What path to use */
path: string;
path?: string;
/**
* What endpoint to select from the map of endpoints available to this link.
* @default `RestLink.endpoints[DEFAULT_ENDPOINT_KEY]`
*/
endpoint?: string;
/**
* Optional function that constructs a request path out of the Environmental state
* when processing this @rest(...) call.
* @default function that produces a request path string from the args.
*/
pathBuilder?: (args: object) => string;
/**
* Optional method that constructs a RequestBody out of the Environmental state
* when processing this @rest(...) call.
Expand Down Expand Up @@ -387,19 +393,36 @@ const resolver: Resolver = async (
typePatcher,
fieldNameDenormalizer: linkLevelNameDenormalizer,
} = context;
const { path, endpoint } = directives.rest as RestLink.DirectiveOptions;
let {
path,
endpoint,
pathBuilder,
} = directives.rest as RestLink.DirectiveOptions;
const uri = getURIFromEndpoints(endpoints, endpoint);
try {
const argsWithExport = { ...args, ...exportVariables };
let pathWithParams = Object.keys(argsWithExport).reduce(
(acc, e) => replaceParam(acc, e, argsWithExport[e]),
path,
);
if (pathWithParams.includes(':')) {
throw new Error(
'Missing params to run query, specify it in the query params or use an export directive',
);

if (!pathBuilder) {
if (!path) {
throw new Error(
'Parmeter "path" or "pathBuilder" must be set in @rest directive',
);
}
pathBuilder = (args: object): string => {
const pathWithParams = Object.keys(args).reduce(
(acc, e) => replaceParam(acc, e, args[e]),
path,
);
if (pathWithParams.includes(':')) {
throw new Error(
'Missing params to run query, specify it in the query params or use an export directive',
);
}
return pathWithParams;
};
}
const pathWithParams = pathBuilder(argsWithExport);

let {
method,
type,
Expand Down