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

Converting from MobX+REST to Apollo+GraphQL #6

Open
wants to merge 34 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
8ccd93b
Add packages and scripts
JstnEdr Jan 20, 2021
e12ed25
Add next and graphql config files
JstnEdr Jan 20, 2021
e3b7e12
Initial graphql file setup
JstnEdr Jan 20, 2021
bc75a32
Add generated files by running yarn dev
JstnEdr Jan 20, 2021
a4d6256
Add auth graphql schema files
JstnEdr Jan 21, 2021
808c1be
Auto-generated files and OldUser cleanup
JstnEdr Jan 21, 2021
8236748
Implement auth query
JstnEdr Jan 21, 2021
ac00181
Adding signIn mutation with mock data
JstnEdr Jan 21, 2021
9ac240d
Auto-generated files -- currently with duplicates
JstnEdr Jan 21, 2021
8452912
Authentication setup and working
JstnEdr Jan 23, 2021
9a4c209
Authentication cleanup
JstnEdr Jan 23, 2021
d826b92
Removing and GitIgnoring GraphQL Files
JstnEdr Jan 25, 2021
3ea89c2
Toast state now managed in Apollo client
JstnEdr Jan 25, 2021
350a2ce
Added graphql hooks and resolvers for shows
JstnEdr Jan 26, 2021
c25d8fe
GraphQL data implementation complete
JstnEdr Jan 27, 2021
4a3bddf
Cleaning up auth types and queries
JstnEdr Jan 27, 2021
2efed02
Consistant file names for reactiveVars
JstnEdr Jan 27, 2021
f867916
Remove unused stores and add .state files
JstnEdr Jan 27, 2021
aceb824
showMapper in place
JstnEdr Jan 28, 2021
cd783fb
updated cast
JstnEdr Jan 28, 2021
e3c43a0
Added GraphQL Server types and reducers
JstnEdr Jan 28, 2021
1eff1a1
Apollo client and server naming cleanup
JstnEdr Jan 28, 2021
b0b0ed5
Remove mobx and all stores
JstnEdr Jan 28, 2021
52b0090
Move server files from lib to sever directory
JstnEdr Jan 28, 2021
d71f9b3
Rename server directory to apollo
JstnEdr Jan 28, 2021
a0265cc
Renaming and moving Graphql queries into domain directory
JstnEdr Jan 28, 2021
78bad3a
Removing Auth http service
JstnEdr Jan 28, 2021
d09a27e
Remove http utils
JstnEdr Jan 28, 2021
b1b4ef2
Merge branch 'main' of github.com:codeBelt/mobx-local-global-stores i…
JstnEdr Jan 29, 2021
11c4b0b
Move shows.constants
JstnEdr Jan 29, 2021
2b91def
Fixing import locations
JstnEdr Jan 29, 2021
4c44d9e
Removed commented code
JstnEdr Jan 29, 2021
9acd060
Removed commented code
JstnEdr Jan 29, 2021
d111d24
Fixed missing import
JstnEdr Feb 10, 2021
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
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,9 @@ yarn-error.log*

# vercel
.vercel

