├── .circleci
└── config.yml
├── .gitignore
├── department-service
├── .gitignore
├── pom.xml
└── src
│ ├── main
│ ├── graphql
│ │ └── departments
│ │ │ ├── queries
│ │ │ ├── departments.graphql
│ │ │ └── departmentsByOrganization.graphql
│ │ │ └── schema.json
│ ├── java
│ │ ├── META-INF
│ │ │ └── MANIFEST.MF
│ │ ├── pl
│ │ │ └── piomin
│ │ │ │ └── services
│ │ │ │ └── department
│ │ │ │ ├── DepartmentApplication.java
│ │ │ │ ├── client
│ │ │ │ ├── EmployeeClient.java
│ │ │ │ └── EmployeesByDepartmentQuery.java
│ │ │ │ ├── model
│ │ │ │ ├── Department.java
│ │ │ │ └── Employee.java
│ │ │ │ ├── repository
│ │ │ │ └── DepartmentRepository.java
│ │ │ │ └── resolver
│ │ │ │ ├── DepartmentMutations.java
│ │ │ │ └── DepartmentQueries.java
│ │ └── type
│ │ │ └── CustomType.java
│ └── resources
│ │ ├── bootstrap.yml
│ │ └── graphql
│ │ └── department.graphqls
│ └── test
│ └── java
│ └── pl
│ └── piomin
│ └── services
│ └── department
│ └── DepartmentAppTests.java
├── discovery-service
├── .gitignore
├── pom.xml
└── src
│ └── main
│ ├── java
│ ├── META-INF
│ │ └── MANIFEST.MF
│ └── pl
│ │ └── piomin
│ │ └── services
│ │ └── discovery
│ │ └── DiscoveryApplication.java
│ └── resources
│ └── bootstrap.yml
├── employee-service
├── .gitignore
├── pom.xml
└── src
│ ├── main
│ ├── graphql
│ │ └── employees
│ │ │ ├── queries
│ │ │ └── employees.graphql
│ │ │ └── schema.json
│ ├── java
│ │ ├── META-INF
│ │ │ └── MANIFEST.MF
│ │ └── pl
│ │ │ └── piomin
│ │ │ └── services
│ │ │ └── employee
│ │ │ ├── EmployeeApplication.java
│ │ │ ├── model
│ │ │ ├── Employee.java
│ │ │ └── EmployeesQuery.java
│ │ │ ├── repository
│ │ │ └── EmployeeRepository.java
│ │ │ └── resolver
│ │ │ ├── EmployeeMutations.java
│ │ │ └── EmployeeQueries.java
│ └── resources
│ │ ├── bootstrap.yml
│ │ └── graphql
│ │ └── employee.graphqls
│ └── test
│ └── java
│ └── pl
│ └── piomin
│ └── services
│ └── employee
│ └── EmployeeApiTest.java
├── organization-service
├── .gitignore
├── pom.xml
└── src
│ └── main
│ ├── java
│ ├── META-INF
│ │ └── MANIFEST.MF
│ ├── pl
│ │ └── piomin
│ │ │ └── services
│ │ │ └── organization
│ │ │ ├── OrganizationApplication.java
│ │ │ ├── client
│ │ │ ├── DepartmentClient.java
│ │ │ ├── EmployeeClient.java
│ │ │ ├── EmployeesByDepartmentQuery.java
│ │ │ └── EmployeesByOrganizationQuery.java
│ │ │ ├── model
│ │ │ ├── Department.java
│ │ │ ├── Employee.java
│ │ │ └── Organization.java
│ │ │ ├── repository
│ │ │ └── OrganizationRepository.java
│ │ │ └── resolver
│ │ │ ├── OrganizationMutations.java
│ │ │ └── OrganizationQueries.java
│ └── type
│ │ └── CustomType.java
│ └── resources
│ ├── bootstrap.yml
│ └── graphql
│ └── organization.graphqls
├── pom.xml
├── readme.md
└── renovate.json
/.circleci/config.yml:
--------------------------------------------------------------------------------
1 | version: 2.1
2 |
3 | jobs:
4 | analyze:
5 | docker:
6 | - image: 'cimg/openjdk:8.0'
7 | steps:
8 | - checkout
9 | - run:
10 | name: Analyze on SonarCloud
11 | command: mvn verify sonar:sonar
12 |
13 | executors:
14 | jdk:
15 | docker:
16 | - image: 'cimg/openjdk:8.0'
17 |
18 | orbs:
19 | maven: circleci/maven@1.4.0
20 |
21 | workflows:
22 | maven_test:
23 | jobs:
24 | - maven/test:
25 | executor: jdk
26 | - analyze:
27 | context: SonarCloud
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /.project
2 | /.settings/
3 |
--------------------------------------------------------------------------------
/department-service/.gitignore:
--------------------------------------------------------------------------------
1 | /target/
2 | /.classpath
3 | /.project
4 | /.settings/
5 |
--------------------------------------------------------------------------------
/department-service/pom.xml:
--------------------------------------------------------------------------------
1 |
3 | 4.0.0
4 |
5 | pl.piomin.services
6 | sample-graphql-microservices
7 | 1.0-SNAPSHOT
8 |
9 | department-service
10 | 1.0-SNAPSHOT
11 |
12 |
13 | ${project.artifactId}
14 |
15 |
16 |
17 |
18 | org.springframework.cloud
19 | spring-cloud-starter-netflix-eureka-client
20 |
21 |
22 | org.springframework.cloud
23 | spring-cloud-starter-openfeign
24 |
25 |
26 | org.springframework.cloud
27 | spring-cloud-openfeign-core
28 |
29 |
30 | org.springframework.boot
31 | spring-boot-starter-web
32 |
33 |
34 | org.springframework.boot
35 | spring-boot-starter-actuator
36 |
37 |
38 | com.graphql-java
39 | graphql-spring-boot-starter
40 | 5.0.2
41 |
42 |
43 | com.graphql-java
44 | graphiql-spring-boot-starter
45 | 5.0.2
46 |
47 |
48 | com.graphql-java
49 | voyager-spring-boot-starter
50 | 5.0.2
51 |
52 |
53 | com.graphql-java
54 | graphql-java
55 | 9.2
56 |
57 |
58 | com.graphql-java
59 | graphql-java-tools
60 | 5.2.3
61 |
62 |
63 | org.springframework.cloud
64 | spring-cloud-starter-sleuth
65 |
66 |
67 | com.apollographql.apollo
68 | apollo-runtime
69 | 1.0.1
70 |
71 |
72 | com.apollographql.apollo3
73 | apollo-api-jvm
74 | 3.0.0
75 |
76 |
77 | com.apollographql.apollo3
78 | apollo-runtime-jvm
79 | 3.0.0
80 |
81 |
82 | org.springframework.boot
83 | spring-boot-starter-test
84 | test
85 |
86 |
87 |
88 |
89 |
90 |
91 | org.springframework.boot
92 | spring-boot-maven-plugin
93 |
94 |
95 | com.github.aoudiamoncef
96 | apollo-client-maven-plugin
97 | 5.0.0
98 |
99 |
100 |
101 | generate
102 |
103 |
104 |
105 |
106 |
107 | departments
108 |
109 | pl.piomin.services.department.client
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 | org.codehaus.mojo
120 | build-helper-maven-plugin
121 |
122 |
123 | add-source
124 | generate-sources
125 |
126 | add-source
127 |
128 |
129 |
130 | target/generated-sources/apollo/departments
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
--------------------------------------------------------------------------------
/department-service/src/main/graphql/departments/queries/departments.graphql:
--------------------------------------------------------------------------------
1 | query departments {
2 | departments {
3 | id
4 | name
5 | organizationId
6 | }
7 | }
--------------------------------------------------------------------------------
/department-service/src/main/graphql/departments/queries/departmentsByOrganization.graphql:
--------------------------------------------------------------------------------
1 | query departmentsByOrganization {
2 | departmentsByOrganization(organizationId: 1) {
3 | id
4 | name
5 | }
6 | }
--------------------------------------------------------------------------------
/department-service/src/main/graphql/departments/schema.json:
--------------------------------------------------------------------------------
1 | {"data":{"__schema":{"queryType":{"name":"DepartmentQueries"},"mutationType":{"name":"DepartmentMutations"},"subscriptionType":null,"types":[{"kind":"OBJECT","name":"DepartmentQueries","description":"","fields":[{"name":"departments","description":"","args":[],"type":{"kind":"LIST","name":null,"ofType":{"kind":"OBJECT","name":"Department","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"department","description":"","args":[{"name":"id","description":"","type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"ID","ofType":null}},"defaultValue":null}],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"OBJECT","name":"Department","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"departmentsByOrganization","description":"","args":[{"name":"organizationId","description":"","type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"Int","ofType":null}},"defaultValue":null}],"type":{"kind":"LIST","name":null,"ofType":{"kind":"OBJECT","name":"Department","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"departmentsByOrganizationWithEmployees","description":"","args":[{"name":"organizationId","description":"","type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"Int","ofType":null}},"defaultValue":null}],"type":{"kind":"LIST","name":null,"ofType":{"kind":"OBJECT","name":"Department","ofType":null}},"isDeprecated":false,"deprecationReason":null}],"inputFields":null,"interfaces":[],"enumValues":null,"possibleTypes":null},{"kind":"SCALAR","name":"ID","description":"Built-in ID","fields":null,"inputFields":null,"interfaces":null,"enumValues":null,"possibleTypes":null},{"kind":"SCALAR","name":"Int","description":"Built-in Int","fields":null,"inputFields":null,"interfaces":null,"enumValues":null,"possibleTypes":null},{"kind":"OBJECT","name":"DepartmentMutations","description":"","fields":[{"name":"newDepartment","description":"","args":[{"name":"department","description":"","type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"INPUT_OBJECT","name":"DepartmentInput","ofType":null}},"defaultValue":null}],"type":{"kind":"OBJECT","name":"Department","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"deleteDepartment","description":"","args":[{"name":"id","description":"","type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"ID","ofType":null}},"defaultValue":null}],"type":{"kind":"SCALAR","name":"Boolean","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"updateDepartment","description":"","args":[{"name":"id","description":"","type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"ID","ofType":null}},"defaultValue":null},{"name":"department","description":"","type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"INPUT_OBJECT","name":"DepartmentInput","ofType":null}},"defaultValue":null}],"type":{"kind":"OBJECT","name":"Department","ofType":null},"isDeprecated":false,"deprecationReason":null}],"inputFields":null,"interfaces":[],"enumValues":null,"possibleTypes":null},{"kind":"SCALAR","name":"Boolean","description":"Built-in Boolean","fields":null,"inputFields":null,"interfaces":null,"enumValues":null,"possibleTypes":null},{"kind":"OBJECT","name":"Department","description":"","fields":[{"name":"id","description":"","args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"ID","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"organizationId","description":"","args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"Int","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"name","description":"","args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"String","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"employees","description":"","args":[],"type":{"kind":"LIST","name":null,"ofType":{"kind":"OBJECT","name":"Employee","ofType":null}},"isDeprecated":false,"deprecationReason":null}],"inputFields":null,"interfaces":[],"enumValues":null,"possibleTypes":null},{"kind":"SCALAR","name":"String","description":"Built-in String","fields":null,"inputFields":null,"interfaces":null,"enumValues":null,"possibleTypes":null},{"kind":"OBJECT","name":"Employee","description":"","fields":[{"name":"id","description":"","args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"ID","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"name","description":"","args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"String","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"position","description":"","args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"String","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"salary","description":"","args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"Int","ofType":null}},"isDeprecated":false,"deprecationReason":null}],"inputFields":null,"interfaces":[],"enumValues":null,"possibleTypes":null},{"kind":"INPUT_OBJECT","name":"DepartmentInput","description":"","fields":null,"inputFields":[{"name":"organizationId","description":"","type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"Int","ofType":null}},"defaultValue":null},{"name":"name","description":"","type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"String","ofType":null}},"defaultValue":null}],"interfaces":null,"enumValues":null,"possibleTypes":null},{"kind":"OBJECT","name":"__Schema","description":"A GraphQL Introspection defines the capabilities of a GraphQL server. It exposes all available types and directives on the server, the entry points for query, mutation, and subscription operations.","fields":[{"name":"types","description":"A list of all types supported by this server.","args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"LIST","name":null,"ofType":{"kind":"NON_NULL","name":null,"ofType":{"kind":"OBJECT","name":"__Type"}}}},"isDeprecated":false,"deprecationReason":null},{"name":"queryType","description":"The type that query operations will be rooted at.","args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"OBJECT","name":"__Type","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"mutationType","description":"If this server supports mutation, the type that mutation operations will be rooted at.","args":[],"type":{"kind":"OBJECT","name":"__Type","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"directives","description":"'A list of all directives supported by this server.","args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"LIST","name":null,"ofType":{"kind":"NON_NULL","name":null,"ofType":{"kind":"OBJECT","name":"__Directive"}}}},"isDeprecated":false,"deprecationReason":null},{"name":"subscriptionType","description":"'If this server support subscription, the type that subscription operations will be rooted at.","args":[],"type":{"kind":"OBJECT","name":"__Type","ofType":null},"isDeprecated":false,"deprecationReason":null}],"inputFields":null,"interfaces":[],"enumValues":null,"possibleTypes":null},{"kind":"OBJECT","name":"__Type","description":null,"fields":[{"name":"kind","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"ENUM","name":"__TypeKind","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"name","description":null,"args":[],"type":{"kind":"SCALAR","name":"String","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"description","description":null,"args":[],"type":{"kind":"SCALAR","name":"String","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"fields","description":null,"args":[{"name":"includeDeprecated","description":null,"type":{"kind":"SCALAR","name":"Boolean","ofType":null},"defaultValue":"false"}],"type":{"kind":"LIST","name":null,"ofType":{"kind":"NON_NULL","name":null,"ofType":{"kind":"OBJECT","name":"__Field","ofType":null}}},"isDeprecated":false,"deprecationReason":null},{"name":"interfaces","description":null,"args":[],"type":{"kind":"LIST","name":null,"ofType":{"kind":"NON_NULL","name":null,"ofType":{"kind":"OBJECT","name":"__Type","ofType":null}}},"isDeprecated":false,"deprecationReason":null},{"name":"possibleTypes","description":null,"args":[],"type":{"kind":"LIST","name":null,"ofType":{"kind":"NON_NULL","name":null,"ofType":{"kind":"OBJECT","name":"__Type","ofType":null}}},"isDeprecated":false,"deprecationReason":null},{"name":"enumValues","description":null,"args":[{"name":"includeDeprecated","description":null,"type":{"kind":"SCALAR","name":"Boolean","ofType":null},"defaultValue":"false"}],"type":{"kind":"LIST","name":null,"ofType":{"kind":"NON_NULL","name":null,"ofType":{"kind":"OBJECT","name":"__EnumValue","ofType":null}}},"isDeprecated":false,"deprecationReason":null},{"name":"inputFields","description":null,"args":[],"type":{"kind":"LIST","name":null,"ofType":{"kind":"NON_NULL","name":null,"ofType":{"kind":"OBJECT","name":"__InputValue","ofType":null}}},"isDeprecated":false,"deprecationReason":null},{"name":"ofType","description":null,"args":[],"type":{"kind":"OBJECT","name":"__Type","ofType":null},"isDeprecated":false,"deprecationReason":null}],"inputFields":null,"interfaces":[],"enumValues":null,"possibleTypes":null},{"kind":"ENUM","name":"__TypeKind","description":"An enum describing what kind of type a given __Type is","fields":null,"inputFields":null,"interfaces":null,"enumValues":[{"name":"SCALAR","description":"Indicates this type is a scalar.","isDeprecated":false,"deprecationReason":null},{"name":"OBJECT","description":"Indicates this type is an object. `fields` and `interfaces` are valid fields.","isDeprecated":false,"deprecationReason":null},{"name":"INTERFACE","description":"Indicates this type is an interface. `fields` and `possibleTypes` are valid fields.","isDeprecated":false,"deprecationReason":null},{"name":"UNION","description":"Indicates this type is a union. `possibleTypes` is a valid field.","isDeprecated":false,"deprecationReason":null},{"name":"ENUM","description":"Indicates this type is an enum. `enumValues` is a valid field.","isDeprecated":false,"deprecationReason":null},{"name":"INPUT_OBJECT","description":"Indicates this type is an input object. `inputFields` is a valid field.","isDeprecated":false,"deprecationReason":null},{"name":"LIST","description":"Indicates this type is a list. `ofType` is a valid field.","isDeprecated":false,"deprecationReason":null},{"name":"NON_NULL","description":"Indicates this type is a non-null. `ofType` is a valid field.","isDeprecated":false,"deprecationReason":null}],"possibleTypes":null},{"kind":"OBJECT","name":"__Field","description":null,"fields":[{"name":"name","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"String","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"description","description":null,"args":[],"type":{"kind":"SCALAR","name":"String","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"args","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"LIST","name":null,"ofType":{"kind":"NON_NULL","name":null,"ofType":{"kind":"OBJECT","name":"__InputValue"}}}},"isDeprecated":false,"deprecationReason":null},{"name":"type","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"OBJECT","name":"__Type","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"isDeprecated","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"Boolean","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"deprecationReason","description":null,"args":[],"type":{"kind":"SCALAR","name":"String","ofType":null},"isDeprecated":false,"deprecationReason":null}],"inputFields":null,"interfaces":[],"enumValues":null,"possibleTypes":null},{"kind":"OBJECT","name":"__InputValue","description":null,"fields":[{"name":"name","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"String","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"description","description":null,"args":[],"type":{"kind":"SCALAR","name":"String","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"type","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"OBJECT","name":"__Type","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"defaultValue","description":null,"args":[],"type":{"kind":"SCALAR","name":"String","ofType":null},"isDeprecated":false,"deprecationReason":null}],"inputFields":null,"interfaces":[],"enumValues":null,"possibleTypes":null},{"kind":"OBJECT","name":"__EnumValue","description":null,"fields":[{"name":"name","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"String","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"description","description":null,"args":[],"type":{"kind":"SCALAR","name":"String","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"isDeprecated","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"Boolean","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"deprecationReason","description":null,"args":[],"type":{"kind":"SCALAR","name":"String","ofType":null},"isDeprecated":false,"deprecationReason":null}],"inputFields":null,"interfaces":[],"enumValues":null,"possibleTypes":null},{"kind":"OBJECT","name":"__Directive","description":null,"fields":[{"name":"name","description":null,"args":[],"type":{"kind":"SCALAR","name":"String","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"description","description":null,"args":[],"type":{"kind":"SCALAR","name":"String","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"locations","description":null,"args":[],"type":{"kind":"LIST","name":null,"ofType":{"kind":"NON_NULL","name":null,"ofType":{"kind":"ENUM","name":"__DirectiveLocation","ofType":null}}},"isDeprecated":false,"deprecationReason":null},{"name":"args","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"LIST","name":null,"ofType":{"kind":"NON_NULL","name":null,"ofType":{"kind":"OBJECT","name":"__InputValue"}}}},"isDeprecated":false,"deprecationReason":null},{"name":"onOperation","description":null,"args":[],"type":{"kind":"SCALAR","name":"Boolean","ofType":null},"isDeprecated":true,"deprecationReason":"Use `locations`."},{"name":"onFragment","description":null,"args":[],"type":{"kind":"SCALAR","name":"Boolean","ofType":null},"isDeprecated":true,"deprecationReason":"Use `locations`."},{"name":"onField","description":null,"args":[],"type":{"kind":"SCALAR","name":"Boolean","ofType":null},"isDeprecated":true,"deprecationReason":"Use `locations`."}],"inputFields":null,"interfaces":[],"enumValues":null,"possibleTypes":null},{"kind":"ENUM","name":"__DirectiveLocation","description":"An enum describing valid locations where a directive can be placed","fields":null,"inputFields":null,"interfaces":null,"enumValues":[{"name":"QUERY","description":"Indicates the directive is valid on queries.","isDeprecated":false,"deprecationReason":null},{"name":"MUTATION","description":"Indicates the directive is valid on mutations.","isDeprecated":false,"deprecationReason":null},{"name":"FIELD","description":"Indicates the directive is valid on fields.","isDeprecated":false,"deprecationReason":null},{"name":"FRAGMENT_DEFINITION","description":"Indicates the directive is valid on fragment definitions.","isDeprecated":false,"deprecationReason":null},{"name":"FRAGMENT_SPREAD","description":"Indicates the directive is valid on fragment spreads.","isDeprecated":false,"deprecationReason":null},{"name":"INLINE_FRAGMENT","description":"Indicates the directive is valid on inline fragments.","isDeprecated":false,"deprecationReason":null},{"name":"SCHEMA","description":"Indicates the directive is valid on a schema SDL definition.","isDeprecated":false,"deprecationReason":null},{"name":"SCALAR","description":"Indicates the directive is valid on a scalar SDL definition.","isDeprecated":false,"deprecationReason":null},{"name":"OBJECT","description":"Indicates the directive is valid on an object SDL definition.","isDeprecated":false,"deprecationReason":null},{"name":"FIELD_DEFINITION","description":"Indicates the directive is valid on a field SDL definition.","isDeprecated":false,"deprecationReason":null},{"name":"ARGUMENT_DEFINITION","description":"Indicates the directive is valid on a field argument SDL definition.","isDeprecated":false,"deprecationReason":null},{"name":"INTERFACE","description":"Indicates the directive is valid on an interface SDL definition.","isDeprecated":false,"deprecationReason":null},{"name":"UNION","description":"Indicates the directive is valid on an union SDL definition.","isDeprecated":false,"deprecationReason":null},{"name":"ENUM","description":"Indicates the directive is valid on an enum SDL definition.","isDeprecated":false,"deprecationReason":null},{"name":"ENUM_VALUE","description":"Indicates the directive is valid on an enum value SDL definition.","isDeprecated":false,"deprecationReason":null},{"name":"INPUT_OBJECT","description":"Indicates the directive is valid on an input object SDL definition.","isDeprecated":false,"deprecationReason":null},{"name":"INPUT_FIELD_DEFINITION","description":"Indicates the directive is valid on an input object field SDL definition.","isDeprecated":false,"deprecationReason":null}],"possibleTypes":null}],"directives":[{"name":"include","description":"Directs the executor to include this field or fragment only when the `if` argument is true","locations":["FIELD","FRAGMENT_SPREAD","INLINE_FRAGMENT"],"args":[{"name":"if","description":"Included when true.","type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"Boolean","ofType":null}},"defaultValue":null}]},{"name":"skip","description":"Directs the executor to skip this field or fragment when the `if`'argument is true.","locations":["FIELD","FRAGMENT_SPREAD","INLINE_FRAGMENT"],"args":[{"name":"if","description":"Skipped when true.","type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"Boolean","ofType":null}},"defaultValue":null}]},{"name":"defer","description":"This directive allows results to be deferred during execution","locations":["FIELD"],"args":[]}]}}}
--------------------------------------------------------------------------------
/department-service/src/main/java/META-INF/MANIFEST.MF:
--------------------------------------------------------------------------------
1 | Manifest-Version: 1.0
2 | Class-Path:
3 |
4 |
--------------------------------------------------------------------------------
/department-service/src/main/java/pl/piomin/services/department/DepartmentApplication.java:
--------------------------------------------------------------------------------
1 | package pl.piomin.services.department;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 | import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
6 | import org.springframework.cloud.openfeign.EnableFeignClients;
7 | import org.springframework.context.annotation.Bean;
8 |
9 | import pl.piomin.services.department.model.Department;
10 | import pl.piomin.services.department.repository.DepartmentRepository;
11 |
12 | @SpringBootApplication
13 | @EnableDiscoveryClient
14 | @EnableFeignClients
15 | public class DepartmentApplication {
16 |
17 | public static void main(String[] args) {
18 | SpringApplication.run(DepartmentApplication.class, args);
19 | }
20 |
21 | @Bean
22 | DepartmentRepository repository() {
23 | DepartmentRepository repository = new DepartmentRepository();
24 | repository.add(new Department(1L, "Development"));
25 | repository.add(new Department(1L, "Operations"));
26 | repository.add(new Department(2L, "Development"));
27 | repository.add(new Department(2L, "Operations"));
28 | return repository;
29 | }
30 |
31 | }
32 |
--------------------------------------------------------------------------------
/department-service/src/main/java/pl/piomin/services/department/client/EmployeeClient.java:
--------------------------------------------------------------------------------
1 | package pl.piomin.services.department.client;
2 |
3 | import java.util.ArrayList;
4 | import java.util.List;
5 | import java.util.Random;
6 | import java.util.concurrent.CountDownLatch;
7 | import java.util.concurrent.TimeUnit;
8 | import java.util.stream.Collectors;
9 |
10 | import org.slf4j.Logger;
11 | import org.slf4j.LoggerFactory;
12 | import org.springframework.beans.factory.annotation.Autowired;
13 | import org.springframework.stereotype.Component;
14 |
15 | import com.apollographql.apollo.ApolloCall.Callback;
16 | import com.apollographql.apollo.ApolloClient;
17 | import com.apollographql.apollo.api.Response;
18 | import com.apollographql.apollo.exception.ApolloException;
19 | import com.netflix.appinfo.InstanceInfo;
20 | import com.netflix.discovery.EurekaClient;
21 | import com.netflix.discovery.shared.Application;
22 |
23 | import pl.piomin.services.department.model.Employee;
24 |
25 | @Component
26 | public class EmployeeClient {
27 |
28 | private static final Logger LOGGER = LoggerFactory.getLogger(EmployeeClient.class);
29 | private static final int TIMEOUT = 5000;
30 | private static final String SERVICE_NAME = "EMPLOYEE-SERVICE";
31 | private static final String SERVER_URL = "http://localhost:%d/graphql";
32 |
33 | Random r = new Random();
34 |
35 | @Autowired
36 | private EurekaClient discoveryClient;
37 |
38 | public List findByDepartment(Long departmentId) throws InterruptedException {
39 | List employees = new ArrayList<>();
40 | Application app = discoveryClient.getApplication(SERVICE_NAME);
41 | InstanceInfo ii = app.getInstances().get(r.nextInt(app.size()));
42 | ApolloClient client = ApolloClient.builder().serverUrl(String.format(SERVER_URL, ii.getPort())).build();
43 | CountDownLatch lock = new CountDownLatch(1);
44 | client.query(EmployeesByDepartmentQuery.builder().departmentId(departmentId.intValue()).build()).enqueue(new Callback() {
45 |
46 | @Override
47 | public void onFailure(ApolloException ex) {
48 | LOGGER.info("Err: {}", ex);
49 | lock.countDown();
50 | }
51 |
52 | @Override
53 | public void onResponse(Response res) {
54 | LOGGER.info("Res: {}", res);
55 | employees.addAll(res.data().employeesByDepartment().stream().map(emp -> new Employee(Long.valueOf(emp.id()), emp.name(), emp.position(), emp.salary())).collect(Collectors.toList()));
56 | lock.countDown();
57 | }
58 |
59 | });
60 | lock.await(TIMEOUT, TimeUnit.MILLISECONDS);
61 | return employees;
62 | }
63 |
64 | }
65 |
--------------------------------------------------------------------------------
/department-service/src/main/java/pl/piomin/services/department/client/EmployeesByDepartmentQuery.java:
--------------------------------------------------------------------------------
1 | package pl.piomin.services.department.client;
2 |
3 | import com.apollographql.apollo.api.InputFieldMarshaller;
4 | import com.apollographql.apollo.api.InputFieldWriter;
5 | import com.apollographql.apollo.api.Operation;
6 | import com.apollographql.apollo.api.OperationName;
7 | import com.apollographql.apollo.api.Query;
8 | import com.apollographql.apollo.api.ResponseField;
9 | import com.apollographql.apollo.api.ResponseFieldMapper;
10 | import com.apollographql.apollo.api.ResponseFieldMarshaller;
11 | import com.apollographql.apollo.api.ResponseReader;
12 | import com.apollographql.apollo.api.ResponseWriter;
13 | import com.apollographql.apollo.api.internal.UnmodifiableMapBuilder;
14 | import com.apollographql.apollo.api.internal.Utils;
15 | import java.io.IOException;
16 | import java.lang.Object;
17 | import java.lang.Override;
18 | import java.lang.String;
19 | import java.util.Collections;
20 | import java.util.LinkedHashMap;
21 | import java.util.List;
22 | import java.util.Map;
23 | import javax.annotation.Generated;
24 | import org.jetbrains.annotations.NotNull;
25 | import org.jetbrains.annotations.Nullable;
26 | import type.CustomType;
27 |
28 | @Generated("Apollo GraphQL")
29 | public final class EmployeesByDepartmentQuery implements Query {
30 | public static final String OPERATION_DEFINITION = "query EmployeesByDepartment($departmentId: Int!) {\n"
31 | + " employeesByDepartment(departmentId: $departmentId) {\n"
32 | + " __typename\n"
33 | + " id\n"
34 | + " name\n"
35 | + " position\n"
36 | + " salary\n"
37 | + " }\n"
38 | + "}";
39 |
40 | public static final String OPERATION_ID = "14971a7245ab04844941749beef351913563d71c03d8a05a48ca6375230e90aa";
41 |
42 | public static final String QUERY_DOCUMENT = OPERATION_DEFINITION;
43 |
44 | public static final OperationName OPERATION_NAME = new OperationName() {
45 | @Override
46 | public String name() {
47 | return "EmployeesByDepartment";
48 | }
49 | };
50 |
51 | private final EmployeesByDepartmentQuery.Variables variables;
52 |
53 | public EmployeesByDepartmentQuery(int departmentId) {
54 | variables = new EmployeesByDepartmentQuery.Variables(departmentId);
55 | }
56 |
57 | @Override
58 | public String operationId() {
59 | return OPERATION_ID;
60 | }
61 |
62 | @Override
63 | public String queryDocument() {
64 | return QUERY_DOCUMENT;
65 | }
66 |
67 | @Override
68 | public EmployeesByDepartmentQuery.Data wrapData(EmployeesByDepartmentQuery.Data data) {
69 | return data;
70 | }
71 |
72 | @Override
73 | public EmployeesByDepartmentQuery.Variables variables() {
74 | return variables;
75 | }
76 |
77 | @Override
78 | public ResponseFieldMapper responseFieldMapper() {
79 | return new Data.Mapper();
80 | }
81 |
82 | public static Builder builder() {
83 | return new Builder();
84 | }
85 |
86 | @Override
87 | public OperationName name() {
88 | return OPERATION_NAME;
89 | }
90 |
91 | public static final class Builder {
92 | private int departmentId;
93 |
94 | Builder() {
95 | }
96 |
97 | public Builder departmentId(int departmentId) {
98 | this.departmentId = departmentId;
99 | return this;
100 | }
101 |
102 | public EmployeesByDepartmentQuery build() {
103 | return new EmployeesByDepartmentQuery(departmentId);
104 | }
105 | }
106 |
107 | public static final class Variables extends Operation.Variables {
108 | private final int departmentId;
109 |
110 | private final transient Map valueMap = new LinkedHashMap<>();
111 |
112 | Variables(int departmentId) {
113 | this.departmentId = departmentId;
114 | this.valueMap.put("departmentId", departmentId);
115 | }
116 |
117 | public int departmentId() {
118 | return departmentId;
119 | }
120 |
121 | @Override
122 | public Map valueMap() {
123 | return Collections.unmodifiableMap(valueMap);
124 | }
125 |
126 | @Override
127 | public InputFieldMarshaller marshaller() {
128 | return new InputFieldMarshaller() {
129 | @Override
130 | public void marshal(InputFieldWriter writer) throws IOException {
131 | writer.writeInt("departmentId", departmentId);
132 | }
133 | };
134 | }
135 | }
136 |
137 | public static class Data implements Operation.Data {
138 | static final ResponseField[] $responseFields = {
139 | ResponseField.forList("employeesByDepartment", "employeesByDepartment", new UnmodifiableMapBuilder(1)
140 | .put("departmentId", new UnmodifiableMapBuilder(2)
141 | .put("kind", "Variable")
142 | .put("variableName", "departmentId")
143 | .build())
144 | .build(), true, Collections.emptyList())
145 | };
146 |
147 | final @Nullable List employeesByDepartment;
148 |
149 | private volatile String $toString;
150 |
151 | private volatile int $hashCode;
152 |
153 | private volatile boolean $hashCodeMemoized;
154 |
155 | public Data(@Nullable List employeesByDepartment) {
156 | this.employeesByDepartment = employeesByDepartment;
157 | }
158 |
159 | public @Nullable List employeesByDepartment() {
160 | return this.employeesByDepartment;
161 | }
162 |
163 | public ResponseFieldMarshaller marshaller() {
164 | return new ResponseFieldMarshaller() {
165 | @Override
166 | public void marshal(ResponseWriter writer) {
167 | writer.writeList($responseFields[0], employeesByDepartment, new ResponseWriter.ListWriter() {
168 | @Override
169 | public void write(@Nullable List list, @NotNull ResponseWriter.ListItemWriter listItemWriter) {
170 | listItemWriter.writeList(list, this);
171 | }
172 |
173 | // @Override
174 | // public void write(Object value, ResponseWriter.ListItemWriter listItemWriter) {
175 | // listItemWriter.writeObject(((EmployeesByDepartment) value).marshaller());
176 | // }
177 | });
178 | }
179 | };
180 | }
181 |
182 | @Override
183 | public String toString() {
184 | if ($toString == null) {
185 | $toString = "Data{"
186 | + "employeesByDepartment=" + employeesByDepartment
187 | + "}";
188 | }
189 | return $toString;
190 | }
191 |
192 | @Override
193 | public boolean equals(Object o) {
194 | if (o == this) {
195 | return true;
196 | }
197 | if (o instanceof Data) {
198 | Data that = (Data) o;
199 | return ((this.employeesByDepartment == null) ? (that.employeesByDepartment == null) : this.employeesByDepartment.equals(that.employeesByDepartment));
200 | }
201 | return false;
202 | }
203 |
204 | @Override
205 | public int hashCode() {
206 | if (!$hashCodeMemoized) {
207 | int h = 1;
208 | h *= 1000003;
209 | h ^= (employeesByDepartment == null) ? 0 : employeesByDepartment.hashCode();
210 | $hashCode = h;
211 | $hashCodeMemoized = true;
212 | }
213 | return $hashCode;
214 | }
215 |
216 | public static final class Mapper implements ResponseFieldMapper {
217 | final EmployeesByDepartment.Mapper employeesByDepartmentFieldMapper = new EmployeesByDepartment.Mapper();
218 |
219 | @Override
220 | public Data map(ResponseReader reader) {
221 | final List employeesByDepartment = reader.readList($responseFields[0], new ResponseReader.ListReader() {
222 | @Override
223 | public EmployeesByDepartment read(ResponseReader.ListItemReader listItemReader) {
224 | return listItemReader.readObject(new ResponseReader.ObjectReader() {
225 | @Override
226 | public EmployeesByDepartment read(ResponseReader reader) {
227 | return employeesByDepartmentFieldMapper.map(reader);
228 | }
229 | });
230 | }
231 | });
232 | return new Data(employeesByDepartment);
233 | }
234 | }
235 | }
236 |
237 | public static class EmployeesByDepartment {
238 | static final ResponseField[] $responseFields = {
239 | ResponseField.forString("__typename", "__typename", null, false, Collections.emptyList()),
240 | ResponseField.forCustomType("id", "id", null, false, CustomType.ID, Collections.emptyList()),
241 | ResponseField.forString("name", "name", null, false, Collections.emptyList()),
242 | ResponseField.forString("position", "position", null, false, Collections.emptyList()),
243 | ResponseField.forInt("salary", "salary", null, false, Collections.emptyList())
244 | };
245 |
246 | final @NotNull String __typename;
247 |
248 | final @NotNull String id;
249 |
250 | final @NotNull String name;
251 |
252 | final @NotNull String position;
253 |
254 | final int salary;
255 |
256 | private volatile String $toString;
257 |
258 | private volatile int $hashCode;
259 |
260 | private volatile boolean $hashCodeMemoized;
261 |
262 | public EmployeesByDepartment(@NotNull String __typename, @NotNull String id,
263 | @NotNull String name, @NotNull String position, int salary) {
264 | this.__typename = Utils.checkNotNull(__typename, "__typename == null");
265 | this.id = Utils.checkNotNull(id, "id == null");
266 | this.name = Utils.checkNotNull(name, "name == null");
267 | this.position = Utils.checkNotNull(position, "position == null");
268 | this.salary = salary;
269 | }
270 |
271 | public @NotNull String __typename() {
272 | return this.__typename;
273 | }
274 |
275 | public @NotNull String id() {
276 | return this.id;
277 | }
278 |
279 | public @NotNull String name() {
280 | return this.name;
281 | }
282 |
283 | public @NotNull String position() {
284 | return this.position;
285 | }
286 |
287 | public int salary() {
288 | return this.salary;
289 | }
290 |
291 | public ResponseFieldMarshaller marshaller() {
292 | return new ResponseFieldMarshaller() {
293 | @Override
294 | public void marshal(ResponseWriter writer) {
295 | writer.writeString($responseFields[0], __typename);
296 | writer.writeCustom((ResponseField.CustomTypeField) $responseFields[1], id);
297 | writer.writeString($responseFields[2], name);
298 | writer.writeString($responseFields[3], position);
299 | writer.writeInt($responseFields[4], salary);
300 | }
301 | };
302 | }
303 |
304 | @Override
305 | public String toString() {
306 | if ($toString == null) {
307 | $toString = "EmployeesByDepartment{"
308 | + "__typename=" + __typename + ", "
309 | + "id=" + id + ", "
310 | + "name=" + name + ", "
311 | + "position=" + position + ", "
312 | + "salary=" + salary
313 | + "}";
314 | }
315 | return $toString;
316 | }
317 |
318 | @Override
319 | public boolean equals(Object o) {
320 | if (o == this) {
321 | return true;
322 | }
323 | if (o instanceof EmployeesByDepartment) {
324 | EmployeesByDepartment that = (EmployeesByDepartment) o;
325 | return this.__typename.equals(that.__typename)
326 | && this.id.equals(that.id)
327 | && this.name.equals(that.name)
328 | && this.position.equals(that.position)
329 | && this.salary == that.salary;
330 | }
331 | return false;
332 | }
333 |
334 | @Override
335 | public int hashCode() {
336 | if (!$hashCodeMemoized) {
337 | int h = 1;
338 | h *= 1000003;
339 | h ^= __typename.hashCode();
340 | h *= 1000003;
341 | h ^= id.hashCode();
342 | h *= 1000003;
343 | h ^= name.hashCode();
344 | h *= 1000003;
345 | h ^= position.hashCode();
346 | h *= 1000003;
347 | h ^= salary;
348 | $hashCode = h;
349 | $hashCodeMemoized = true;
350 | }
351 | return $hashCode;
352 | }
353 |
354 | public static final class Mapper implements ResponseFieldMapper {
355 | @Override
356 | public EmployeesByDepartment map(ResponseReader reader) {
357 | final String __typename = reader.readString($responseFields[0]);
358 | final String id = reader.readCustomType((ResponseField.CustomTypeField) $responseFields[1]);
359 | final String name = reader.readString($responseFields[2]);
360 | final String position = reader.readString($responseFields[3]);
361 | final int salary = reader.readInt($responseFields[4]);
362 | return new EmployeesByDepartment(__typename, id, name, position, salary);
363 | }
364 | }
365 | }
366 | }
367 |
--------------------------------------------------------------------------------
/department-service/src/main/java/pl/piomin/services/department/model/Department.java:
--------------------------------------------------------------------------------
1 | package pl.piomin.services.department.model;
2 |
3 | import java.util.ArrayList;
4 | import java.util.List;
5 |
6 | public class Department {
7 |
8 | private Long id;
9 | private Long organizationId;
10 | private String name;
11 | private List employees = new ArrayList<>();
12 |
13 | public Department() {
14 |
15 | }
16 |
17 | public Department(Long organizationId, String name) {
18 | super();
19 | this.organizationId = organizationId;
20 | this.name = name;
21 | }
22 |
23 | public Long getId() {
24 | return id;
25 | }
26 |
27 | public void setId(Long id) {
28 | this.id = id;
29 | }
30 |
31 | public Long getOrganizationId() {
32 | return organizationId;
33 | }
34 |
35 | public void setOrganizationId(Long organizationId) {
36 | this.organizationId = organizationId;
37 | }
38 |
39 | public String getName() {
40 | return name;
41 | }
42 |
43 | public void setName(String name) {
44 | this.name = name;
45 | }
46 |
47 | public List getEmployees() {
48 | return employees;
49 | }
50 |
51 | public void setEmployees(List employees) {
52 | this.employees = employees;
53 | }
54 |
55 | @Override
56 | public String toString() {
57 | return "Department [id=" + id + ", organizationId=" + organizationId + ", name=" + name + "]";
58 | }
59 |
60 | }
61 |
--------------------------------------------------------------------------------
/department-service/src/main/java/pl/piomin/services/department/model/Employee.java:
--------------------------------------------------------------------------------
1 | package pl.piomin.services.department.model;
2 |
3 | public class Employee {
4 |
5 | private Long id;
6 | private String name;
7 | private String position;
8 | private int salary;
9 |
10 | public Employee() {
11 |
12 | }
13 |
14 | public Employee(Long id, String name, String position, int salary) {
15 | super();
16 | this.id = id;
17 | this.name = name;
18 | this.position = position;
19 | this.salary = salary;
20 | }
21 |
22 | public Long getId() {
23 | return id;
24 | }
25 |
26 | public void setId(Long id) {
27 | this.id = id;
28 | }
29 |
30 | public String getName() {
31 | return name;
32 | }
33 |
34 | public void setName(String name) {
35 | this.name = name;
36 | }
37 |
38 |
39 | public String getPosition() {
40 | return position;
41 | }
42 |
43 | public void setPosition(String position) {
44 | this.position = position;
45 | }
46 |
47 | public int getSalary() {
48 | return salary;
49 | }
50 |
51 | public void setSalary(int salary) {
52 | this.salary = salary;
53 | }
54 |
55 | @Override
56 | public String toString() {
57 | return "Employee [id=" + id + ", name=" + name + ", position=" + position + "]";
58 | }
59 |
60 | }
61 |
--------------------------------------------------------------------------------
/department-service/src/main/java/pl/piomin/services/department/repository/DepartmentRepository.java:
--------------------------------------------------------------------------------
1 | package pl.piomin.services.department.repository;
2 |
3 | import java.util.ArrayList;
4 | import java.util.List;
5 | import java.util.Optional;
6 | import java.util.stream.Collectors;
7 |
8 | import pl.piomin.services.department.model.Department;
9 |
10 | public class DepartmentRepository {
11 |
12 | private List departments = new ArrayList<>();
13 |
14 | public Department add(Department department) {
15 | department.setId((long) (departments.size()+1));
16 | departments.add(department);
17 | return department;
18 | }
19 |
20 | public Department findById(Long id) {
21 | Optional department = departments.stream().filter(a -> a.getId().equals(id)).findFirst();
22 | if (department.isPresent())
23 | return department.get();
24 | else
25 | return null;
26 | }
27 |
28 | public List findAll() {
29 | return departments;
30 | }
31 |
32 | public List findByOrganization(Long organizationId) {
33 | return departments.stream().filter(a -> a.getOrganizationId().equals(organizationId)).collect(Collectors.toList());
34 | }
35 |
36 | public boolean delete(Long id) {
37 | return departments.removeIf(it -> it.getId() == id.longValue());
38 | }
39 |
40 | public Department update(Long id, Department department) {
41 | department.setId(id);
42 | int index = departments.indexOf(department);
43 | departments.set(index, department);
44 | return department;
45 | }
46 |
47 | }
48 |
--------------------------------------------------------------------------------
/department-service/src/main/java/pl/piomin/services/department/resolver/DepartmentMutations.java:
--------------------------------------------------------------------------------
1 | package pl.piomin.services.department.resolver;
2 |
3 | import org.slf4j.Logger;
4 | import org.slf4j.LoggerFactory;
5 | import org.springframework.beans.factory.annotation.Autowired;
6 | import org.springframework.stereotype.Component;
7 |
8 | import com.coxautodev.graphql.tools.GraphQLMutationResolver;
9 |
10 | import pl.piomin.services.department.model.Department;
11 | import pl.piomin.services.department.repository.DepartmentRepository;
12 |
13 | @Component
14 | public class DepartmentMutations implements GraphQLMutationResolver {
15 |
16 | private static final Logger LOGGER = LoggerFactory.getLogger(DepartmentQueries.class);
17 |
18 | @Autowired
19 | DepartmentRepository repository;
20 |
21 | public Department newDepartment(Department department) {
22 | LOGGER.info("Department add: department={}", department);
23 | return repository.add(department);
24 | }
25 |
26 | public boolean deleteDepartment(Long id) {
27 | LOGGER.info("Department delete: id={}", id);
28 | return repository.delete(id);
29 | }
30 |
31 | public Department updateDepartment(Long id, Department department) {
32 | LOGGER.info("Department update: id={}, department={}", id, department);
33 | return repository.update(id, department);
34 | }
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/department-service/src/main/java/pl/piomin/services/department/resolver/DepartmentQueries.java:
--------------------------------------------------------------------------------
1 | package pl.piomin.services.department.resolver;
2 |
3 | import java.util.List;
4 |
5 | import org.slf4j.Logger;
6 | import org.slf4j.LoggerFactory;
7 | import org.springframework.beans.factory.annotation.Autowired;
8 | import org.springframework.stereotype.Component;
9 |
10 | import com.coxautodev.graphql.tools.GraphQLQueryResolver;
11 |
12 | import pl.piomin.services.department.client.EmployeeClient;
13 | import pl.piomin.services.department.model.Department;
14 | import pl.piomin.services.department.repository.DepartmentRepository;
15 |
16 | @Component
17 | public class DepartmentQueries implements GraphQLQueryResolver {
18 |
19 | private static final Logger LOGGER = LoggerFactory.getLogger(DepartmentQueries.class);
20 |
21 | @Autowired
22 | EmployeeClient employeeClient;
23 | @Autowired
24 | DepartmentRepository repository;
25 |
26 | public List departments() {
27 | LOGGER.info("Departments find");
28 | return repository.findAll();
29 | }
30 |
31 | public List departmentsByOrganization(Long organizationId) {
32 | LOGGER.info("Departments find: organizationId={}", organizationId);
33 | return repository.findByOrganization(organizationId);
34 | }
35 |
36 | public List departmentsByOrganizationWithEmployees(Long organizationId) {
37 | LOGGER.info("Departments find: organizationId={}", organizationId);
38 | List departments = repository.findByOrganization(organizationId);
39 | for (int i = 0; i < departments.size(); i++) {
40 | try {
41 | departments.get(i).setEmployees(employeeClient.findByDepartment(departments.get(i).getId()));
42 | } catch (InterruptedException e) {
43 | LOGGER.error("Error calling employee-service", e);
44 | }
45 | }
46 | return departments;
47 | }
48 |
49 | public Department department(Long id) {
50 | LOGGER.info("Department find: id={}", id);
51 | return repository.findById(id);
52 | }
53 |
54 | }
55 |
--------------------------------------------------------------------------------
/department-service/src/main/java/type/CustomType.java:
--------------------------------------------------------------------------------
1 | package type;
2 |
3 | import com.apollographql.apollo.api.ScalarType;
4 | import java.lang.Class;
5 | import java.lang.Override;
6 | import java.lang.String;
7 | import javax.annotation.Generated;
8 |
9 | @Generated("Apollo GraphQL")
10 | public enum CustomType implements ScalarType {
11 | ID {
12 | @Override
13 | public String typeName() {
14 | return "ID";
15 | }
16 |
17 | @Override
18 | public Class javaType() {
19 | return String.class;
20 | }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/department-service/src/main/resources/bootstrap.yml:
--------------------------------------------------------------------------------
1 | spring:
2 | application:
3 | name: department-service
4 | server:
5 | port: 8091
6 |
7 | eureka:
8 | client:
9 | serviceUrl:
10 | defaultZone: http://localhost:8061/eureka/
11 |
12 | logging:
13 | pattern:
14 | console: "%d{yyyy-MM-dd HH:mm:ss} ${LOG_LEVEL_PATTERN:-%5p} %m%n"
--------------------------------------------------------------------------------
/department-service/src/main/resources/graphql/department.graphqls:
--------------------------------------------------------------------------------
1 | schema {
2 | query: DepartmentQueries
3 | mutation: DepartmentMutations
4 | }
5 |
6 | type DepartmentQueries {
7 | departments: [Department]
8 | department(id: ID!): Department!
9 | departmentsByOrganization(organizationId: Int!): [Department]
10 | departmentsByOrganizationWithEmployees(organizationId: Int!): [Department]
11 | }
12 |
13 | type DepartmentMutations {
14 | newDepartment(department: DepartmentInput!): Department
15 | deleteDepartment(id: ID!) : Boolean
16 | updateDepartment(id: ID!, department: DepartmentInput!): Department
17 | }
18 |
19 | input DepartmentInput {
20 | organizationId: Int!
21 | name: String!
22 | }
23 |
24 | type Department {
25 | id: ID!
26 | organizationId: Int!
27 | name: String!
28 | employees: [Employee]
29 | }
30 |
31 | type Employee {
32 | id: ID!
33 | name: String!
34 | position: String!
35 | salary: Int!
36 | }
--------------------------------------------------------------------------------
/department-service/src/test/java/pl/piomin/services/department/DepartmentAppTests.java:
--------------------------------------------------------------------------------
1 | package pl.piomin.services.department;
2 |
3 | import com.apollographql.apollo3.ApolloClient;
4 | import org.junit.Test;
5 | import org.junit.runner.RunWith;
6 | import org.springframework.boot.test.context.SpringBootTest;
7 | import org.springframework.boot.test.context.TestConfiguration;
8 | import org.springframework.boot.web.server.LocalServerPort;
9 | import org.springframework.context.annotation.Bean;
10 | import org.springframework.test.context.junit4.SpringRunner;
11 | import pl.piomin.services.department.clientoperation.DepartmentsByOrganizationQuery;
12 | import pl.piomin.services.department.clientoperation.DepartmentsQuery;
13 |
14 | @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
15 | @RunWith(SpringRunner.class)
16 | public class DepartmentAppTests {
17 |
18 | @LocalServerPort
19 | int port;
20 |
21 | @Test
22 | public void departments() {
23 | ApolloClient client = new ApolloClient.Builder()
24 | .serverUrl("http://localhost:" + port + "/graphql")
25 | .build();
26 | client.query(new DepartmentsQuery());
27 | }
28 |
29 | @Test
30 | public void departmentsByOrganization() {
31 | ApolloClient client = new ApolloClient.Builder()
32 | .serverUrl("http://localhost:" + port + "/graphql")
33 | .build();
34 | client.query(new DepartmentsByOrganizationQuery());
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/discovery-service/.gitignore:
--------------------------------------------------------------------------------
1 | /target/
2 | /.settings/
3 | /.classpath
4 | /.project
5 |
--------------------------------------------------------------------------------
/discovery-service/pom.xml:
--------------------------------------------------------------------------------
1 |
3 | 4.0.0
4 |
5 | pl.piomin.services
6 | sample-graphql-microservices
7 | 1.0-SNAPSHOT
8 |
9 | discovery-service
10 | 1.0-SNAPSHOT
11 |
12 |
13 | ${project.artifactId}
14 |
15 |
16 |
17 |
18 | org.springframework.cloud
19 | spring-cloud-starter-netflix-eureka-server
20 |
21 |
22 | org.springframework.cloud
23 | spring-cloud-starter-config
24 |
25 |
26 |
27 |
28 |
29 |
30 | org.springframework.boot
31 | spring-boot-maven-plugin
32 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/discovery-service/src/main/java/META-INF/MANIFEST.MF:
--------------------------------------------------------------------------------
1 | Manifest-Version: 1.0
2 | Class-Path:
3 |
4 |
--------------------------------------------------------------------------------
/discovery-service/src/main/java/pl/piomin/services/discovery/DiscoveryApplication.java:
--------------------------------------------------------------------------------
1 | package pl.piomin.services.discovery;
2 |
3 | import org.springframework.boot.autoconfigure.SpringBootApplication;
4 | import org.springframework.boot.builder.SpringApplicationBuilder;
5 | import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
6 |
7 | @SpringBootApplication
8 | @EnableEurekaServer
9 | public class DiscoveryApplication {
10 |
11 | public static void main(String[] args) {
12 | new SpringApplicationBuilder(DiscoveryApplication.class).run(args);
13 | }
14 |
15 | }
16 |
--------------------------------------------------------------------------------
/discovery-service/src/main/resources/bootstrap.yml:
--------------------------------------------------------------------------------
1 | spring:
2 | application:
3 | name: discovery-service
4 |
5 | server:
6 | port: 8061
7 |
8 | eureka:
9 | instance:
10 | hostname: localhost
11 | client:
12 | registerWithEureka: false
13 | fetchRegistry: false
14 | serviceUrl:
15 | defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
--------------------------------------------------------------------------------
/employee-service/.gitignore:
--------------------------------------------------------------------------------
1 | /target/
2 | /.classpath
3 | /.project
4 | /.settings/
5 |
--------------------------------------------------------------------------------
/employee-service/pom.xml:
--------------------------------------------------------------------------------
1 |
3 | 4.0.0
4 |
5 | pl.piomin.services
6 | sample-graphql-microservices
7 | 1.0-SNAPSHOT
8 |
9 | employee-service
10 | 1.0-SNAPSHOT
11 |
12 |
13 | ${project.artifactId}
14 |
15 |
16 |
17 |
18 | org.springframework.cloud
19 | spring-cloud-starter-netflix-eureka-client
20 |
21 |
22 | org.springframework.boot
23 | spring-boot-starter-web
24 |
25 |
26 | org.springframework.boot
27 | spring-boot-starter-actuator
28 |
29 |
30 | com.graphql-java
31 | graphql-spring-boot-starter
32 | 5.0.2
33 |
34 |
35 | com.graphql-java
36 | graphiql-spring-boot-starter
37 | 5.0.2
38 |
39 |
40 | com.graphql-java
41 | voyager-spring-boot-starter
42 | 5.0.2
43 |
44 |
45 | com.graphql-java
46 | graphql-java
47 | 9.2
48 |
49 |
50 | com.graphql-java
51 | graphql-java-tools
52 | 5.2.3
53 |
54 |
55 | com.apollographql.apollo
56 | apollo-runtime
57 | 1.0.1
58 |
59 |
60 | com.apollographql.apollo3
61 | apollo-api-jvm
62 | 3.0.0
63 |
64 |
65 | com.apollographql.apollo3
66 | apollo-runtime-jvm
67 | 3.0.0
68 |
69 |
70 | org.springframework.boot
71 | spring-boot-starter-test
72 | test
73 |
74 |
75 |
76 |
77 |
78 |
79 | org.springframework.boot
80 | spring-boot-maven-plugin
81 |
82 |
83 | com.github.aoudiamoncef
84 | apollo-client-maven-plugin
85 | 5.0.0
86 |
87 |
88 |
89 | generate
90 |
91 |
92 |
93 |
94 |
95 | employees
96 |
97 | pl.piomin.services.employee.client
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
--------------------------------------------------------------------------------
/employee-service/src/main/graphql/employees/queries/employees.graphql:
--------------------------------------------------------------------------------
1 | query employees {
2 | employees {
3 | id
4 | organizationId
5 | departmentId
6 | name
7 | age
8 | position
9 | }
10 | }
--------------------------------------------------------------------------------
/employee-service/src/main/graphql/employees/schema.json:
--------------------------------------------------------------------------------
1 | {"data":{"__schema":{"queryType":{"name":"EmployeeQueries"},"mutationType":{"name":"EmployeeMutations"},"subscriptionType":null,"types":[{"kind":"OBJECT","name":"EmployeeQueries","description":"","fields":[{"name":"employees","description":"","args":[],"type":{"kind":"LIST","name":null,"ofType":{"kind":"OBJECT","name":"Employee","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"employee","description":"","args":[{"name":"id","description":"","type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"ID","ofType":null}},"defaultValue":null}],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"OBJECT","name":"Employee","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"employeesByOrganization","description":"","args":[{"name":"organizationId","description":"","type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"Int","ofType":null}},"defaultValue":null}],"type":{"kind":"LIST","name":null,"ofType":{"kind":"OBJECT","name":"Employee","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"employeesByDepartment","description":"","args":[{"name":"departmentId","description":"","type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"Int","ofType":null}},"defaultValue":null}],"type":{"kind":"LIST","name":null,"ofType":{"kind":"OBJECT","name":"Employee","ofType":null}},"isDeprecated":false,"deprecationReason":null}],"inputFields":null,"interfaces":[],"enumValues":null,"possibleTypes":null},{"kind":"SCALAR","name":"ID","description":"Built-in ID","fields":null,"inputFields":null,"interfaces":null,"enumValues":null,"possibleTypes":null},{"kind":"SCALAR","name":"Int","description":"Built-in Int","fields":null,"inputFields":null,"interfaces":null,"enumValues":null,"possibleTypes":null},{"kind":"OBJECT","name":"EmployeeMutations","description":"","fields":[{"name":"newEmployee","description":"","args":[{"name":"employee","description":"","type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"INPUT_OBJECT","name":"EmployeeInput","ofType":null}},"defaultValue":null}],"type":{"kind":"OBJECT","name":"Employee","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"deleteEmployee","description":"","args":[{"name":"id","description":"","type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"ID","ofType":null}},"defaultValue":null}],"type":{"kind":"SCALAR","name":"Boolean","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"updateEmployee","description":"","args":[{"name":"id","description":"","type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"ID","ofType":null}},"defaultValue":null},{"name":"employee","description":"","type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"INPUT_OBJECT","name":"EmployeeInput","ofType":null}},"defaultValue":null}],"type":{"kind":"OBJECT","name":"Employee","ofType":null},"isDeprecated":false,"deprecationReason":null}],"inputFields":null,"interfaces":[],"enumValues":null,"possibleTypes":null},{"kind":"SCALAR","name":"Boolean","description":"Built-in Boolean","fields":null,"inputFields":null,"interfaces":null,"enumValues":null,"possibleTypes":null},{"kind":"OBJECT","name":"Employee","description":"","fields":[{"name":"id","description":"","args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"ID","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"organizationId","description":"","args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"Int","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"departmentId","description":"","args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"Int","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"name","description":"","args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"String","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"age","description":"","args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"Int","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"position","description":"","args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"String","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"salary","description":"","args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"Int","ofType":null}},"isDeprecated":false,"deprecationReason":null}],"inputFields":null,"interfaces":[],"enumValues":null,"possibleTypes":null},{"kind":"SCALAR","name":"String","description":"Built-in String","fields":null,"inputFields":null,"interfaces":null,"enumValues":null,"possibleTypes":null},{"kind":"INPUT_OBJECT","name":"EmployeeInput","description":"","fields":null,"inputFields":[{"name":"organizationId","description":"","type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"Int","ofType":null}},"defaultValue":null},{"name":"departmentId","description":"","type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"Int","ofType":null}},"defaultValue":null},{"name":"name","description":"","type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"String","ofType":null}},"defaultValue":null},{"name":"age","description":"","type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"Int","ofType":null}},"defaultValue":null},{"name":"position","description":"","type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"String","ofType":null}},"defaultValue":null},{"name":"salary","description":"","type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"Int","ofType":null}},"defaultValue":null}],"interfaces":null,"enumValues":null,"possibleTypes":null},{"kind":"OBJECT","name":"__Schema","description":"A GraphQL Introspection defines the capabilities of a GraphQL server. It exposes all available types and directives on the server, the entry points for query, mutation, and subscription operations.","fields":[{"name":"types","description":"A list of all types supported by this server.","args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"LIST","name":null,"ofType":{"kind":"NON_NULL","name":null,"ofType":{"kind":"OBJECT","name":"__Type"}}}},"isDeprecated":false,"deprecationReason":null},{"name":"queryType","description":"The type that query operations will be rooted at.","args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"OBJECT","name":"__Type","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"mutationType","description":"If this server supports mutation, the type that mutation operations will be rooted at.","args":[],"type":{"kind":"OBJECT","name":"__Type","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"directives","description":"'A list of all directives supported by this server.","args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"LIST","name":null,"ofType":{"kind":"NON_NULL","name":null,"ofType":{"kind":"OBJECT","name":"__Directive"}}}},"isDeprecated":false,"deprecationReason":null},{"name":"subscriptionType","description":"'If this server support subscription, the type that subscription operations will be rooted at.","args":[],"type":{"kind":"OBJECT","name":"__Type","ofType":null},"isDeprecated":false,"deprecationReason":null}],"inputFields":null,"interfaces":[],"enumValues":null,"possibleTypes":null},{"kind":"OBJECT","name":"__Type","description":null,"fields":[{"name":"kind","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"ENUM","name":"__TypeKind","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"name","description":null,"args":[],"type":{"kind":"SCALAR","name":"String","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"description","description":null,"args":[],"type":{"kind":"SCALAR","name":"String","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"fields","description":null,"args":[{"name":"includeDeprecated","description":null,"type":{"kind":"SCALAR","name":"Boolean","ofType":null},"defaultValue":"false"}],"type":{"kind":"LIST","name":null,"ofType":{"kind":"NON_NULL","name":null,"ofType":{"kind":"OBJECT","name":"__Field","ofType":null}}},"isDeprecated":false,"deprecationReason":null},{"name":"interfaces","description":null,"args":[],"type":{"kind":"LIST","name":null,"ofType":{"kind":"NON_NULL","name":null,"ofType":{"kind":"OBJECT","name":"__Type","ofType":null}}},"isDeprecated":false,"deprecationReason":null},{"name":"possibleTypes","description":null,"args":[],"type":{"kind":"LIST","name":null,"ofType":{"kind":"NON_NULL","name":null,"ofType":{"kind":"OBJECT","name":"__Type","ofType":null}}},"isDeprecated":false,"deprecationReason":null},{"name":"enumValues","description":null,"args":[{"name":"includeDeprecated","description":null,"type":{"kind":"SCALAR","name":"Boolean","ofType":null},"defaultValue":"false"}],"type":{"kind":"LIST","name":null,"ofType":{"kind":"NON_NULL","name":null,"ofType":{"kind":"OBJECT","name":"__EnumValue","ofType":null}}},"isDeprecated":false,"deprecationReason":null},{"name":"inputFields","description":null,"args":[],"type":{"kind":"LIST","name":null,"ofType":{"kind":"NON_NULL","name":null,"ofType":{"kind":"OBJECT","name":"__InputValue","ofType":null}}},"isDeprecated":false,"deprecationReason":null},{"name":"ofType","description":null,"args":[],"type":{"kind":"OBJECT","name":"__Type","ofType":null},"isDeprecated":false,"deprecationReason":null}],"inputFields":null,"interfaces":[],"enumValues":null,"possibleTypes":null},{"kind":"ENUM","name":"__TypeKind","description":"An enum describing what kind of type a given __Type is","fields":null,"inputFields":null,"interfaces":null,"enumValues":[{"name":"SCALAR","description":"Indicates this type is a scalar.","isDeprecated":false,"deprecationReason":null},{"name":"OBJECT","description":"Indicates this type is an object. `fields` and `interfaces` are valid fields.","isDeprecated":false,"deprecationReason":null},{"name":"INTERFACE","description":"Indicates this type is an interface. `fields` and `possibleTypes` are valid fields.","isDeprecated":false,"deprecationReason":null},{"name":"UNION","description":"Indicates this type is a union. `possibleTypes` is a valid field.","isDeprecated":false,"deprecationReason":null},{"name":"ENUM","description":"Indicates this type is an enum. `enumValues` is a valid field.","isDeprecated":false,"deprecationReason":null},{"name":"INPUT_OBJECT","description":"Indicates this type is an input object. `inputFields` is a valid field.","isDeprecated":false,"deprecationReason":null},{"name":"LIST","description":"Indicates this type is a list. `ofType` is a valid field.","isDeprecated":false,"deprecationReason":null},{"name":"NON_NULL","description":"Indicates this type is a non-null. `ofType` is a valid field.","isDeprecated":false,"deprecationReason":null}],"possibleTypes":null},{"kind":"OBJECT","name":"__Field","description":null,"fields":[{"name":"name","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"String","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"description","description":null,"args":[],"type":{"kind":"SCALAR","name":"String","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"args","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"LIST","name":null,"ofType":{"kind":"NON_NULL","name":null,"ofType":{"kind":"OBJECT","name":"__InputValue"}}}},"isDeprecated":false,"deprecationReason":null},{"name":"type","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"OBJECT","name":"__Type","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"isDeprecated","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"Boolean","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"deprecationReason","description":null,"args":[],"type":{"kind":"SCALAR","name":"String","ofType":null},"isDeprecated":false,"deprecationReason":null}],"inputFields":null,"interfaces":[],"enumValues":null,"possibleTypes":null},{"kind":"OBJECT","name":"__InputValue","description":null,"fields":[{"name":"name","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"String","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"description","description":null,"args":[],"type":{"kind":"SCALAR","name":"String","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"type","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"OBJECT","name":"__Type","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"defaultValue","description":null,"args":[],"type":{"kind":"SCALAR","name":"String","ofType":null},"isDeprecated":false,"deprecationReason":null}],"inputFields":null,"interfaces":[],"enumValues":null,"possibleTypes":null},{"kind":"OBJECT","name":"__EnumValue","description":null,"fields":[{"name":"name","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"String","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"description","description":null,"args":[],"type":{"kind":"SCALAR","name":"String","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"isDeprecated","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"Boolean","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"deprecationReason","description":null,"args":[],"type":{"kind":"SCALAR","name":"String","ofType":null},"isDeprecated":false,"deprecationReason":null}],"inputFields":null,"interfaces":[],"enumValues":null,"possibleTypes":null},{"kind":"OBJECT","name":"__Directive","description":null,"fields":[{"name":"name","description":null,"args":[],"type":{"kind":"SCALAR","name":"String","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"description","description":null,"args":[],"type":{"kind":"SCALAR","name":"String","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"locations","description":null,"args":[],"type":{"kind":"LIST","name":null,"ofType":{"kind":"NON_NULL","name":null,"ofType":{"kind":"ENUM","name":"__DirectiveLocation","ofType":null}}},"isDeprecated":false,"deprecationReason":null},{"name":"args","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"LIST","name":null,"ofType":{"kind":"NON_NULL","name":null,"ofType":{"kind":"OBJECT","name":"__InputValue"}}}},"isDeprecated":false,"deprecationReason":null},{"name":"onOperation","description":null,"args":[],"type":{"kind":"SCALAR","name":"Boolean","ofType":null},"isDeprecated":true,"deprecationReason":"Use `locations`."},{"name":"onFragment","description":null,"args":[],"type":{"kind":"SCALAR","name":"Boolean","ofType":null},"isDeprecated":true,"deprecationReason":"Use `locations`."},{"name":"onField","description":null,"args":[],"type":{"kind":"SCALAR","name":"Boolean","ofType":null},"isDeprecated":true,"deprecationReason":"Use `locations`."}],"inputFields":null,"interfaces":[],"enumValues":null,"possibleTypes":null},{"kind":"ENUM","name":"__DirectiveLocation","description":"An enum describing valid locations where a directive can be placed","fields":null,"inputFields":null,"interfaces":null,"enumValues":[{"name":"QUERY","description":"Indicates the directive is valid on queries.","isDeprecated":false,"deprecationReason":null},{"name":"MUTATION","description":"Indicates the directive is valid on mutations.","isDeprecated":false,"deprecationReason":null},{"name":"FIELD","description":"Indicates the directive is valid on fields.","isDeprecated":false,"deprecationReason":null},{"name":"FRAGMENT_DEFINITION","description":"Indicates the directive is valid on fragment definitions.","isDeprecated":false,"deprecationReason":null},{"name":"FRAGMENT_SPREAD","description":"Indicates the directive is valid on fragment spreads.","isDeprecated":false,"deprecationReason":null},{"name":"INLINE_FRAGMENT","description":"Indicates the directive is valid on inline fragments.","isDeprecated":false,"deprecationReason":null},{"name":"SCHEMA","description":"Indicates the directive is valid on a schema SDL definition.","isDeprecated":false,"deprecationReason":null},{"name":"SCALAR","description":"Indicates the directive is valid on a scalar SDL definition.","isDeprecated":false,"deprecationReason":null},{"name":"OBJECT","description":"Indicates the directive is valid on an object SDL definition.","isDeprecated":false,"deprecationReason":null},{"name":"FIELD_DEFINITION","description":"Indicates the directive is valid on a field SDL definition.","isDeprecated":false,"deprecationReason":null},{"name":"ARGUMENT_DEFINITION","description":"Indicates the directive is valid on a field argument SDL definition.","isDeprecated":false,"deprecationReason":null},{"name":"INTERFACE","description":"Indicates the directive is valid on an interface SDL definition.","isDeprecated":false,"deprecationReason":null},{"name":"UNION","description":"Indicates the directive is valid on an union SDL definition.","isDeprecated":false,"deprecationReason":null},{"name":"ENUM","description":"Indicates the directive is valid on an enum SDL definition.","isDeprecated":false,"deprecationReason":null},{"name":"ENUM_VALUE","description":"Indicates the directive is valid on an enum value SDL definition.","isDeprecated":false,"deprecationReason":null},{"name":"INPUT_OBJECT","description":"Indicates the directive is valid on an input object SDL definition.","isDeprecated":false,"deprecationReason":null},{"name":"INPUT_FIELD_DEFINITION","description":"Indicates the directive is valid on an input object field SDL definition.","isDeprecated":false,"deprecationReason":null}],"possibleTypes":null}],"directives":[{"name":"include","description":"Directs the executor to include this field or fragment only when the `if` argument is true","locations":["FIELD","FRAGMENT_SPREAD","INLINE_FRAGMENT"],"args":[{"name":"if","description":"Included when true.","type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"Boolean","ofType":null}},"defaultValue":null}]},{"name":"skip","description":"Directs the executor to skip this field or fragment when the `if`'argument is true.","locations":["FIELD","FRAGMENT_SPREAD","INLINE_FRAGMENT"],"args":[{"name":"if","description":"Skipped when true.","type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"Boolean","ofType":null}},"defaultValue":null}]},{"name":"defer","description":"This directive allows results to be deferred during execution","locations":["FIELD"],"args":[]}]}}}
--------------------------------------------------------------------------------
/employee-service/src/main/java/META-INF/MANIFEST.MF:
--------------------------------------------------------------------------------
1 | Manifest-Version: 1.0
2 | Class-Path:
3 |
4 |
--------------------------------------------------------------------------------
/employee-service/src/main/java/pl/piomin/services/employee/EmployeeApplication.java:
--------------------------------------------------------------------------------
1 | package pl.piomin.services.employee;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 | import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
6 | import org.springframework.context.annotation.Bean;
7 |
8 | import pl.piomin.services.employee.model.Employee;
9 | import pl.piomin.services.employee.repository.EmployeeRepository;
10 |
11 | @SpringBootApplication
12 | @EnableDiscoveryClient
13 | public class EmployeeApplication {
14 |
15 | public static void main(String[] args) {
16 | SpringApplication.run(EmployeeApplication.class, args);
17 | }
18 |
19 | @Bean
20 | EmployeeRepository repository() {
21 | EmployeeRepository repository = new EmployeeRepository();
22 | repository.add(new Employee(1L, 1L, "John Smith", 34, "Analyst", 3000));
23 | repository.add(new Employee(1L, 1L, "Darren Hamilton", 37, "Manager", 5000));
24 | repository.add(new Employee(1L, 1L, "Tom Scott", 26, "Developer", 4500));
25 | repository.add(new Employee(1L, 2L, "Anna London", 39, "Analyst", 2500));
26 | repository.add(new Employee(1L, 2L, "Patrick Dempsey", 27, "Developer", 5000));
27 | repository.add(new Employee(2L, 3L, "Kevin Price", 38, "Developer", 6000));
28 | repository.add(new Employee(2L, 3L, "Ian Scott", 34, "Developer", 4500));
29 | repository.add(new Employee(2L, 3L, "Andrew Campton", 30, "Manager", 8000));
30 | repository.add(new Employee(2L, 4L, "Steve Franklin", 25, "Developer", 4000));
31 | repository.add(new Employee(2L, 4L, "Elisabeth Smith", 30, "Developer", 4000));
32 | return repository;
33 | }
34 |
35 | }
36 |
--------------------------------------------------------------------------------
/employee-service/src/main/java/pl/piomin/services/employee/model/Employee.java:
--------------------------------------------------------------------------------
1 | package pl.piomin.services.employee.model;
2 |
3 | public class Employee {
4 |
5 | private Long id;
6 | private Long organizationId;
7 | private Long departmentId;
8 | private String name;
9 | private int age;
10 | private String position;
11 | private int salary;
12 |
13 | public Employee() {
14 |
15 | }
16 |
17 | public Employee(Long organizationId, Long departmentId, String name, int age, String position, int salary) {
18 | this.organizationId = organizationId;
19 | this.departmentId = departmentId;
20 | this.name = name;
21 | this.age = age;
22 | this.position = position;
23 | this.salary = salary;
24 | }
25 |
26 | public Long getId() {
27 | return id;
28 | }
29 |
30 | public void setId(Long id) {
31 | this.id = id;
32 | }
33 |
34 | public Long getOrganizationId() {
35 | return organizationId;
36 | }
37 |
38 | public void setOrganizationId(Long organizationId) {
39 | this.organizationId = organizationId;
40 | }
41 |
42 | public Long getDepartmentId() {
43 | return departmentId;
44 | }
45 |
46 | public void setDepartmentId(Long departmentId) {
47 | this.departmentId = departmentId;
48 | }
49 |
50 | public String getName() {
51 | return name;
52 | }
53 |
54 | public void setName(String name) {
55 | this.name = name;
56 | }
57 |
58 | public int getAge() {
59 | return age;
60 | }
61 |
62 | public void setAge(int age) {
63 | this.age = age;
64 | }
65 |
66 | public String getPosition() {
67 | return position;
68 | }
69 |
70 | public void setPosition(String position) {
71 | this.position = position;
72 | }
73 |
74 | public int getSalary() {
75 | return salary;
76 | }
77 |
78 | public void setSalary(int salary) {
79 | this.salary = salary;
80 | }
81 |
82 | @Override
83 | public String toString() {
84 | return "Employee [id=" + id + ", organizationId=" + organizationId + ", departmentId=" + departmentId
85 | + ", name=" + name + ", position=" + position + "]";
86 | }
87 |
88 | @Override
89 | public int hashCode() {
90 | final int prime = 31;
91 | int result = 1;
92 | result = prime * result + ((id == null) ? 0 : id.hashCode());
93 | return result;
94 | }
95 |
96 | @Override
97 | public boolean equals(Object obj) {
98 | if (this == obj)
99 | return true;
100 | if (obj == null)
101 | return false;
102 | if (getClass() != obj.getClass())
103 | return false;
104 | Employee other = (Employee) obj;
105 | if (id == null) {
106 | if (other.id != null)
107 | return false;
108 | } else if (!id.equals(other.id))
109 | return false;
110 | return true;
111 | }
112 |
113 | }
114 |
--------------------------------------------------------------------------------
/employee-service/src/main/java/pl/piomin/services/employee/model/EmployeesQuery.java:
--------------------------------------------------------------------------------
1 | package pl.piomin.services.employee.model;
2 |
3 | import com.apollographql.apollo.api.Operation;
4 | import com.apollographql.apollo.api.OperationName;
5 | import com.apollographql.apollo.api.Query;
6 | import com.apollographql.apollo.api.ResponseField;
7 | import com.apollographql.apollo.api.ResponseFieldMapper;
8 | import com.apollographql.apollo.api.ResponseFieldMarshaller;
9 | import com.apollographql.apollo.api.ResponseReader;
10 | import com.apollographql.apollo.api.ResponseWriter;
11 | import com.apollographql.apollo.api.internal.Utils;
12 | import java.lang.Object;
13 | import java.lang.Override;
14 | import java.lang.String;
15 | import java.util.Collections;
16 | import java.util.List;
17 | import javax.annotation.Generated;
18 | import org.jetbrains.annotations.NotNull;
19 | import org.jetbrains.annotations.Nullable;
20 |
21 | @Generated("Apollo GraphQL")
22 | public final class EmployeesQuery implements Query {
23 | public static final String OPERATION_DEFINITION = "query EmployeesQuery {\n"
24 | + " employees {\n"
25 | + " __typename\n"
26 | + " name\n"
27 | + " age\n"
28 | + " }\n"
29 | + "}";
30 |
31 | public static final String OPERATION_ID = "fb9a898c6d1af441e2a005a73850290ea980e0b0575b833cb06f17dd2331ba13";
32 |
33 | public static final String QUERY_DOCUMENT = OPERATION_DEFINITION;
34 |
35 | public static final OperationName OPERATION_NAME = new OperationName() {
36 | @Override
37 | public String name() {
38 | return "EmployeesQuery";
39 | }
40 | };
41 |
42 | private final Operation.Variables variables;
43 |
44 | public EmployeesQuery() {
45 | this.variables = Operation.EMPTY_VARIABLES;
46 | }
47 |
48 | @Override
49 | public String operationId() {
50 | return OPERATION_ID;
51 | }
52 |
53 | @Override
54 | public String queryDocument() {
55 | return QUERY_DOCUMENT;
56 | }
57 |
58 | @Override
59 | public EmployeesQuery.Data wrapData(EmployeesQuery.Data data) {
60 | return data;
61 | }
62 |
63 | @Override
64 | public Operation.Variables variables() {
65 | return variables;
66 | }
67 |
68 | @Override
69 | public ResponseFieldMapper responseFieldMapper() {
70 | return new Data.Mapper();
71 | }
72 |
73 | public static Builder builder() {
74 | return new Builder();
75 | }
76 |
77 | @Override
78 | public OperationName name() {
79 | return OPERATION_NAME;
80 | }
81 |
82 | public static final class Builder {
83 | Builder() {
84 | }
85 |
86 | public EmployeesQuery build() {
87 | return new EmployeesQuery();
88 | }
89 | }
90 |
91 | public static class Data implements Operation.Data {
92 | static final ResponseField[] $responseFields = {
93 | ResponseField.forList("employees", "employees", null, true, Collections.emptyList())
94 | };
95 |
96 | final @Nullable List employees;
97 |
98 | private volatile String $toString;
99 |
100 | private volatile int $hashCode;
101 |
102 | private volatile boolean $hashCodeMemoized;
103 |
104 | public Data(@Nullable List employees) {
105 | this.employees = employees;
106 | }
107 |
108 | public @Nullable List employees() {
109 | return this.employees;
110 | }
111 |
112 | public ResponseFieldMarshaller marshaller() {
113 | return new ResponseFieldMarshaller() {
114 | @Override
115 | public void marshal(ResponseWriter writer) {
116 | writer.writeList($responseFields[0], employees, new ResponseWriter.ListWriter() {
117 |
118 | @Override
119 | public void write(@Nullable List list, @NotNull ResponseWriter.ListItemWriter listItemWriter) {
120 | listItemWriter.writeList(list, this);
121 | }
122 |
123 | // public void write(Object value, ResponseWriter.ListItemWriter listItemWriter) {
124 | // listItemWriter.writeObject(((Employee) value).marshaller());
125 | // }
126 | });
127 | }
128 | };
129 | }
130 |
131 | @Override
132 | public String toString() {
133 | if ($toString == null) {
134 | $toString = "Data{"
135 | + "employees=" + employees
136 | + "}";
137 | }
138 | return $toString;
139 | }
140 |
141 | @Override
142 | public boolean equals(Object o) {
143 | if (o == this) {
144 | return true;
145 | }
146 | if (o instanceof Data) {
147 | Data that = (Data) o;
148 | return ((this.employees == null) ? (that.employees == null) : this.employees.equals(that.employees));
149 | }
150 | return false;
151 | }
152 |
153 | @Override
154 | public int hashCode() {
155 | if (!$hashCodeMemoized) {
156 | int h = 1;
157 | h *= 1000003;
158 | h ^= (employees == null) ? 0 : employees.hashCode();
159 | $hashCode = h;
160 | $hashCodeMemoized = true;
161 | }
162 | return $hashCode;
163 | }
164 |
165 | public static final class Mapper implements ResponseFieldMapper {
166 | final Employee.Mapper employeeFieldMapper = new Employee.Mapper();
167 |
168 | @Override
169 | public Data map(ResponseReader reader) {
170 | final List employees = reader.readList($responseFields[0], new ResponseReader.ListReader() {
171 | @Override
172 | public Employee read(ResponseReader.ListItemReader listItemReader) {
173 | return listItemReader.readObject(new ResponseReader.ObjectReader() {
174 | @Override
175 | public Employee read(ResponseReader reader) {
176 | return employeeFieldMapper.map(reader);
177 | }
178 | });
179 | }
180 | });
181 | return new Data(employees);
182 | }
183 | }
184 | }
185 |
186 | public static class Employee {
187 | static final ResponseField[] $responseFields = {
188 | ResponseField.forString("__typename", "__typename", null, false, Collections.emptyList()),
189 | ResponseField.forString("name", "name", null, false, Collections.emptyList()),
190 | ResponseField.forInt("age", "age", null, false, Collections.emptyList())
191 | };
192 |
193 | final @NotNull String __typename;
194 |
195 | final @NotNull String name;
196 |
197 | final int age;
198 |
199 | private volatile String $toString;
200 |
201 | private volatile int $hashCode;
202 |
203 | private volatile boolean $hashCodeMemoized;
204 |
205 | public Employee(@NotNull String __typename, @NotNull String name, int age) {
206 | this.__typename = Utils.checkNotNull(__typename, "__typename == null");
207 | this.name = Utils.checkNotNull(name, "name == null");
208 | this.age = age;
209 | }
210 |
211 | public @NotNull String __typename() {
212 | return this.__typename;
213 | }
214 |
215 | public @NotNull String name() {
216 | return this.name;
217 | }
218 |
219 | public int age() {
220 | return this.age;
221 | }
222 |
223 | public ResponseFieldMarshaller marshaller() {
224 | return new ResponseFieldMarshaller() {
225 | @Override
226 | public void marshal(ResponseWriter writer) {
227 | writer.writeString($responseFields[0], __typename);
228 | writer.writeString($responseFields[1], name);
229 | writer.writeInt($responseFields[2], age);
230 | }
231 | };
232 | }
233 |
234 | @Override
235 | public String toString() {
236 | if ($toString == null) {
237 | $toString = "Employee{"
238 | + "__typename=" + __typename + ", "
239 | + "name=" + name + ", "
240 | + "age=" + age
241 | + "}";
242 | }
243 | return $toString;
244 | }
245 |
246 | @Override
247 | public boolean equals(Object o) {
248 | if (o == this) {
249 | return true;
250 | }
251 | if (o instanceof Employee) {
252 | Employee that = (Employee) o;
253 | return this.__typename.equals(that.__typename)
254 | && this.name.equals(that.name)
255 | && this.age == that.age;
256 | }
257 | return false;
258 | }
259 |
260 | @Override
261 | public int hashCode() {
262 | if (!$hashCodeMemoized) {
263 | int h = 1;
264 | h *= 1000003;
265 | h ^= __typename.hashCode();
266 | h *= 1000003;
267 | h ^= name.hashCode();
268 | h *= 1000003;
269 | h ^= age;
270 | $hashCode = h;
271 | $hashCodeMemoized = true;
272 | }
273 | return $hashCode;
274 | }
275 |
276 | public static final class Mapper implements ResponseFieldMapper {
277 | @Override
278 | public Employee map(ResponseReader reader) {
279 | final String __typename = reader.readString($responseFields[0]);
280 | final String name = reader.readString($responseFields[1]);
281 | final int age = reader.readInt($responseFields[2]);
282 | return new Employee(__typename, name, age);
283 | }
284 | }
285 | }
286 | }
287 |
--------------------------------------------------------------------------------
/employee-service/src/main/java/pl/piomin/services/employee/repository/EmployeeRepository.java:
--------------------------------------------------------------------------------
1 | package pl.piomin.services.employee.repository;
2 |
3 | import java.util.ArrayList;
4 | import java.util.List;
5 | import java.util.Optional;
6 | import java.util.stream.Collectors;
7 |
8 | import pl.piomin.services.employee.model.Employee;
9 |
10 | public class EmployeeRepository {
11 |
12 | private List employees = new ArrayList<>();
13 |
14 | public Employee add(Employee employee) {
15 | employee.setId((long) (employees.size()+1));
16 | employees.add(employee);
17 | return employee;
18 | }
19 |
20 | public Employee findById(Long id) {
21 | Optional employee = employees.stream().filter(a -> a.getId().equals(id)).findFirst();
22 | if (employee.isPresent())
23 | return employee.get();
24 | else
25 | return null;
26 | }
27 |
28 | public List findAll() {
29 | return employees;
30 | }
31 |
32 | public List findByDepartment(Long departmentId) {
33 | return employees.stream().filter(a -> a.getDepartmentId().equals(departmentId)).collect(Collectors.toList());
34 | }
35 |
36 | public List findByOrganization(Long organizationId) {
37 | return employees.stream().filter(a -> a.getOrganizationId().equals(organizationId)).collect(Collectors.toList());
38 | }
39 |
40 | public boolean delete(Long id) {
41 | return employees.removeIf(it -> it.getId() == id.longValue());
42 | }
43 |
44 | public Employee update(Long id, Employee employee) {
45 | employee.setId(id);
46 | int index = employees.indexOf(employee);
47 | employees.set(index, employee);
48 | return employee;
49 | }
50 |
51 | }
52 |
--------------------------------------------------------------------------------
/employee-service/src/main/java/pl/piomin/services/employee/resolver/EmployeeMutations.java:
--------------------------------------------------------------------------------
1 | package pl.piomin.services.employee.resolver;
2 |
3 | import org.slf4j.Logger;
4 | import org.slf4j.LoggerFactory;
5 | import org.springframework.beans.factory.annotation.Autowired;
6 | import org.springframework.stereotype.Component;
7 |
8 | import com.coxautodev.graphql.tools.GraphQLMutationResolver;
9 |
10 | import pl.piomin.services.employee.model.Employee;
11 | import pl.piomin.services.employee.repository.EmployeeRepository;
12 |
13 | @Component
14 | public class EmployeeMutations implements GraphQLMutationResolver {
15 |
16 | private static final Logger LOGGER = LoggerFactory.getLogger(EmployeeQueries.class);
17 |
18 | @Autowired
19 | EmployeeRepository repository;
20 |
21 | public Employee newEmployee(Employee employee) {
22 | LOGGER.info("Employee add: employee={}", employee);
23 | return repository.add(employee);
24 | }
25 |
26 | public boolean deleteEmployee(Long id) {
27 | LOGGER.info("Employee delete: id={}", id);
28 | return repository.delete(id);
29 | }
30 |
31 | public Employee updateEmployee(Long id, Employee employee) {
32 | LOGGER.info("Employee update: id={}, employee={}", id, employee);
33 | return repository.update(id, employee);
34 | }
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/employee-service/src/main/java/pl/piomin/services/employee/resolver/EmployeeQueries.java:
--------------------------------------------------------------------------------
1 | package pl.piomin.services.employee.resolver;
2 |
3 | import java.util.List;
4 |
5 | import org.slf4j.Logger;
6 | import org.slf4j.LoggerFactory;
7 | import org.springframework.beans.factory.annotation.Autowired;
8 | import org.springframework.stereotype.Component;
9 |
10 | import com.coxautodev.graphql.tools.GraphQLQueryResolver;
11 |
12 | import pl.piomin.services.employee.model.Employee;
13 | import pl.piomin.services.employee.repository.EmployeeRepository;
14 |
15 | @Component
16 | public class EmployeeQueries implements GraphQLQueryResolver {
17 |
18 | private static final Logger LOGGER = LoggerFactory.getLogger(EmployeeQueries.class);
19 |
20 | @Autowired
21 | EmployeeRepository repository;
22 |
23 | public List employees() {
24 | LOGGER.info("Employees find");
25 | return repository.findAll();
26 | }
27 |
28 | public List employeesByOrganization(Long organizationId) {
29 | LOGGER.info("Employees find: organizationId={}", organizationId);
30 | return repository.findByOrganization(organizationId);
31 | }
32 |
33 | public List employeesByDepartment(Long departmentId) {
34 | LOGGER.info("Employees find: departmentId={}", departmentId);
35 | return repository.findByDepartment(departmentId);
36 | }
37 |
38 | public Employee employee(Long id) {
39 | LOGGER.info("Employee find: id={}", id);
40 | return repository.findById(id);
41 | }
42 |
43 | }
44 |
--------------------------------------------------------------------------------
/employee-service/src/main/resources/bootstrap.yml:
--------------------------------------------------------------------------------
1 | spring:
2 | application:
3 | name: employee-service
4 |
5 | server:
6 | port: 8090
7 |
8 | eureka:
9 | client:
10 | serviceUrl:
11 | defaultZone: http://localhost:8061/eureka/
12 |
13 | logging:
14 | pattern:
15 | console: "%d{yyyy-MM-dd HH:mm:ss} ${LOG_LEVEL_PATTERN:-%5p} %m%n"
--------------------------------------------------------------------------------
/employee-service/src/main/resources/graphql/employee.graphqls:
--------------------------------------------------------------------------------
1 | schema {
2 | query: EmployeeQueries
3 | mutation: EmployeeMutations
4 | }
5 |
6 | type EmployeeQueries {
7 | employees: [Employee]
8 | employee(id: ID!): Employee!
9 | employeesByOrganization(organizationId: Int!): [Employee]
10 | employeesByDepartment(departmentId: Int!): [Employee]
11 | }
12 |
13 | type EmployeeMutations {
14 | newEmployee(employee: EmployeeInput!): Employee
15 | deleteEmployee(id: ID!) : Boolean
16 | updateEmployee(id: ID!, employee: EmployeeInput!): Employee
17 | }
18 |
19 | input EmployeeInput {
20 | organizationId: Int!
21 | departmentId: Int!
22 | name: String!
23 | age: Int!
24 | position: String!
25 | salary: Int!
26 | }
27 |
28 | type Employee {
29 | id: ID!
30 | organizationId: Int!
31 | departmentId: Int!
32 | name: String!
33 | age: Int!
34 | position: String!
35 | salary: Int!
36 | }
--------------------------------------------------------------------------------
/employee-service/src/test/java/pl/piomin/services/employee/EmployeeApiTest.java:
--------------------------------------------------------------------------------
1 | package pl.piomin.services.employee;
2 |
3 | import com.apollographql.apollo.ApolloCall.Callback;
4 | import com.apollographql.apollo.ApolloClient;
5 | import com.apollographql.apollo.api.Response;
6 | import com.apollographql.apollo.exception.ApolloException;
7 | import org.junit.Test;
8 | import org.junit.runner.RunWith;
9 | import org.slf4j.Logger;
10 | import org.slf4j.LoggerFactory;
11 | import org.springframework.boot.test.context.SpringBootTest;
12 | import org.springframework.boot.web.server.LocalServerPort;
13 | import org.springframework.test.context.junit4.SpringRunner;
14 | import pl.piomin.services.employee.model.EmployeesQuery;
15 | import pl.piomin.services.employee.model.EmployeesQuery.Data;
16 |
17 | import java.util.concurrent.CountDownLatch;
18 | import java.util.concurrent.TimeUnit;
19 |
20 | @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
21 | @RunWith(SpringRunner.class)
22 | public class EmployeeApiTest {
23 |
24 | @LocalServerPort
25 | int port;
26 |
27 | private static final Logger LOGGER = LoggerFactory.getLogger(EmployeeApiTest.class);
28 |
29 | private CountDownLatch lock = new CountDownLatch(1);
30 |
31 | @Test
32 | public void testClient() throws InterruptedException {
33 | ApolloClient client = ApolloClient.builder().serverUrl("http://localhost:" + port + "/graphql").build();
34 | client.query(EmployeesQuery.builder().build()).enqueue(new Callback() {
35 |
36 | @Override
37 | public void onFailure(ApolloException arg0) {
38 | LOGGER.error("Error", arg0);
39 | lock.countDown();
40 | }
41 |
42 | @Override
43 | public void onResponse(Response res) {
44 | LOGGER.info("Res: {}", res.data().employees());
45 | lock.countDown();
46 | }
47 | });
48 | lock.await(10000, TimeUnit.MILLISECONDS);
49 | }
50 |
51 | }
52 |
--------------------------------------------------------------------------------
/organization-service/.gitignore:
--------------------------------------------------------------------------------
1 | /target/
2 | /.classpath
3 | /.project
4 | /.settings/
5 | /build/
6 |
--------------------------------------------------------------------------------
/organization-service/pom.xml:
--------------------------------------------------------------------------------
1 |
2 | 4.0.0
3 |
4 | pl.piomin.services
5 | sample-graphql-microservices
6 | 1.0-SNAPSHOT
7 |
8 | organization-service
9 | 1.0-SNAPSHOT
10 |
11 |
12 | ${project.artifactId}
13 |
14 |
15 |
16 |
17 | org.springframework.cloud
18 | spring-cloud-starter-netflix-eureka-client
19 |
20 |
21 | org.springframework.cloud
22 | spring-cloud-starter-config
23 |
24 |
25 | org.springframework.cloud
26 | spring-cloud-starter-openfeign
27 |
28 |
29 | org.springframework.cloud
30 | spring-cloud-openfeign-core
31 |
32 |
33 | org.springframework.boot
34 | spring-boot-starter-web
35 |
36 |
37 | org.springframework.boot
38 | spring-boot-starter-actuator
39 |
40 |
41 | com.graphql-java
42 | graphql-spring-boot-starter
43 | 5.0.2
44 |
45 |
46 | com.graphql-java
47 | graphiql-spring-boot-starter
48 | 5.0.2
49 |
50 |
51 | com.graphql-java
52 | voyager-spring-boot-starter
53 | 5.0.2
54 |
55 |
56 | com.graphql-java
57 | graphql-java
58 | 9.2
59 |
60 |
61 | com.graphql-java
62 | graphql-java-tools
63 | 5.2.3
64 |
65 |
66 | org.springframework.cloud
67 | spring-cloud-starter-sleuth
68 |
69 |
70 | com.apollographql.apollo
71 | apollo-runtime
72 | 1.0.1
73 |
74 |
75 |
76 |
77 |
78 |
79 | org.springframework.boot
80 | spring-boot-maven-plugin
81 |
82 |
83 |
84 |
85 |
--------------------------------------------------------------------------------
/organization-service/src/main/java/META-INF/MANIFEST.MF:
--------------------------------------------------------------------------------
1 | Manifest-Version: 1.0
2 | Class-Path:
3 |
4 |
--------------------------------------------------------------------------------
/organization-service/src/main/java/pl/piomin/services/organization/OrganizationApplication.java:
--------------------------------------------------------------------------------
1 | package pl.piomin.services.organization;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 | import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
6 | import org.springframework.cloud.openfeign.EnableFeignClients;
7 | import org.springframework.context.annotation.Bean;
8 |
9 | import pl.piomin.services.organization.model.Organization;
10 | import pl.piomin.services.organization.repository.OrganizationRepository;
11 |
12 | @SpringBootApplication
13 | @EnableDiscoveryClient
14 | @EnableFeignClients
15 | public class OrganizationApplication {
16 |
17 | public static void main(String[] args) {
18 | SpringApplication.run(OrganizationApplication.class, args);
19 | }
20 |
21 | @Bean
22 | OrganizationRepository repository() {
23 | OrganizationRepository repository = new OrganizationRepository();
24 | repository.add(new Organization("Microsoft", "Redmond, Washington, USA"));
25 | repository.add(new Organization("Oracle", "Redwood City, California, USA"));
26 | return repository;
27 | }
28 |
29 | }
30 |
--------------------------------------------------------------------------------
/organization-service/src/main/java/pl/piomin/services/organization/client/DepartmentClient.java:
--------------------------------------------------------------------------------
1 | package pl.piomin.services.organization.client;
2 |
3 | import java.util.List;
4 |
5 | import org.springframework.cloud.openfeign.FeignClient;
6 | import org.springframework.web.bind.annotation.GetMapping;
7 | import org.springframework.web.bind.annotation.PathVariable;
8 |
9 | import pl.piomin.services.organization.model.Department;
10 |
11 | @FeignClient(name = "department-service")
12 | public interface DepartmentClient {
13 |
14 | @GetMapping("/organization/{organizationId}")
15 | public List findByOrganization(@PathVariable("organizationId") Long organizationId);
16 |
17 | @GetMapping("/organization/{organizationId}/with-employees")
18 | public List findByOrganizationWithEmployees(@PathVariable("organizationId") Long organizationId);
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/organization-service/src/main/java/pl/piomin/services/organization/client/EmployeeClient.java:
--------------------------------------------------------------------------------
1 | package pl.piomin.services.organization.client;
2 |
3 | import java.util.ArrayList;
4 | import java.util.List;
5 | import java.util.Random;
6 | import java.util.concurrent.CountDownLatch;
7 | import java.util.concurrent.TimeUnit;
8 | import java.util.stream.Collectors;
9 |
10 | import org.slf4j.Logger;
11 | import org.slf4j.LoggerFactory;
12 | import org.springframework.beans.factory.annotation.Autowired;
13 | import org.springframework.stereotype.Component;
14 |
15 | import com.apollographql.apollo.ApolloCall.Callback;
16 | import com.apollographql.apollo.ApolloClient;
17 | import com.apollographql.apollo.api.Response;
18 | import com.apollographql.apollo.exception.ApolloException;
19 | import com.netflix.appinfo.InstanceInfo;
20 | import com.netflix.discovery.EurekaClient;
21 | import com.netflix.discovery.shared.Application;
22 |
23 | import pl.piomin.services.organization.model.Employee;
24 |
25 | @Component
26 | public class EmployeeClient {
27 |
28 | private static final Logger LOGGER = LoggerFactory.getLogger(EmployeeClient.class);
29 | private static final int TIMEOUT = 5000;
30 | private static final String SERVICE_NAME = "EMPLOYEE-SERVICE";
31 | private static final String SERVER_URL = "http://localhost:%d/graphql";
32 |
33 | Random r = new Random();
34 |
35 | @Autowired
36 | private EurekaClient discoveryClient;
37 |
38 | public List findByDepartment(Long departmentId) throws InterruptedException {
39 | List employees = new ArrayList<>();
40 | Application app = discoveryClient.getApplication(SERVICE_NAME);
41 | InstanceInfo ii = app.getInstances().get(r.nextInt(app.size()));
42 | ApolloClient client = ApolloClient.builder().serverUrl(String.format(SERVER_URL, ii.getPort())).build();
43 | CountDownLatch lock = new CountDownLatch(1);
44 | client.query(EmployeesByDepartmentQuery.builder().departmentId(departmentId.intValue()).build()).enqueue(new Callback() {
45 |
46 | @Override
47 | public void onFailure(ApolloException ex) {
48 | LOGGER.info("Err: {}", ex);
49 | lock.countDown();
50 | }
51 |
52 | @Override
53 | public void onResponse(Response res) {
54 | LOGGER.info("Res: {}", res);
55 | employees.addAll(res.data().employeesByDepartment().stream().map(emp -> new Employee(Long.valueOf(emp.id()), emp.name(), null)).collect(Collectors.toList()));
56 | lock.countDown();
57 | }
58 |
59 | });
60 | lock.await(TIMEOUT, TimeUnit.MILLISECONDS);
61 | return employees;
62 | }
63 |
64 | public List findByOrganization(Long organizationId) throws InterruptedException {
65 | List employees = new ArrayList<>();
66 | Application app = discoveryClient.getApplication(SERVICE_NAME);
67 | InstanceInfo ii = app.getInstances().get(r.nextInt(app.size()));
68 | ApolloClient client = ApolloClient.builder().serverUrl(String.format(SERVER_URL, ii.getPort())).build();
69 | CountDownLatch lock = new CountDownLatch(1);
70 | client.query(EmployeesByOrganizationQuery.builder().organizationId(organizationId.intValue()).build()).enqueue(new Callback() {
71 |
72 | @Override
73 | public void onFailure(ApolloException ex) {
74 | LOGGER.info("Err: {}", ex);
75 | lock.countDown();
76 | }
77 |
78 | @Override
79 | public void onResponse(Response res) {
80 | LOGGER.info("Res: {}", res);
81 | employees.addAll(res.data().employeesByOrganization().stream().map(emp -> new Employee(Long.valueOf(emp.id()), emp.name(), null)).collect(Collectors.toList()));
82 | lock.countDown();
83 | }
84 |
85 | });
86 | lock.await(TIMEOUT, TimeUnit.MILLISECONDS);
87 | return employees;
88 | }
89 |
90 | }
91 |
--------------------------------------------------------------------------------
/organization-service/src/main/java/pl/piomin/services/organization/client/EmployeesByDepartmentQuery.java:
--------------------------------------------------------------------------------
1 | package pl.piomin.services.organization.client;
2 |
3 | import com.apollographql.apollo.api.InputFieldMarshaller;
4 | import com.apollographql.apollo.api.InputFieldWriter;
5 | import com.apollographql.apollo.api.Operation;
6 | import com.apollographql.apollo.api.OperationName;
7 | import com.apollographql.apollo.api.Query;
8 | import com.apollographql.apollo.api.ResponseField;
9 | import com.apollographql.apollo.api.ResponseFieldMapper;
10 | import com.apollographql.apollo.api.ResponseFieldMarshaller;
11 | import com.apollographql.apollo.api.ResponseReader;
12 | import com.apollographql.apollo.api.ResponseWriter;
13 | import com.apollographql.apollo.api.internal.UnmodifiableMapBuilder;
14 | import com.apollographql.apollo.api.internal.Utils;
15 | import java.io.IOException;
16 | import java.lang.Object;
17 | import java.lang.Override;
18 | import java.lang.String;
19 | import java.util.Collections;
20 | import java.util.LinkedHashMap;
21 | import java.util.List;
22 | import java.util.Map;
23 | import javax.annotation.Generated;
24 | import org.jetbrains.annotations.NotNull;
25 | import org.jetbrains.annotations.Nullable;
26 | import type.CustomType;
27 |
28 | @Generated("Apollo GraphQL")
29 | public final class EmployeesByDepartmentQuery implements Query {
30 | public static final String OPERATION_DEFINITION = "query EmployeesByDepartment($departmentId: Int!) {\n"
31 | + " employeesByDepartment(departmentId: $departmentId) {\n"
32 | + " __typename\n"
33 | + " id\n"
34 | + " name\n"
35 | + " }\n"
36 | + "}";
37 |
38 | public static final String OPERATION_ID = "aed2f7d05a2e1d2b5dc61fb2a9678bd08132b0cef2cc769c6d3c34e090f00da0";
39 |
40 | public static final String QUERY_DOCUMENT = OPERATION_DEFINITION;
41 |
42 | public static final OperationName OPERATION_NAME = new OperationName() {
43 | @Override
44 | public String name() {
45 | return "EmployeesByDepartment";
46 | }
47 | };
48 |
49 | private final EmployeesByDepartmentQuery.Variables variables;
50 |
51 | public EmployeesByDepartmentQuery(int departmentId) {
52 | variables = new EmployeesByDepartmentQuery.Variables(departmentId);
53 | }
54 |
55 | @Override
56 | public String operationId() {
57 | return OPERATION_ID;
58 | }
59 |
60 | @Override
61 | public String queryDocument() {
62 | return QUERY_DOCUMENT;
63 | }
64 |
65 | @Override
66 | public EmployeesByDepartmentQuery.Data wrapData(EmployeesByDepartmentQuery.Data data) {
67 | return data;
68 | }
69 |
70 | @Override
71 | public EmployeesByDepartmentQuery.Variables variables() {
72 | return variables;
73 | }
74 |
75 | @Override
76 | public ResponseFieldMapper responseFieldMapper() {
77 | return new Data.Mapper();
78 | }
79 |
80 | public static Builder builder() {
81 | return new Builder();
82 | }
83 |
84 | @Override
85 | public OperationName name() {
86 | return OPERATION_NAME;
87 | }
88 |
89 | public static final class Builder {
90 | private int departmentId;
91 |
92 | Builder() {
93 | }
94 |
95 | public Builder departmentId(int departmentId) {
96 | this.departmentId = departmentId;
97 | return this;
98 | }
99 |
100 | public EmployeesByDepartmentQuery build() {
101 | return new EmployeesByDepartmentQuery(departmentId);
102 | }
103 | }
104 |
105 | public static final class Variables extends Operation.Variables {
106 | private final int departmentId;
107 |
108 | private final transient Map valueMap = new LinkedHashMap<>();
109 |
110 | Variables(int departmentId) {
111 | this.departmentId = departmentId;
112 | this.valueMap.put("departmentId", departmentId);
113 | }
114 |
115 | public int departmentId() {
116 | return departmentId;
117 | }
118 |
119 | @Override
120 | public Map valueMap() {
121 | return Collections.unmodifiableMap(valueMap);
122 | }
123 |
124 | @Override
125 | public InputFieldMarshaller marshaller() {
126 | return new InputFieldMarshaller() {
127 | @Override
128 | public void marshal(InputFieldWriter writer) throws IOException {
129 | writer.writeInt("departmentId", departmentId);
130 | }
131 | };
132 | }
133 | }
134 |
135 | public static class Data implements Operation.Data {
136 | static final ResponseField[] $responseFields = {
137 | ResponseField.forList("employeesByDepartment", "employeesByDepartment", new UnmodifiableMapBuilder(1)
138 | .put("departmentId", new UnmodifiableMapBuilder(2)
139 | .put("kind", "Variable")
140 | .put("variableName", "departmentId")
141 | .build())
142 | .build(), true, Collections.emptyList())
143 | };
144 |
145 | final @Nullable List employeesByDepartment;
146 |
147 | private volatile String $toString;
148 |
149 | private volatile int $hashCode;
150 |
151 | private volatile boolean $hashCodeMemoized;
152 |
153 | public Data(@Nullable List employeesByDepartment) {
154 | this.employeesByDepartment = employeesByDepartment;
155 | }
156 |
157 | public @Nullable List employeesByDepartment() {
158 | return this.employeesByDepartment;
159 | }
160 |
161 | public ResponseFieldMarshaller marshaller() {
162 | return new ResponseFieldMarshaller() {
163 | @Override
164 | public void marshal(ResponseWriter writer) {
165 | writer.writeList($responseFields[0], employeesByDepartment, new ResponseWriter.ListWriter() {
166 | @Override
167 | public void write(@Nullable List list, @NotNull ResponseWriter.ListItemWriter listItemWriter) {
168 | listItemWriter.writeList(list, this);
169 | }
170 |
171 | // @Override
172 | // public void write(Object value, ResponseWriter.ListItemWriter listItemWriter) {
173 | // listItemWriter.writeObject(((EmployeesByDepartment) value).marshaller());
174 | // }
175 | });
176 | }
177 | };
178 | }
179 |
180 | @Override
181 | public String toString() {
182 | if ($toString == null) {
183 | $toString = "Data{"
184 | + "employeesByDepartment=" + employeesByDepartment
185 | + "}";
186 | }
187 | return $toString;
188 | }
189 |
190 | @Override
191 | public boolean equals(Object o) {
192 | if (o == this) {
193 | return true;
194 | }
195 | if (o instanceof Data) {
196 | Data that = (Data) o;
197 | return ((this.employeesByDepartment == null) ? (that.employeesByDepartment == null) : this.employeesByDepartment.equals(that.employeesByDepartment));
198 | }
199 | return false;
200 | }
201 |
202 | @Override
203 | public int hashCode() {
204 | if (!$hashCodeMemoized) {
205 | int h = 1;
206 | h *= 1000003;
207 | h ^= (employeesByDepartment == null) ? 0 : employeesByDepartment.hashCode();
208 | $hashCode = h;
209 | $hashCodeMemoized = true;
210 | }
211 | return $hashCode;
212 | }
213 |
214 | public static final class Mapper implements ResponseFieldMapper {
215 | final EmployeesByDepartment.Mapper employeesByDepartmentFieldMapper = new EmployeesByDepartment.Mapper();
216 |
217 | @Override
218 | public Data map(ResponseReader reader) {
219 | final List employeesByDepartment = reader.readList($responseFields[0], new ResponseReader.ListReader() {
220 | @Override
221 | public EmployeesByDepartment read(ResponseReader.ListItemReader listItemReader) {
222 | return listItemReader.readObject(new ResponseReader.ObjectReader() {
223 | @Override
224 | public EmployeesByDepartment read(ResponseReader reader) {
225 | return employeesByDepartmentFieldMapper.map(reader);
226 | }
227 | });
228 | }
229 | });
230 | return new Data(employeesByDepartment);
231 | }
232 | }
233 | }
234 |
235 | public static class EmployeesByDepartment {
236 | static final ResponseField[] $responseFields = {
237 | ResponseField.forString("__typename", "__typename", null, false, Collections.emptyList()),
238 | ResponseField.forCustomType("id", "id", null, false, CustomType.ID, Collections.emptyList()),
239 | ResponseField.forString("name", "name", null, false, Collections.emptyList())
240 | };
241 |
242 | final @NotNull String __typename;
243 |
244 | final @NotNull String id;
245 |
246 | final @NotNull String name;
247 |
248 | private volatile String $toString;
249 |
250 | private volatile int $hashCode;
251 |
252 | private volatile boolean $hashCodeMemoized;
253 |
254 | public EmployeesByDepartment(@NotNull String __typename, @NotNull String id,
255 | @NotNull String name) {
256 | this.__typename = Utils.checkNotNull(__typename, "__typename == null");
257 | this.id = Utils.checkNotNull(id, "id == null");
258 | this.name = Utils.checkNotNull(name, "name == null");
259 | }
260 |
261 | public @NotNull String __typename() {
262 | return this.__typename;
263 | }
264 |
265 | public @NotNull String id() {
266 | return this.id;
267 | }
268 |
269 | public @NotNull String name() {
270 | return this.name;
271 | }
272 |
273 | public ResponseFieldMarshaller marshaller() {
274 | return new ResponseFieldMarshaller() {
275 | @Override
276 | public void marshal(ResponseWriter writer) {
277 | writer.writeString($responseFields[0], __typename);
278 | writer.writeCustom((ResponseField.CustomTypeField) $responseFields[1], id);
279 | writer.writeString($responseFields[2], name);
280 | }
281 | };
282 | }
283 |
284 | @Override
285 | public String toString() {
286 | if ($toString == null) {
287 | $toString = "EmployeesByDepartment{"
288 | + "__typename=" + __typename + ", "
289 | + "id=" + id + ", "
290 | + "name=" + name
291 | + "}";
292 | }
293 | return $toString;
294 | }
295 |
296 | @Override
297 | public boolean equals(Object o) {
298 | if (o == this) {
299 | return true;
300 | }
301 | if (o instanceof EmployeesByDepartment) {
302 | EmployeesByDepartment that = (EmployeesByDepartment) o;
303 | return this.__typename.equals(that.__typename)
304 | && this.id.equals(that.id)
305 | && this.name.equals(that.name);
306 | }
307 | return false;
308 | }
309 |
310 | @Override
311 | public int hashCode() {
312 | if (!$hashCodeMemoized) {
313 | int h = 1;
314 | h *= 1000003;
315 | h ^= __typename.hashCode();
316 | h *= 1000003;
317 | h ^= id.hashCode();
318 | h *= 1000003;
319 | h ^= name.hashCode();
320 | $hashCode = h;
321 | $hashCodeMemoized = true;
322 | }
323 | return $hashCode;
324 | }
325 |
326 | public static final class Mapper implements ResponseFieldMapper {
327 | @Override
328 | public EmployeesByDepartment map(ResponseReader reader) {
329 | final String __typename = reader.readString($responseFields[0]);
330 | final String id = reader.readCustomType((ResponseField.CustomTypeField) $responseFields[1]);
331 | final String name = reader.readString($responseFields[2]);
332 | return new EmployeesByDepartment(__typename, id, name);
333 | }
334 | }
335 | }
336 | }
337 |
--------------------------------------------------------------------------------
/organization-service/src/main/java/pl/piomin/services/organization/client/EmployeesByOrganizationQuery.java:
--------------------------------------------------------------------------------
1 | package pl.piomin.services.organization.client;
2 |
3 | import com.apollographql.apollo.api.InputFieldMarshaller;
4 | import com.apollographql.apollo.api.InputFieldWriter;
5 | import com.apollographql.apollo.api.Operation;
6 | import com.apollographql.apollo.api.OperationName;
7 | import com.apollographql.apollo.api.Query;
8 | import com.apollographql.apollo.api.ResponseField;
9 | import com.apollographql.apollo.api.ResponseFieldMapper;
10 | import com.apollographql.apollo.api.ResponseFieldMarshaller;
11 | import com.apollographql.apollo.api.ResponseReader;
12 | import com.apollographql.apollo.api.ResponseWriter;
13 | import com.apollographql.apollo.api.internal.UnmodifiableMapBuilder;
14 | import com.apollographql.apollo.api.internal.Utils;
15 | import java.io.IOException;
16 | import java.lang.Object;
17 | import java.lang.Override;
18 | import java.lang.String;
19 | import java.util.Collections;
20 | import java.util.LinkedHashMap;
21 | import java.util.List;
22 | import java.util.Map;
23 | import javax.annotation.Generated;
24 | import org.jetbrains.annotations.NotNull;
25 | import org.jetbrains.annotations.Nullable;
26 | import type.CustomType;
27 |
28 | @Generated("Apollo GraphQL")
29 | public final class EmployeesByOrganizationQuery implements Query {
30 | public static final String OPERATION_DEFINITION = "query EmployeesByOrganization($organizationId: Int!) {\n"
31 | + " employeesByOrganization(organizationId: $organizationId) {\n"
32 | + " __typename\n"
33 | + " id\n"
34 | + " name\n"
35 | + " }\n"
36 | + "}";
37 |
38 | public static final String OPERATION_ID = "e22dfe6efe53b9e0faa27de63eda414ee6fa8fa9a8d0cc4269ef7bce117705a9";
39 |
40 | public static final String QUERY_DOCUMENT = OPERATION_DEFINITION;
41 |
42 | public static final OperationName OPERATION_NAME = new OperationName() {
43 | @Override
44 | public String name() {
45 | return "EmployeesByOrganization";
46 | }
47 | };
48 |
49 | private final EmployeesByOrganizationQuery.Variables variables;
50 |
51 | public EmployeesByOrganizationQuery(int organizationId) {
52 | variables = new EmployeesByOrganizationQuery.Variables(organizationId);
53 | }
54 |
55 | @Override
56 | public String operationId() {
57 | return OPERATION_ID;
58 | }
59 |
60 | @Override
61 | public String queryDocument() {
62 | return QUERY_DOCUMENT;
63 | }
64 |
65 | @Override
66 | public EmployeesByOrganizationQuery.Data wrapData(EmployeesByOrganizationQuery.Data data) {
67 | return data;
68 | }
69 |
70 | @Override
71 | public EmployeesByOrganizationQuery.Variables variables() {
72 | return variables;
73 | }
74 |
75 | @Override
76 | public ResponseFieldMapper responseFieldMapper() {
77 | return new Data.Mapper();
78 | }
79 |
80 | public static Builder builder() {
81 | return new Builder();
82 | }
83 |
84 | @Override
85 | public OperationName name() {
86 | return OPERATION_NAME;
87 | }
88 |
89 | public static final class Builder {
90 | private int organizationId;
91 |
92 | Builder() {
93 | }
94 |
95 | public Builder organizationId(int organizationId) {
96 | this.organizationId = organizationId;
97 | return this;
98 | }
99 |
100 | public EmployeesByOrganizationQuery build() {
101 | return new EmployeesByOrganizationQuery(organizationId);
102 | }
103 | }
104 |
105 | public static final class Variables extends Operation.Variables {
106 | private final int organizationId;
107 |
108 | private final transient Map valueMap = new LinkedHashMap<>();
109 |
110 | Variables(int organizationId) {
111 | this.organizationId = organizationId;
112 | this.valueMap.put("organizationId", organizationId);
113 | }
114 |
115 | public int organizationId() {
116 | return organizationId;
117 | }
118 |
119 | @Override
120 | public Map valueMap() {
121 | return Collections.unmodifiableMap(valueMap);
122 | }
123 |
124 | @Override
125 | public InputFieldMarshaller marshaller() {
126 | return new InputFieldMarshaller() {
127 | @Override
128 | public void marshal(InputFieldWriter writer) throws IOException {
129 | writer.writeInt("organizationId", organizationId);
130 | }
131 | };
132 | }
133 | }
134 |
135 | public static class Data implements Operation.Data {
136 | static final ResponseField[] $responseFields = {
137 | ResponseField.forList("employeesByOrganization", "employeesByOrganization", new UnmodifiableMapBuilder(1)
138 | .put("organizationId", new UnmodifiableMapBuilder(2)
139 | .put("kind", "Variable")
140 | .put("variableName", "organizationId")
141 | .build())
142 | .build(), true, Collections.emptyList())
143 | };
144 |
145 | final @Nullable List employeesByOrganization;
146 |
147 | private volatile String $toString;
148 |
149 | private volatile int $hashCode;
150 |
151 | private volatile boolean $hashCodeMemoized;
152 |
153 | public Data(@Nullable List employeesByOrganization) {
154 | this.employeesByOrganization = employeesByOrganization;
155 | }
156 |
157 | public @Nullable List employeesByOrganization() {
158 | return this.employeesByOrganization;
159 | }
160 |
161 | public ResponseFieldMarshaller marshaller() {
162 | return new ResponseFieldMarshaller() {
163 | @Override
164 | public void marshal(ResponseWriter writer) {
165 | writer.writeList($responseFields[0], employeesByOrganization, new ResponseWriter.ListWriter() {
166 | @Override
167 | public void write(@Nullable List list, @NotNull ResponseWriter.ListItemWriter listItemWriter) {
168 | listItemWriter.writeList(list, this);
169 | }
170 |
171 | // @Override
172 | // public void write(Object value, ResponseWriter.ListItemWriter listItemWriter) {
173 | // listItemWriter.writeObject(((EmployeesByOrganization) value).marshaller());
174 | // }
175 | });
176 | }
177 | };
178 | }
179 |
180 | @Override
181 | public String toString() {
182 | if ($toString == null) {
183 | $toString = "Data{"
184 | + "employeesByOrganization=" + employeesByOrganization
185 | + "}";
186 | }
187 | return $toString;
188 | }
189 |
190 | @Override
191 | public boolean equals(Object o) {
192 | if (o == this) {
193 | return true;
194 | }
195 | if (o instanceof Data) {
196 | Data that = (Data) o;
197 | return ((this.employeesByOrganization == null) ? (that.employeesByOrganization == null) : this.employeesByOrganization.equals(that.employeesByOrganization));
198 | }
199 | return false;
200 | }
201 |
202 | @Override
203 | public int hashCode() {
204 | if (!$hashCodeMemoized) {
205 | int h = 1;
206 | h *= 1000003;
207 | h ^= (employeesByOrganization == null) ? 0 : employeesByOrganization.hashCode();
208 | $hashCode = h;
209 | $hashCodeMemoized = true;
210 | }
211 | return $hashCode;
212 | }
213 |
214 | public static final class Mapper implements ResponseFieldMapper {
215 | final EmployeesByOrganization.Mapper employeesByOrganizationFieldMapper = new EmployeesByOrganization.Mapper();
216 |
217 | @Override
218 | public Data map(ResponseReader reader) {
219 | final List employeesByOrganization = reader.readList($responseFields[0], new ResponseReader.ListReader() {
220 | @Override
221 | public EmployeesByOrganization read(ResponseReader.ListItemReader listItemReader) {
222 | return listItemReader.readObject(new ResponseReader.ObjectReader() {
223 | @Override
224 | public EmployeesByOrganization read(ResponseReader reader) {
225 | return employeesByOrganizationFieldMapper.map(reader);
226 | }
227 | });
228 | }
229 | });
230 | return new Data(employeesByOrganization);
231 | }
232 | }
233 | }
234 |
235 | public static class EmployeesByOrganization {
236 | static final ResponseField[] $responseFields = {
237 | ResponseField.forString("__typename", "__typename", null, false, Collections.emptyList()),
238 | ResponseField.forCustomType("id", "id", null, false, CustomType.ID, Collections.emptyList()),
239 | ResponseField.forString("name", "name", null, false, Collections.emptyList())
240 | };
241 |
242 | final @NotNull String __typename;
243 |
244 | final @NotNull String id;
245 |
246 | final @NotNull String name;
247 |
248 | private volatile String $toString;
249 |
250 | private volatile int $hashCode;
251 |
252 | private volatile boolean $hashCodeMemoized;
253 |
254 | public EmployeesByOrganization(@NotNull String __typename, @NotNull String id,
255 | @NotNull String name) {
256 | this.__typename = Utils.checkNotNull(__typename, "__typename == null");
257 | this.id = Utils.checkNotNull(id, "id == null");
258 | this.name = Utils.checkNotNull(name, "name == null");
259 | }
260 |
261 | public @NotNull String __typename() {
262 | return this.__typename;
263 | }
264 |
265 | public @NotNull String id() {
266 | return this.id;
267 | }
268 |
269 | public @NotNull String name() {
270 | return this.name;
271 | }
272 |
273 | public ResponseFieldMarshaller marshaller() {
274 | return new ResponseFieldMarshaller() {
275 | @Override
276 | public void marshal(ResponseWriter writer) {
277 | writer.writeString($responseFields[0], __typename);
278 | writer.writeCustom((ResponseField.CustomTypeField) $responseFields[1], id);
279 | writer.writeString($responseFields[2], name);
280 | }
281 | };
282 | }
283 |
284 | @Override
285 | public String toString() {
286 | if ($toString == null) {
287 | $toString = "EmployeesByOrganization{"
288 | + "__typename=" + __typename + ", "
289 | + "id=" + id + ", "
290 | + "name=" + name
291 | + "}";
292 | }
293 | return $toString;
294 | }
295 |
296 | @Override
297 | public boolean equals(Object o) {
298 | if (o == this) {
299 | return true;
300 | }
301 | if (o instanceof EmployeesByOrganization) {
302 | EmployeesByOrganization that = (EmployeesByOrganization) o;
303 | return this.__typename.equals(that.__typename)
304 | && this.id.equals(that.id)
305 | && this.name.equals(that.name);
306 | }
307 | return false;
308 | }
309 |
310 | @Override
311 | public int hashCode() {
312 | if (!$hashCodeMemoized) {
313 | int h = 1;
314 | h *= 1000003;
315 | h ^= __typename.hashCode();
316 | h *= 1000003;
317 | h ^= id.hashCode();
318 | h *= 1000003;
319 | h ^= name.hashCode();
320 | $hashCode = h;
321 | $hashCodeMemoized = true;
322 | }
323 | return $hashCode;
324 | }
325 |
326 | public static final class Mapper implements ResponseFieldMapper {
327 | @Override
328 | public EmployeesByOrganization map(ResponseReader reader) {
329 | final String __typename = reader.readString($responseFields[0]);
330 | final String id = reader.readCustomType((ResponseField.CustomTypeField) $responseFields[1]);
331 | final String name = reader.readString($responseFields[2]);
332 | return new EmployeesByOrganization(__typename, id, name);
333 | }
334 | }
335 | }
336 | }
337 |
--------------------------------------------------------------------------------
/organization-service/src/main/java/pl/piomin/services/organization/model/Department.java:
--------------------------------------------------------------------------------
1 | package pl.piomin.services.organization.model;
2 |
3 | import java.util.ArrayList;
4 | import java.util.List;
5 |
6 | public class Department {
7 |
8 | private Long id;
9 | private String name;
10 | private List employees = new ArrayList<>();
11 |
12 | public Department() {
13 |
14 | }
15 |
16 | public Department(String name) {
17 | super();
18 | this.name = name;
19 | }
20 |
21 | public Long getId() {
22 | return id;
23 | }
24 |
25 | public void setId(Long id) {
26 | this.id = id;
27 | }
28 |
29 | public String getName() {
30 | return name;
31 | }
32 |
33 | public void setName(String name) {
34 | this.name = name;
35 | }
36 |
37 | public List getEmployees() {
38 | return employees;
39 | }
40 |
41 | public void setEmployees(List employees) {
42 | this.employees = employees;
43 | }
44 |
45 | @Override
46 | public String toString() {
47 | return "Department [id=" + id + ", name=" + name + "]";
48 | }
49 |
50 | }
51 |
--------------------------------------------------------------------------------
/organization-service/src/main/java/pl/piomin/services/organization/model/Employee.java:
--------------------------------------------------------------------------------
1 | package pl.piomin.services.organization.model;
2 |
3 | public class Employee {
4 |
5 | private Long id;
6 | private String name;
7 | private Long departmentId;
8 |
9 | public Employee() {
10 |
11 | }
12 |
13 | public Employee(Long id, String name, Long departmentId) {
14 | super();
15 | this.id = id;
16 | this.name = name;
17 | this.departmentId = departmentId;
18 | }
19 |
20 | public Employee(String name, Long departmentId) {
21 | super();
22 | this.name = name;
23 | this.departmentId = departmentId;
24 | }
25 |
26 | public Long getId() {
27 | return id;
28 | }
29 |
30 | public void setId(Long id) {
31 | this.id = id;
32 | }
33 |
34 | public String getName() {
35 | return name;
36 | }
37 |
38 | public void setName(String name) {
39 | this.name = name;
40 | }
41 |
42 | public Long getDepartmentId() {
43 | return departmentId;
44 | }
45 |
46 | public void setDepartmentId(Long departmentId) {
47 | this.departmentId = departmentId;
48 | }
49 |
50 | @Override
51 | public String toString() {
52 | return "Employee [id=" + id + ", name=" + name + "]";
53 | }
54 |
55 | }
56 |
--------------------------------------------------------------------------------
/organization-service/src/main/java/pl/piomin/services/organization/model/Organization.java:
--------------------------------------------------------------------------------
1 | package pl.piomin.services.organization.model;
2 |
3 | import java.util.ArrayList;
4 | import java.util.List;
5 |
6 | public class Organization {
7 |
8 | private Long id;
9 | private String name;
10 | private String address;
11 | private List departments = new ArrayList<>();
12 | private List employees = new ArrayList<>();
13 |
14 | public Organization() {
15 |
16 | }
17 |
18 | public Organization(String name, String address) {
19 | this.name = name;
20 | this.address = address;
21 | }
22 |
23 | public Long getId() {
24 | return id;
25 | }
26 |
27 | public void setId(Long id) {
28 | this.id = id;
29 | }
30 |
31 | public String getName() {
32 | return name;
33 | }
34 |
35 | public void setName(String name) {
36 | this.name = name;
37 | }
38 |
39 | public String getAddress() {
40 | return address;
41 | }
42 |
43 | public void setAddress(String address) {
44 | this.address = address;
45 | }
46 |
47 | public List getDepartments() {
48 | return departments;
49 | }
50 |
51 | public void setDepartments(List departments) {
52 | this.departments = departments;
53 | }
54 |
55 | public List getEmployees() {
56 | return employees;
57 | }
58 |
59 | public void setEmployees(List employees) {
60 | this.employees = employees;
61 | }
62 |
63 | @Override
64 | public String toString() {
65 | return "Organization [id=" + id + ", name=" + name + ", address=" + address + "]";
66 | }
67 |
68 | }
69 |
--------------------------------------------------------------------------------
/organization-service/src/main/java/pl/piomin/services/organization/repository/OrganizationRepository.java:
--------------------------------------------------------------------------------
1 | package pl.piomin.services.organization.repository;
2 |
3 | import java.util.ArrayList;
4 | import java.util.List;
5 | import java.util.Optional;
6 |
7 | import pl.piomin.services.organization.model.Organization;
8 |
9 | public class OrganizationRepository {
10 |
11 | private List organizations = new ArrayList<>();
12 |
13 | public Organization add(Organization organization) {
14 | organization.setId((long) (organizations.size()+1));
15 | organizations.add(organization);
16 | return organization;
17 | }
18 |
19 | public Organization findById(Long id) {
20 | Optional organization = organizations.stream().filter(a -> a.getId().equals(id)).findFirst();
21 | if (organization.isPresent())
22 | return organization.get();
23 | else
24 | return null;
25 | }
26 |
27 | public List findAll() {
28 | return organizations;
29 | }
30 |
31 | public boolean delete(Long id) {
32 | return organizations.removeIf(it -> it.getId() == id.longValue());
33 | }
34 |
35 | public Organization update(Long id, Organization organization) {
36 | organization.setId(id);
37 | int index = organizations.indexOf(organization);
38 | organizations.set(index, organization);
39 | return organization;
40 | }
41 |
42 |
43 | }
44 |
--------------------------------------------------------------------------------
/organization-service/src/main/java/pl/piomin/services/organization/resolver/OrganizationMutations.java:
--------------------------------------------------------------------------------
1 | package pl.piomin.services.organization.resolver;
2 |
3 | import org.slf4j.Logger;
4 | import org.slf4j.LoggerFactory;
5 | import org.springframework.beans.factory.annotation.Autowired;
6 | import org.springframework.stereotype.Component;
7 |
8 | import com.coxautodev.graphql.tools.GraphQLMutationResolver;
9 |
10 | import pl.piomin.services.organization.model.Organization;
11 | import pl.piomin.services.organization.repository.OrganizationRepository;
12 |
13 |
14 | @Component
15 | public class OrganizationMutations implements GraphQLMutationResolver {
16 |
17 | private static final Logger LOGGER = LoggerFactory.getLogger(OrganizationMutations.class);
18 |
19 | @Autowired
20 | OrganizationRepository repository;
21 |
22 | public Organization newOrganization(Organization department) {
23 | LOGGER.info("Organization add: department={}", department);
24 | return repository.add(department);
25 | }
26 |
27 | public boolean deleteOrganization(Long id) {
28 | LOGGER.info("Organization delete: id={}", id);
29 | return repository.delete(id);
30 | }
31 |
32 | public Organization updateOrganization(Long id, Organization department) {
33 | LOGGER.info("Organization update: id={}, department={}", id, department);
34 | return repository.update(id, department);
35 | }
36 |
37 | }
38 |
--------------------------------------------------------------------------------
/organization-service/src/main/java/pl/piomin/services/organization/resolver/OrganizationQueries.java:
--------------------------------------------------------------------------------
1 | package pl.piomin.services.organization.resolver;
2 |
3 | import java.util.List;
4 |
5 | import org.slf4j.Logger;
6 | import org.slf4j.LoggerFactory;
7 | import org.springframework.beans.factory.annotation.Autowired;
8 | import org.springframework.stereotype.Component;
9 |
10 | import com.coxautodev.graphql.tools.GraphQLQueryResolver;
11 |
12 | import pl.piomin.services.organization.client.EmployeeClient;
13 | import pl.piomin.services.organization.model.Organization;
14 | import pl.piomin.services.organization.repository.OrganizationRepository;
15 |
16 | @Component
17 | public class OrganizationQueries implements GraphQLQueryResolver {
18 |
19 | private static final Logger LOGGER = LoggerFactory.getLogger(OrganizationQueries.class);
20 |
21 | @Autowired
22 | EmployeeClient employeeClient;
23 | @Autowired
24 | OrganizationRepository repository;
25 |
26 | public List organizations() {
27 | LOGGER.info("Organization find");
28 | return repository.findAll();
29 | }
30 |
31 | public Organization organizationByIdWithEmployees(Long id) throws InterruptedException {
32 | LOGGER.info("Organizations find: id={}", id);
33 | Organization organization = repository.findById(id);
34 | organization.setEmployees(employeeClient.findByOrganization(id));
35 | return organization;
36 | }
37 |
38 | public Organization organization(Long id) {
39 | LOGGER.info("Organization find: id={}", id);
40 | return repository.findById(id);
41 | }
42 |
43 | }
44 |
--------------------------------------------------------------------------------
/organization-service/src/main/java/type/CustomType.java:
--------------------------------------------------------------------------------
1 | package type;
2 |
3 | import com.apollographql.apollo.api.ScalarType;
4 | import java.lang.Class;
5 | import java.lang.Override;
6 | import java.lang.String;
7 | import javax.annotation.Generated;
8 |
9 | @Generated("Apollo GraphQL")
10 | public enum CustomType implements ScalarType {
11 | ID {
12 | @Override
13 | public String typeName() {
14 | return "ID";
15 | }
16 |
17 | @Override
18 | public Class javaType() {
19 | return String.class;
20 | }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/organization-service/src/main/resources/bootstrap.yml:
--------------------------------------------------------------------------------
1 | spring:
2 | application:
3 | name: organization-service
4 | cloud:
5 | config:
6 | uri: http://localhost:8088
--------------------------------------------------------------------------------
/organization-service/src/main/resources/graphql/organization.graphqls:
--------------------------------------------------------------------------------
1 | schema {
2 | query: OrganizationQueries
3 | mutation: OrganizationMutations
4 | }
5 |
6 | type OrganizationQueries {
7 | organizations: [Organization]
8 | organization(id: ID!): Organization!
9 | organizationByIdWithEmployees(id: Int!): Organization
10 | organizationByIdWithDepartments(id: Int!): Organization
11 | organizationByIdWithDepartmentsAndEmployees(id: Int!): Organization
12 | }
13 |
14 | type OrganizationMutations {
15 | newOrganization(organization: OrganizationInput!): Organization
16 | deleteOrganization(id: ID!) : Boolean
17 | updateOrganization(id: ID!, organization: OrganizationInput!): Organization
18 | }
19 |
20 | input OrganizationInput {
21 | organizationId: Int!
22 | name: String!
23 | }
24 |
25 | type Organization {
26 | id: ID!
27 | name: String!
28 | address: String!
29 | employees: [Employee]
30 | departments: [Department]
31 | }
32 |
33 | type Department {
34 | id: ID!
35 | name: String!
36 | employees: [Employee]
37 | }
38 |
39 | type Employee {
40 | id: ID!
41 | name: String!
42 | position: String!
43 | }
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
3 | 4.0.0
4 |
5 |
6 | org.springframework.boot
7 | spring-boot-starter-parent
8 | 2.0.0.RELEASE
9 |
10 |
11 |
12 | pl.piomin.services
13 | sample-graphql-microservices
14 | 1.0-SNAPSHOT
15 | pom
16 |
17 |
18 | 1.8
19 | piomin_sample-graphql-microservices
20 | piomin
21 | https://sonarcloud.io
22 |
23 |
24 |
25 | discovery-service
26 | employee-service
27 | department-service
28 | organization-service
29 |
30 |
31 |
32 |
33 |
34 | org.springframework.cloud
35 | spring-cloud-dependencies
36 | Finchley.SR1
37 | pom
38 | import
39 |
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 | ## GraphQL - The Future of Microservices? [](https://twitter.com/piotr_minkowski)
2 |
3 | Detailed description can be found here: [GraphQL - The Future of Microservices?](https://piotrminkowski.com/2018/08/16/graphql-the-future-of-microservices/)
4 |
--------------------------------------------------------------------------------
/renovate.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json",
3 | "extends": [
4 | "config:base",":dependencyDashboard"
5 | ],
6 | "packageRules": [
7 | {
8 | "matchUpdateTypes": ["minor", "patch", "pin", "digest"],
9 | "automerge": true
10 | }
11 | ],
12 | "prCreation": "not-pending"
13 | }
--------------------------------------------------------------------------------