Skip to content

Commit 2a95239

Browse files
committed
User: Register user, login, server side rendering current user with cookie, successful login redirect all working. Using a GraphQL mutation to create the user and passport to redirect.
1 parent e4239fb commit 2a95239

File tree

16 files changed

+316
-175
lines changed

16 files changed

+316
-175
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
node_modules
22
npm-debug.log
33
logs
4+
coverage
45

56
.next
67
build/static

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
"apollo-server-express": "^1.1.2",
3434
"babel-runtime": "^6.26.0",
3535
"body-parser": "^1.17.2",
36+
"cookie": "^0.3.1",
3637
"cookie-parser": "^1.4.3",
3738
"debug": "^3.0.1",
3839
"dotenv": "^4.0.0",

src/data/HNDataAPI.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ export function fetchNewsItem(id) {
4747
}
4848
throw post;
4949
})
50-
.catch(reason => logger(`Fetching news item failed: ${reason}`));
50+
.catch(reason => logger(`Fetching post failed: ${reason}`));
5151
}
5252

5353
export function fetchComment(id) {
@@ -77,7 +77,7 @@ export function getFeed(feedType) {
7777
logger(`Fetching /${feedType}stories.json`);
7878
return api.child(`${feedType}stories`).once('value')
7979
.then(feedSnapshot => feedSnapshot.val())
80-
.then(feed => feed.filter(newsItem => newsItem !== undefined))
80+
.then(feed => feed.filter(newsItem => newsItem !== undefined && newsItem !== null))
8181
.catch(reason => logger(`Fetching news feed failed: ${reason}`));
8282
}
8383

@@ -87,7 +87,7 @@ const rebuildFeed = (feedType) => {
8787
.then(feed => Promise.all(feed.map(id => fetchNewsItem(id)))
8888
.then((newsItems) => {
8989
logger(newsItems);
90-
Feed[`${feedType}NewsItems`] = newsItems;
90+
Feed[`${feedType}NewsItems`] = newsItems.filter(newsItem => newsItem !== undefined && newsItem !== null);
9191
Feed[feedType] = feed;
9292
logger(`Updated ${feedType} ids`);
9393
}),

src/data/Schema.js

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,14 @@ import {
77
import {
88
makeExecutableSchema,
99
} from 'graphql-tools';
10+
import debug from 'debug';
1011

1112
// Read the complete docs for graphql-tools here:
1213
// http://dev.apollodata.com/tools/graphql-tools/generate-schema.html
1314

15+
const logger = debug('app:Schema');
16+
logger.log = console.log.bind(console);
17+
1418
/*
1519
Schema properties are in following order:
1620
Alphabetical
@@ -161,7 +165,7 @@ const typeDefs = `
161165
162166
`;
163167

164-
const resolvers = {
168+
export const resolvers = {
165169

166170
/*
167171
http://dev.apollodata.com/tools/graphql-tools/resolvers.html
@@ -193,7 +197,10 @@ const resolvers = {
193197
return context.Feed.getForType(type, limit, skip);
194198
},
195199

196-
me: (_, __, context) => context.userId && context.User.getUser(context.userId),
200+
me: (_, __, context) => {
201+
logger('Me: userId:', context.userId);
202+
return context.userId && context.User.getUser(context.userId);
203+
},
197204

198205
newsItem: (_, { id }, context) => context.NewsItem.getNewsItem(id),
199206

src/data/__mocks__/HNDataAPI.js

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import {
2+
HN_API_URL,
3+
} from '../../config';
4+
5+
import data from '../SampleData';
6+
7+
// https://github.com/HackerNews/API
8+
9+
/* BEGIN NEWS ITEMS */
10+
11+
12+
export function fetchNewsItem(id) {
13+
return data.topStoriesCache.find(item => item.id === id);
14+
}
15+
16+
export function fetchComment(id) {
17+
return data.topStoriesCache[0].find(item => item.id === id);
18+
}
19+
20+
// export function getFeed(feedType) {
21+
// return data[feedType];
22+
// }
23+
24+
// const rebuildFeed = (feedType) => {
25+
// setTimeout(rebuildFeed, 1000 * 60 * 15, feedType);
26+
// getFeed(feedType)
27+
// .then(feed => Promise.all(feed.map(id => fetchNewsItem(id)))
28+
// .then((newsItems) => {
29+
// logger(newsItems);
30+
// Feed[`${feedType}NewsItems`] = newsItems;
31+
// Feed[feedType] = feed;
32+
// logger(`Updated ${feedType} ids`);
33+
// }),
34+
// )
35+
// .catch(reason => logger(`Error building feed: ${reason}`));
36+
};
37+
38+
/* END NEWS ITEMS */
39+

src/data/__tests__/Schema.js

Lines changed: 54 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,50 +1,61 @@
1-
import data from '../../data/SampleData';
1+
import { resolvers } from '../Schema';
22

3-
const comment = data.topStoriesCache[0].comments[0];
3+
import data from '../../data/SampleData';
44

5-
describe('GraphQL', () => {
6-
describe('Queries', () => {
7-
it('returns expected data for Feed query', () => {
8-
9-
expect(comment);
10-
});
11-
it('returns expected data for Comment query', () => {
12-
13-
expect(comment);
14-
});
15-
it('returns expected data for Me query', () => {
16-
17-
expect(comment);
18-
});
19-
it('returns expected data for News Item query', () => {
20-
21-
expect(comment);
22-
});
23-
it('returns expected data for User query', () => {
24-
25-
expect(comment);
26-
});
27-
});
5+
// const comment = data.topStoriesCache[0].comments[0];
286

29-
describe('Mutations', () => {
30-
it('returns data for upvoteNewsItem mutation', () => {
31-
32-
expect(comment);
33-
});
34-
it('returns data for submitNewsItem mutation', () => {
35-
36-
expect(comment);
37-
});
38-
});
397

40-
describe('Property Resolvers', () => {
41-
it('newsItem author is a user', () => {
42-
43-
expect(comment);
44-
});
45-
it('newsItem comments are comments', () => {
46-
47-
expect(comment);
8+
describe('GraphQL', () => {
9+
describe('Resolvers', () => {
10+
describe('Queries', () => {
11+
it('returns expected data for query on Feed', () => {
12+
expect(true);
13+
});
14+
it('returns expected data for query on Comment', () => {
15+
const result = resolvers.Query.comment(
16+
undefined,
17+
{ id: data.topStoriesCache[0].comments[0].id },
18+
{
19+
Comment: {
20+
getComment: id => data.topStoriesCache[0].comments.find(comment => comment.id === id),
21+
},
22+
},
23+
);
24+
expect(result).toBeDefined();
25+
});
26+
it('returns expected data for query on Me', () => {
27+
28+
expect(true);
29+
});
30+
it('returns expected data for News Item query', () => {
31+
32+
expect(true);
33+
});
34+
it('returns expected data for User query', () => {
35+
36+
expect(true);
37+
});
38+
});
39+
describe('Mutations', () => {
40+
it('returns data for upvoteNewsItem mutation', () => {
41+
42+
expect(true);
43+
});
44+
it('returns data for submitNewsItem mutation', () => {
45+
46+
expect(true);
47+
});
48+
});
49+
50+
describe('Property Resolvers', () => {
51+
it('newsItem author is a user', () => {
52+
53+
expect(true);
54+
});
55+
it('newsItem comments are comments', () => {
56+
57+
expect(true);
58+
});
4859
});
4960
});
5061
});

src/helpers/initApollo.js

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,49 @@
1+
import { ApolloClient, createNetworkInterface } from 'react-apollo';
12
import fetch from 'isomorphic-fetch';
2-
import {
3-
ApolloClient,
4-
createNetworkInterface,
5-
} from 'react-apollo';
3+
import debug from 'debug';
4+
65
import {
76
GRAPHQL_URL,
87
} from '../config';
98

9+
const logger = debug('app:initApollo');
10+
logger.log = console.log.bind(console);
11+
1012
let apolloClient = null;
1113

1214
// Polyfill fetch() on the server (used by apollo-client)
1315
if (!process.browser) {
1416
global.fetch = fetch;
1517
}
1618

17-
function create(initialState) {
19+
function create(initialState, { getToken }) {
1820
return new ApolloClient({
1921
initialState,
2022
ssrMode: !process.browser, // Disables forceFetch on the server (so queries are only run once)
2123
networkInterface: createNetworkInterface({
2224
uri: GRAPHQL_URL, // Server URL (must be absolute)
23-
opts: { // Additional fetch() options like `credentials` or `headers`
25+
opts: {
26+
// Additional fetch() options like `credentials` or `headers`
2427
credentials: 'same-origin',
28+
headers: {
29+
// HTTP Header: Cookie: <cookiename>=<cookievalue>
30+
Cookie: `${'connect.sid'}=${getToken()['connect.sid']}`,
31+
},
2532
},
2633
}),
2734
});
2835
}
2936

30-
export default function initApollo(initialState) {
37+
export default function initApollo(initialState, options) {
3138
// Make sure to create a new client for every server-side request so that data
3239
// isn't shared between connections (which would be bad)
3340
if (!process.browser) {
34-
return create(initialState);
41+
return create(initialState, options);
3542
}
3643

3744
// Reuse client on the client-side
3845
if (!apolloClient) {
39-
apolloClient = create(initialState);
46+
apolloClient = create(initialState, options);
4047
}
4148

4249
return apolloClient;

0 commit comments

Comments
 (0)