# graphql generated files
**/*/*.graphql.d.ts
**/*/*.graphqls.d.ts
**/*/*.graphql.tsx
**/*/*.graphqls.tsx
19 changes: 19 additions & 0 deletions .graphql-let.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# https://graphql-code-generator.com/
# https://github.com/piglovesyou/graphql-let#experimental-feature-resolver-types
# https://the-guild.dev/blog/better-type-safety-for-resolvers-with-graphql-codegen
# https://graphql-code-generator.com/docs/plugins/typescript-resolvers#use-your-model-types-mappers

schema: 'src/**/*.graphqls'
schemaEntrypoint: 'src/apollo/type-defs.graphqls'
documents: 'src/**/*.graphql'
plugins:
- typescript
- typescript-operations
- typescript-react-apollo
# - typescript-resolvers TODO: not sure why this isn't working--see links above
config:
contextType: .apollo/context.models#ContextModel
mappers:
# Show: ./apollo/shows/shows.models#ShowModel
# Cast: ./apollo/shows/shows.models#CastModel
cacheDir: __generated__
20 changes: 19 additions & 1 deletion next.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ module.exports = withPlugins(
}),
],
{
webpack(config) {
webpack(config, options) {
config.resolve.alias = {
...config.resolve.alias,
// https://blog.usejournal.com/my-awesome-custom-react-environment-variables-setup-8ebb0797d8ac
Expand All @@ -23,6 +23,24 @@ module.exports = withPlugins(
process.env.NODE_ENV === 'production' ? new DuplicatePackageCheckerPlugin() : null,
].filter(Boolean);

config.module.rules.push({
test: /\.graphql$/,
exclude: /node_modules/,
use: [options.defaultLoaders.babel, { loader: 'graphql-let/loader' }],
});

config.module.rules.push({
test: /\.graphqls$/,
exclude: /node_modules/,
use: ['graphql-let/schema/loader'],
});

config.module.rules.push({
test: /\.ya?ml$/,
type: 'json',
use: 'yaml-loader',
});

return config;
},
}
Expand Down
25 changes: 20 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@
}
},
"scripts": {
"dev": "CLIENT_ENV=development next",
"build": "next build",
"codegen": "graphql-let",
"dev": "yarn codegen && CLIENT_ENV=development next",
"build": "yarn codegen && next build",
"start": "next start",
"---------- Linting ----------------------------------------------------": "",
"eslint": "eslint --quiet \"*/**/*.{ts,tsx}\"",
Expand All @@ -28,14 +29,21 @@
"-----------------------------------------------------------------------": ""
},
"dependencies": {
"@apollo/client": "3.3.7",
"@graphql-tools/load-files": "6.2.5",
"@graphql-tools/merge": "6.2.7",
"@graphql-tools/schema": "7.1.2",
"@material-ui/core": "4.11.3",
"apollo-datasource-rest": "0.9.7",
"apollo-server-micro": "2.19.2",
"axios": "0.21.1",
"clsx": "1.1.1",
"dayjs": "1.10.4",
"graphql": "15.4.0",
"graphql-let": "0.16.3",
"graphql-tag": "2.11.0",
"lodash.groupby": "4.6.0",
"lodash.orderby": "4.6.0",
"mobx": "6.1.1",
"mobx-react": "7.1.0",
"next": "10.0.5",
"notistack": "1.0.3",
"nprogress": "0.2.0",
Expand All @@ -45,6 +53,12 @@
"semantic-ui-react": "2.0.3"
},
"devDependencies": {
"@graphql-codegen/cli": "1.20.0",
"@graphql-codegen/plugin-helpers": "1.18.2",
"@graphql-codegen/typescript": "1.20.0",
"@graphql-codegen/typescript-operations": "1.17.13",
"@graphql-codegen/typescript-react-apollo": "2.2.1",
"@graphql-codegen/typescript-resolvers": "1.18.1",
"@next/bundle-analyzer": "10.0.5",
"@types/lodash.groupby": "4.6.6",
"@types/lodash.orderby": "4.6.6",
Expand All @@ -69,7 +83,8 @@
"prettier": "2.2.1",
"pretty-quick": "3.1.0",
"sass": "1.32.5",
"typescript": "4.1.3"
"typescript": "4.1.3",
"yaml-loader": "0.6.0"
},
"license": "MIT"
}
71 changes: 71 additions & 0 deletions src/apollo/apolloClient.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import { IncomingMessage, ServerResponse } from 'http';
import { useMemo } from 'react';
import { ApolloClient, InMemoryCache, NormalizedCacheObject } from '@apollo/client';
import { toastItemsVar } from '../domains/toasts/toasts.state';

let apolloClient: ApolloClient<NormalizedCacheObject> | undefined;

export type ResolverContext = {
req?: IncomingMessage;
res?: ServerResponse;
};

const createIsomorphLink = (context: ResolverContext = {}) => {
if (typeof window === 'undefined') {
const { SchemaLink } = require('@apollo/client/link/schema');
const { schema } = require('./schema');
return new SchemaLink({ schema, context });
} else {
const { HttpLink } = require('@apollo/client');
return new HttpLink({
uri: '/api/graphql',
credentials: 'same-origin',
});
}
};

const createApolloClient = (context?: ResolverContext) => {
return new ApolloClient({
ssrMode: typeof window === 'undefined',
link: createIsomorphLink(context),
cache: new InMemoryCache({
typePolicies: {
Query: {
fields: {
toastItems: {
read() {
return toastItemsVar();
},
},
},
},
},
}),
});
};

export const initializeApollo = (
initialState: any = null,
// Pages with Next.js data fetching methods, like `getStaticProps`, can send
// a custom context which will be used by `SchemaLink` to server render pages
context?: ResolverContext
) => {
const _apolloClient = apolloClient ?? createApolloClient(context);

// If your page has Next.js data fetching methods that use Apollo Client, the initial state
// get hydrated here
if (initialState) {
_apolloClient.cache.restore(initialState);
}
// For SSG and SSR always create a new Apollo Client
if (typeof window === 'undefined') return _apolloClient;
// Create the Apollo Client once in the client
if (!apolloClient) apolloClient = _apolloClient;

return _apolloClient;
};

