Skip to content
This repository was archived by the owner on Jul 16, 2024. It is now read-only.

Commit db1cefe

Browse files
GraphQL + typescript + dev environment setup
1 parent afd90b8 commit db1cefe

File tree

17 files changed

+848
-46
lines changed

17 files changed

+848
-46
lines changed

README.md

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,23 @@ This app is intended to show off Dgraph quick start, and integration with Auth0.
44

55
# Running
66

7-
To run, you just need to
7+
To run, you just need to get the Dgraph GraphQL backend running with
8+
9+
```sh
10+
./deploy/dev-setup/run.sh up
11+
```
12+
13+
That brings up Dgraph in a docker container and adds the seed data.
14+
15+
Then
816

917
```
1018
yarn install
1119
yarn start
1220
```
1321

22+
Brings up the React app.
23+
1424
# How it was built
1525

1626
There's a blog about building this app (FIXME: insert link)

apollo.config.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
module.exports = {
2+
client: {
3+
service: {
4+
name: 'local',
5+
url: 'http://localhost:8080/graphql',
6+
},
7+
includes: ["src/**/operations.graphql", "deploy/**/operations.graphql"],
8+
excludes: ["src/**/*.{ts}", "deploy/**/*.{ts}"]
9+
}
10+
};

codegen.yml

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
overwrite: true
2+
schema: "http://localhost:8080/graphql"
3+
documents:
4+
- 'src/**/*.graphql'
5+
- 'deploy/**/*.graphql'
6+
generates:
7+
src/types/graphql.ts:
8+
plugins:
9+
- typescript
10+
src/:
11+
preset: near-operation-file
12+
presetConfig:
13+
baseTypesPath: types/graphql
14+
folder: types
15+
extension: .ts
16+
plugins:
17+
- typescript-operations
18+
- typescript-react-apollo
19+
config:
20+
reactApolloVersion: 3
21+
withHOC: false
22+
withHooks: true
23+
withComponent: false

deploy/.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
config.json
2+
config-dev.json
3+
config-prod.json

deploy/dev-setup/load-data.ts

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
import fetch from "cross-fetch"
2+
import { ApolloClient, InMemoryCache, HttpLink } from "@apollo/client"
3+
import { GraphQLError } from "graphql"
4+
import { AddCategoryInput, AddPostInput } from "../../src/types/graphql"
5+
import {
6+
InitCategoriesMutation,
7+
InitCategoriesMutationVariables,
8+
InitCategoriesDocument,
9+
InitPostsMutation,
10+
InitPostsMutationVariables,
11+
InitPostsDocument,
12+
} from "./types/operations"
13+
14+
const client = new ApolloClient({
15+
cache: new InMemoryCache(),
16+
link: new HttpLink({
17+
uri: "http://localhost:8080/graphql",
18+
fetch: fetch,
19+
}),
20+
})
21+
22+
const categories: Array<AddCategoryInput> = [
23+
{ name: "GraphQL" },
24+
{ name: "Dgraph" },
25+
{ name: "React" },
26+
]
27+
28+
const qsQuote = `
29+
With Dgraph you design your application in GraphQL. You design a set of GraphQL types that describes your requirements. Dgraph takes those types, prepares graph storage for them and generates a GraphQL API with queries and mutations.
30+
31+
You design a graph, store a graph and query a graph. You think and design in terms of the graph that your app is based around.
32+
`
33+
34+
const docsQuote = `
35+
Dgraph creates a GraphQL API from nothing more than GraphQL types. That's great, and gets you moving fast from an idea to a running app. However, at some point, as your app develops, you might want to customize the behaviour of your schema.
36+
37+
In Dgraph, you do that with code (in any language you like) that implements custom resolvers.
38+
39+
Dgraph doesn't execute your custom logic itself. It makes external HTTP requests. That means, you can deploy your custom logic into the same Kubernetes cluster as your Dgraph instance, deploy and call, for example, AWS Lambda functions, or even make calls to existing HTTP and GraphQL endpoints.
40+
`
41+
42+
const posts: Array<AddPostInput> = [
43+
{
44+
title: "My first post about GraphQL",
45+
text: qsQuote,
46+
category: { name: "GraphQL" },
47+
},
48+
{
49+
title: "Let me quote from the docs",
50+
text: docsQuote,
51+
category: { name: "GraphQL" },
52+
},
53+
{
54+
title: "I know some things about Dgraph",
55+
text: "It's a GraphQL native DB written from the disk up in Go.",
56+
category: { name: "Dgraph" },
57+
},
58+
{
59+
title: "How should I layout my components?",
60+
text: "Oh man, I can do the code, but the layout, that's not my thing.",
61+
category: { name: "React" },
62+
},
63+
{
64+
title: "Where should I deploy my frontend app?",
65+
text: "Currently",
66+
category: { name: "React" },
67+
},
68+
]
69+
70+
async function installData(): Promise<Readonly<GraphQLError[]> | undefined> {
71+
const { data: categoryData, errors: categoryErrors } = await client.mutate<
72+
InitCategoriesMutation,
73+
InitCategoriesMutationVariables
74+
>({
75+
mutation: InitCategoriesDocument,
76+
variables: { categories },
77+
})
78+
79+
if (categoryErrors || !categoryData?.addCategory?.category ) {
80+
return categoryErrors
81+
}
82+
83+
console.log(`added ` + categoryData.addCategory.category.length + ` users`)
84+
85+
for (let cat of categoryData.addCategory.category) {
86+
for (let post of posts) {
87+
if (cat && cat.name === post.category.name) {
88+
post.category.id = cat.id
89+
}
90+
}
91+
}
92+
93+
const { data: postsData, errors: postsErrors } = await client.mutate<
94+
InitPostsMutation,
95+
InitPostsMutationVariables
96+
>({
97+
mutation: InitPostsDocument,
98+
variables: { posts },
99+
})
100+
101+
if (postsErrors || !postsData?.addPost?.post) {
102+
return postsErrors
103+
}
104+
105+
console.log(`added ` + postsData.addPost.post.length + ` posts`)
106+
}
107+
108+
const result = installData()
109+
result.then((errs) => {
110+
if (errs) {
111+
console.log(`Failed !`)
112+
console.log(errs)
113+
}
114+
})

deploy/dev-setup/operations.graphql

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
mutation InitCategories($categories: [AddCategoryInput!]!) {
2+
addCategory(input: $categories) {
3+
category {
4+
id
5+
name
6+
}
7+
}
8+
}
9+
10+
mutation InitPosts($posts: [AddPostInput!]!) {
11+
addPost(input: $posts) {
12+
post {
13+
id
14+
}
15+
}
16+
}

deploy/dev-setup/run.sh

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
#!/bin/bash
2+
set -e
3+
4+
# run this from the project root dir. e.g.:
5+
#
6+
# ./deploy/dev-setup/run.sh u
7+
8+
up() {
9+
docker run --rm -p 8080:8080 -p 9080:9080 -p 8000:8000 dgraph/standalone:master > deploy/dgraph.log 2>&1 &
10+
echo "** Starting Dgraph"
11+
sleep 20s
12+
echo "** Adding Schema"
13+
curl -X POST localhost:8080/admin/schema --data-binary '@deploy/schema.graphql'
14+
echo
15+
echo "** Loading Seed Data"
16+
yarn run load-data
17+
}
18+
19+
down() {
20+
echo "not implemented :-( do 'docker ps', find the dgraph container, kill it"
21+
}
22+
23+
if [ $# -gt 0 ]; then
24+
if [ $1 == 'up' ]; then
25+
up
26+
elif [ $1 == 'down' ]; then
27+
down
28+
else
29+
echo "up (to start the dev environment, or down (to stop dev environment))"
30+
fi
31+
else
32+
echo "up (to start the dev environment, or down (to stop dev environment))"
33+
fi

deploy/dev-setup/types/operations.ts

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
import * as Types from '../../../src/types/graphql';
2+
3+
import gql from 'graphql-tag';
4+
import * as ApolloReactCommon from '@apollo/client';
5+
import * as ApolloReactHooks from '@apollo/client';
6+
7+
export type InitCategoriesMutationVariables = Types.Exact<{
8+
categories: Array<Types.AddCategoryInput>;
9+
}>;
10+
11+
12+
export type InitCategoriesMutation = (
13+
{ __typename?: 'Mutation' }
14+
& { addCategory?: Types.Maybe<(
15+
{ __typename?: 'AddCategoryPayload' }
16+
& { category?: Types.Maybe<Array<Types.Maybe<(
17+
{ __typename?: 'Category' }
18+
& Pick<Types.Category, 'id' | 'name'>
19+
)>>> }
20+
)> }
21+
);
22+
23+
export type InitPostsMutationVariables = Types.Exact<{
24+
posts: Array<Types.AddPostInput>;
25+
}>;
26+
27+
28+
export type InitPostsMutation = (
29+
{ __typename?: 'Mutation' }
30+
& { addPost?: Types.Maybe<(
31+
{ __typename?: 'AddPostPayload' }
32+
& { post?: Types.Maybe<Array<Types.Maybe<(
33+
{ __typename?: 'Post' }
34+
& Pick<Types.Post, 'id'>
35+
)>>> }
36+
)> }
37+
);
38+
39+
40+
export const InitCategoriesDocument = gql`
41+
mutation InitCategories($categories: [AddCategoryInput!]!) {
42+
addCategory(input: $categories) {
43+
category {
44+
id
45+
name
46+
}
47+
}
48+
}
49+
`;
50+
export type InitCategoriesMutationFn = ApolloReactCommon.MutationFunction<InitCategoriesMutation, InitCategoriesMutationVariables>;
51+
52+
/**
53+
* __useInitCategoriesMutation__
54+
*
55+
* To run a mutation, you first call `useInitCategoriesMutation` within a React component and pass it any options that fit your needs.
56+
* When your component renders, `useInitCategoriesMutation` returns a tuple that includes:
57+
* - A mutate function that you can call at any time to execute the mutation
58+
* - An object with fields that represent the current status of the mutation's execution
59+
*
60+
* @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2;
61+
*
62+
* @example
63+
* const [initCategoriesMutation, { data, loading, error }] = useInitCategoriesMutation({
64+
* variables: {
65+
* categories: // value for 'categories'
66+
* },
67+
* });
68+
*/
69+
export function useInitCategoriesMutation(baseOptions?: ApolloReactHooks.MutationHookOptions<InitCategoriesMutation, InitCategoriesMutationVariables>) {
70+
return ApolloReactHooks.useMutation<InitCategoriesMutation, InitCategoriesMutationVariables>(InitCategoriesDocument, baseOptions);
71+
}
72+
export type InitCategoriesMutationHookResult = ReturnType<typeof useInitCategoriesMutation>;
73+
export type InitCategoriesMutationResult = ApolloReactCommon.MutationResult<InitCategoriesMutation>;
74+
export type InitCategoriesMutationOptions = ApolloReactCommon.BaseMutationOptions<InitCategoriesMutation, InitCategoriesMutationVariables>;
75+
export const InitPostsDocument = gql`
76+
mutation InitPosts($posts: [AddPostInput!]!) {
77+
addPost(input: $posts) {
78+
post {
79+
id
80+
}
81+
}
82+
}
83+
`;
84+
export type InitPostsMutationFn = ApolloReactCommon.MutationFunction<InitPostsMutation, InitPostsMutationVariables>;
85+
86+
/**
87+
* __useInitPostsMutation__
88+
*
89+
* To run a mutation, you first call `useInitPostsMutation` within a React component and pass it any options that fit your needs.
90+
* When your component renders, `useInitPostsMutation` returns a tuple that includes:
91+
* - A mutate function that you can call at any time to execute the mutation
92+
* - An object with fields that represent the current status of the mutation's execution
93+
*
94+
* @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2;
95+
*
96+
* @example
97+
* const [initPostsMutation, { data, loading, error }] = useInitPostsMutation({
98+
* variables: {
99+
* posts: // value for 'posts'
100+
* },
101+
* });
102+
*/
103+
export function useInitPostsMutation(baseOptions?: ApolloReactHooks.MutationHookOptions<InitPostsMutation, InitPostsMutationVariables>) {
104+
return ApolloReactHooks.useMutation<InitPostsMutation, InitPostsMutationVariables>(InitPostsDocument, baseOptions);
105+
}
106+
export type InitPostsMutationHookResult = ReturnType<typeof useInitPostsMutation>;
107+
export type InitPostsMutationResult = ApolloReactCommon.MutationResult<InitPostsMutation>;
108+
export type InitPostsMutationOptions = ApolloReactCommon.BaseMutationOptions<InitPostsMutation, InitPostsMutationVariables>;

deploy/schema.graphql

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
type Post {
2+
id: ID!
3+
title: String!
4+
text: String!
5+
category: Category! @hasInverse(field: posts)
6+
}
7+
8+
type Category {
9+
id: ID!
10+
name: String!
11+
posts: [Post]
12+
}

package.json

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
"@types/node": "^12.0.0",
1212
"@types/react": "^16.9.0",
1313
"@types/react-dom": "^16.9.0",
14+
"cross-fetch": "^3.0.5",
1415
"graphql": "^15.1.0",
1516
"react": "^16.9.0",
1617
"react-dom": "^16.9.0",
@@ -25,7 +26,8 @@
2526
"build": "react-scripts build",
2627
"test": "react-scripts test",
2728
"eject": "react-scripts eject",
28-
"generate-types": "graphql-codegen --config codegen.yml"
29+
"generate-types": "graphql-codegen --config codegen.yml",
30+
"load-data": "ts-node -O '{\"module\": \"commonjs\"}' deploy/dev-setup/load-data.ts"
2931
},
3032
"eslintConfig": {
3133
"extends": "react-app"
@@ -49,6 +51,7 @@
4951
"@graphql-codegen/typescript": "^1.15.4",
5052
"@graphql-codegen/typescript-operations": "^1.15.4",
5153
"@graphql-codegen/typescript-react-apollo": "^1.15.4",
52-
"@types/react-router-dom": "^5.1.5"
54+
"@types/react-router-dom": "^5.1.5",
55+
"ts-node": "^8.10.2"
5356
}
5457
}

0 commit comments

Comments
 (0)