export const useApollo = (initialState: any) => {
const store = useMemo(() => initializeApollo(initialState), [initialState]);
return store;
};
19 changes: 19 additions & 0 deletions src/apollo/apolloServer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { ApolloServer } from 'apollo-server-micro';
import { ShowsAPI } from './shows/shows.datasource';
import { AuthenticationAPI } from './auth/auth.datasource';
import { schema } from './schema';

export const apolloServer = new ApolloServer({
schema,
dataSources: () => {
return {
showsAPI: new ShowsAPI(),
authAPI: new AuthenticationAPI(),
};
},
context: () => {
return {
token: 'foo',
};
},
});
19 changes: 19 additions & 0 deletions src/apollo/auth/auth.datasource.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { RESTDataSource } from 'apollo-datasource-rest';
import { Auth } from 'apollo/type-defs.graphqls';
import environment from 'environment';
import { authReducer } from './auth.reducers';

export class AuthenticationAPI extends RESTDataSource {
constructor() {
super();
this.baseURL = environment.api.userBase;
}

async authenticateUser(showId: string): Promise<Auth> {
const randomUser = await this.get(
`?inc=gender,name` // path
);

return authReducer(randomUser);
}
}
4 changes: 4 additions & 0 deletions src/apollo/auth/auth.graphqls
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
type Auth {
isAuthenticated: Boolean!
userFullName: String!
}
22 changes: 22 additions & 0 deletions src/apollo/auth/auth.models.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
export interface AuthModel {
results: UserModel[];
info: UserResponseInfoModel;
}

export interface UserModel {
gender: string;
name: UserNameModel;
}

export interface UserNameModel {
title: string;
first: string;
last: string;
}

export interface UserResponseInfoModel {
seed: string;
results: number;
page: number;
version: string;
}
9 changes: 9 additions & 0 deletions src/apollo/auth/auth.reducers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { Auth } from 'apollo/type-defs.graphqls';
import { AuthModel } from './auth.models';

export const authReducer = (user: AuthModel): Auth => {
return {
isAuthenticated: Boolean(user),
userFullName: `${user?.results[0]?.name?.first} ${user?.results[0]?.name?.last}`,
};
};
9 changes: 9 additions & 0 deletions src/apollo/context.models.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { AuthenticationAPI } from './auth/auth.datasource';
import { ShowsAPI } from './shows/shows.datasource';

export type ContextModel = {
dataSources: {
showsAPI: ShowsAPI;
authAPI: AuthenticationAPI;
};
};
20 changes: 20 additions & 0 deletions src/apollo/resolvers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { Resolvers } from './type-defs.graphqls';

export const resolvers: Resolvers = {
Query: {
cast: async (_parent, _args, _context, _info) => {
return _context.dataSources.showsAPI.getCast(_args.showId);
},
show: async (_parent, _args, _context, _info) => {
return _context.dataSources.showsAPI.getShowDetails(_args.showId);
},
episodes: async (_parent, _args, _context, _info) => {
return _context.dataSources.showsAPI.getEpisodes(_args.showId);
},
},
Mutation: {
signIn: async (_parent, _args, _context, _info) => {
return _context.dataSources.authAPI.authenticateUser();
},
},
};
14 changes: 14 additions & 0 deletions src/apollo/schema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { join } from 'path';
import { makeExecutableSchema } from '@graphql-tools/schema';
import { loadFilesSync } from '@graphql-tools/load-files';
import { mergeTypeDefs } from '@graphql-tools/merge';
import graphQLLetConfig from '../../.graphql-let.yml';
import { resolvers } from './resolvers';

const loadedFiles = loadFilesSync(join(process.cwd(), graphQLLetConfig.schema));
const typeDefs = mergeTypeDefs(loadedFiles);

export const schema = makeExecutableSchema({
typeDefs,
resolvers,
});
35 changes: 35 additions & 0 deletions src/apollo/shows/shows.datasource.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { RESTDataSource } from 'apollo-datasource-rest';
import environment from 'environment';
import { Cast, Episode, Show } from 'lib/type-defs.graphqls';
import { castReducer, episodeReducer, showReducer } from './shows.reducers';

export class ShowsAPI extends RESTDataSource {
constructor() {
super();
this.baseURL = environment.api.showsBase;
}

async getShowDetails(showId: string): Promise<Show> {
const show = await this.get(
`${showId}` // path
);

return showReducer(show);
}

async getCast(showId: string): Promise<Cast[]> {
const cast = await this.get(
`${showId}/cast` // path
);

return castReducer(cast);
}

async getEpisodes(showId: string): Promise<Episode[]> {
const episodes = await this.get(
`${showId}/episodes` // path
);

return episodeReducer(episodes);
}
}
Loading