forked from wildfly-extras/wildfly-graphql-feature-pack
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
new quickstart for smallrye graphql client
- Loading branch information
Showing
12 changed files
with
731 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,145 @@ | ||
# GraphQL Client quickstart | ||
|
||
## Prerequisites | ||
- JDK 11+ | ||
- Maven | ||
|
||
## Quickstart's compatibility with server-side quickstart | ||
This quickstart requires the server-side quickstart implementation to function properly. Instructions for deploying the feature pack on the server-side can be found in the server-side quickstart's [README](../quickstart/README.md). | ||
|
||
|
||
## Building and deployment | ||
|
||
The [main README](../README.md) contains information about the layers in this feature pack. You can use the `wildfly-maven-plugin` to build and run the server with the feature pack, and deploy the quickstart war. | ||
|
||
``` | ||
mvn wildfly:provision wildfly:dev | ||
``` | ||
|
||
|
||
## Functionality | ||
The quickstart-client.war application exposes various REST endpoints that demonstrate interacting with the server-side GraphQL API through the SmallRye GraphQL Client. | ||
The endpoints utilize both typesafe and dynamic client approaches. | ||
### Typesafe API | ||
|
||
The typesafe client functions like a MicroProfile REST Client but is tailored for GraphQL endpoints. To use it, you will need domain model classes that match the GraphQL schema. | ||
|
||
Think of a client instance as a proxy. You interact with it as you would a regular Java object, and it translates your calls into GraphQL operations. | ||
|
||
It directly handles domain classes, translating input and output data between Java objects and their representations in the GraphQL query language. | ||
#### Example | ||
|
||
Let's start by defining a domain class `Film` to represent the data we will be working with. | ||
```java | ||
package org.wildfly.extras.quickstart.microprofile.graphql.client; | ||
|
||
import java.time.LocalDate; | ||
|
||
public class Film { | ||
String title; | ||
Integer episodeID; | ||
String director; | ||
LocalDate releaseDate; | ||
String desc; | ||
} | ||
``` | ||
Next, create a GraphQL client API interface `FilmClientApi` to define the GraphQL operations: | ||
```java | ||
@GraphQLClientApi | ||
interface FilmClientApi { | ||
@Query | ||
List<Film> getAllFilms(); | ||
} | ||
``` | ||
|
||
Finally, implement a REST endpoint to expose the GraphQL client's functionality: | ||
```java | ||
@GET | ||
@Path("/typesafe/films") | ||
@Produces(MediaType.APPLICATION_JSON) | ||
public List<Film> getAllFilms() { | ||
FilmClientApi client = TypesafeGraphQLClientBuilder.newBuilder() | ||
.endpoint(URL) // http://localhost:8080/quickstart/graphql | ||
.build(FilmClientApi.class); | ||
return client.getAllFilms(); | ||
} | ||
``` | ||
You can test the endpoint using a tool like `curl`: | ||
``` | ||
curl localhost:8080/quickstart-client/typesafe/films | ||
``` | ||
The typesafe client will automatically generate the corresponding GraphQL query based on the operation's return type and domain classes: | ||
``` | ||
query allFilms { | ||
allFilms { | ||
title | ||
pisodeID | ||
director | ||
releaseDate | ||
desc | ||
} | ||
} | ||
``` | ||
The proxy will then send this query as part of the GraphQL request to the server. The server will process the request and return a GraphQL response. | ||
The response will be deserialized into Java objects. | ||
|
||
Other endpoints: | ||
- **`localhost:8080/typesafe/films/{id}`:** Retrieves a specific film by its index. | ||
- **`localhost:8080/typesafe/delete/hero/{id}`:** Deletes a hero by its index. | ||
- **`localhost:8080/typesafe/heroes/{surname}`:** Retrieves a list of heroes with a specific surname. | ||
|
||
> [NOTE] | ||
> The `VertxTypesafeGraphQLClientBuilder` (*Vert.x*'s typesafe implementation) allows to inject a pre-build `ClientModels` bean instance–which has been generated during deployment process via Jandex API. | ||
> This means you can provide the pre-generated GraphQL queries directly to the typesafe client builder, bypassing the default generation process of using Java Reflection during runtime. | ||
> ```java | ||
> @Inject | ||
> ClientModels clientmodels; | ||
> // ... | ||
> FilmClientApi client = new VertxTypesafeGraphQLClientBuilder() | ||
> .clientModels(clientModels) | ||
> .endpoint(URL) | ||
> .build(FilmClientApi.class); | ||
> // ... | ||
>``` | ||
### Dynamic API | ||
Unlike the typesafe API, the dynamic client does not require a client API interface or domain classes. It operates directly with abstract representations of GraphQL documents, constructed using a domain-specific language (DSL). | ||
Exchanged objects are treated as abstract `JsonObject`, but can be converted to concrete model objects if necessary. | ||
#### Example | ||
```java | ||
@GET | ||
@Path("/dynamic/films/{id}") | ||
@Produces(MediaType.APPLICATION_JSON) | ||
public Film getFilmDynamic(@PathParam("id") int id) throws ExecutionException, InterruptedException { | ||
try (VertxDynamicGraphQLClient dynamicGraphQLClient = | ||
(VertxDynamicGraphQLClient) new VertxDynamicGraphQLClientBuilder() | ||
.url(URL) | ||
.build() | ||
) { | ||
Variable filmId = var("filmId", nonNull(ScalarType.GQL_INT)); | ||
Document query = document( | ||
operation("film", vars(filmId), | ||
field("film", args(arg("filmId", filmId)), | ||
field("title"), | ||
field("episodeID"), | ||
field("director"), | ||
field("releaseDate"), | ||
field("desc") | ||
) | ||
) | ||
); | ||
Response response = dynamicGraphQLClient.executeSync(query, Collections.singletonMap("filmId", id)); | ||
return response.getObject(Film.class, "film"); | ||
} | ||
} | ||
``` | ||
You can test the endpoint using a tool like `curl`: | ||
``` | ||
curl localhost:8080/quickstart-client/dynamic/films/{id} | ||
``` | ||
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,209 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<!-- | ||
~ Copyright 2020 Red Hat, Inc. | ||
~ | ||
~ Licensed under the Apache License, Version 2.0 (the "License"); | ||
~ you may not use this file except in compliance with the License. | ||
~ You may obtain a copy of the License at | ||
~ | ||
~ http://www.apache.org/licenses/LICENSE-2.0 | ||
~ | ||
~ Unless required by applicable law or agreed to in writing, software | ||
~ distributed under the License is distributed on an "AS IS" BASIS, | ||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
~ See the License for the specific language governing permissions and | ||
~ limitations under the License. | ||
--> | ||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | ||
<modelVersion>4.0.0</modelVersion> | ||
|
||
<parent> | ||
<artifactId>wildfly-microprofile-graphql-parent</artifactId> | ||
<groupId>org.wildfly.extras.graphql</groupId> | ||
<version>2.4.2.Final-SNAPSHOT</version> | ||
</parent> | ||
|
||
<artifactId>wildfly-microprofile-graphql-quickstart-client</artifactId> | ||
<version>2.4.2.Final-SNAPSHOT</version> | ||
<packaging>war</packaging> | ||
<name>WildFly MicroProfile GraphQL - Quickstart Client</name> | ||
<description>Quickstart for the WildFly implementation of MicroProfile GraphQL Client</description> | ||
|
||
<properties> | ||
<maven.deploy.skip>true</maven.deploy.skip> | ||
<compiler-plugin.version>3.13.0</compiler-plugin.version> | ||
<!-- these are only relevant for testing --> | ||
<jboss.dist>${project.basedir}/target/wildfly</jboss.dist> | ||
<jboss.home>${jboss.dist}</jboss.home> | ||
<!-- Where the testing WF instance will be bound. | ||
If the user has already started their WF instance for experimenting with the quickstart, it is most likely | ||
on 127.0.0.1, so let's try 127.0.0.2 to avoid clashing and run a separate instance. --> | ||
<node0>127.0.0.2</node0> | ||
</properties> | ||
|
||
<licenses> | ||
<license> | ||
<name>Apache License, Version 2.0</name> | ||
<url>http://www.apache.org/licenses/LICENSE-2.0.html</url> | ||
<distribution>repo</distribution> | ||
</license> | ||
</licenses> | ||
|
||
<!-- just override dependencyManagement from parent because we don't want to exclude transitive deps | ||
--> | ||
<dependencyManagement> | ||
<dependencies> | ||
<dependency> | ||
<groupId>io.smallrye</groupId> | ||
<artifactId>smallrye-graphql-client-api</artifactId> | ||
<version>${version.io.smallrye.graphql}</version> | ||
</dependency> | ||
<dependency> | ||
<groupId>io.smallrye</groupId> | ||
<artifactId>smallrye-graphql-client</artifactId> | ||
<version>${version.io.smallrye.graphql}</version> | ||
</dependency> | ||
</dependencies> | ||
</dependencyManagement> | ||
|
||
<dependencies> | ||
<dependency> | ||
<groupId>io.smallrye</groupId> | ||
<artifactId>smallrye-graphql-client-api</artifactId> | ||
<scope>provided</scope> | ||
</dependency> | ||
<dependency> | ||
<groupId>io.smallrye</groupId> | ||
<artifactId>smallrye-graphql-client-implementation-vertx</artifactId> | ||
<scope>provided</scope> | ||
</dependency> | ||
<dependency> | ||
<groupId>io.smallrye</groupId> | ||
<artifactId>smallrye-graphql-client-model</artifactId> | ||
<version>${version.io.smallrye.graphql}</version> | ||
<scope>provided</scope> | ||
</dependency> | ||
<dependency> | ||
<groupId>jakarta.inject</groupId> | ||
<artifactId>jakarta.inject-api</artifactId> | ||
<scope>provided</scope> | ||
</dependency> | ||
<dependency> | ||
<groupId>org.eclipse.microprofile.graphql</groupId> | ||
<artifactId>microprofile-graphql-api</artifactId> | ||
<scope>provided</scope> | ||
</dependency> | ||
<dependency> | ||
<groupId>jakarta.ws.rs</groupId> | ||
<artifactId>jakarta.ws.rs-api</artifactId> | ||
<scope>provided</scope> | ||
</dependency> | ||
</dependencies> | ||
<build> | ||
<finalName>quickstart-client</finalName> | ||
<plugins> | ||
<plugin> | ||
<!-- To be able to deploy the app by doing mvn package wildfly:deploy --> | ||
<groupId>org.wildfly.plugins</groupId> | ||
<artifactId>wildfly-maven-plugin</artifactId> | ||
<configuration> | ||
<feature-packs> | ||
<feature-pack> | ||
<location>wildfly@maven(org.jboss.universe:community-universe):current#${version.org.wildfly}</location> | ||
</feature-pack> | ||
<feature-pack> | ||
<location>org.wildfly.extras.graphql:wildfly-microprofile-graphql-feature-pack:${project.version}</location> | ||
</feature-pack> | ||
</feature-packs> | ||
<layers> | ||
<layer>cloud-server</layer> | ||
<layer>jmx-remoting</layer> | ||
<layer>management</layer> | ||
<layer>microprofile-graphql</layer> | ||
<layer>micrometer</layer> | ||
<layer>microprofile-telemetry</layer> | ||
</layers> | ||
</configuration> | ||
</plugin> | ||
|
||
<!-- Prepare a WildFly distribution for testing. Only relevant for the tests. --> | ||
<plugin> | ||
<groupId>org.jboss.galleon</groupId> | ||
<artifactId>galleon-maven-plugin</artifactId> | ||
<executions> | ||
<execution> | ||
<id>server-provisioning</id> | ||
<goals> | ||
<goal>provision</goal> | ||
</goals> | ||
<phase>test-compile</phase> | ||
<configuration> | ||
<install-dir>${project.build.directory}/wildfly-test</install-dir> | ||
<record-state>false</record-state> | ||
<log-time>${galleon.log.time}</log-time> | ||
<plugin-options> | ||
<jboss-maven-dist/> | ||
<jboss-fork-embedded>${galleon.fork.embedded}</jboss-fork-embedded> | ||
<optional-packages>passive+</optional-packages> | ||
</plugin-options> | ||
<feature-packs> | ||
<feature-pack> | ||
<transitive>true</transitive> | ||
<groupId>org.wildfly</groupId> | ||
<artifactId>wildfly-galleon-pack</artifactId> | ||
<version>${version.org.wildfly}</version> | ||
<inherit-packages>false</inherit-packages> | ||
<inherit-configs>false</inherit-configs> | ||
</feature-pack> | ||
<feature-pack> | ||
<groupId>${project.groupId}</groupId> | ||
<artifactId>wildfly-microprofile-graphql-feature-pack</artifactId> | ||
<version>${project.version}</version> | ||
<inherit-packages>false</inherit-packages> | ||
<inherit-configs>false</inherit-configs> | ||
</feature-pack> | ||
</feature-packs> | ||
<configurations> | ||
<config> | ||
<model>standalone</model> | ||
<name>standalone.xml</name> | ||
<layers> | ||
<layer>jaxrs-server</layer> | ||
<layer>jmx-remoting</layer> | ||
<layer>observability</layer> | ||
<!-- Layers from this FP --> | ||
<layer>microprofile-graphql</layer> | ||
<layer>micrometer</layer> | ||
<layer>microprofile-telemetry</layer> | ||
</layers> | ||
</config> | ||
</configurations> | ||
</configuration> | ||
</execution> | ||
</executions> | ||
</plugin> | ||
<plugin> | ||
<groupId>org.apache.maven.plugins</groupId> | ||
<artifactId>maven-surefire-plugin</artifactId> | ||
<configuration> | ||
<systemPropertyVariables combine.children="append"> | ||
<jboss.install.dir>${project.build.directory}/wildfly-test</jboss.install.dir> | ||
<server.jvm.args>-Djboss.bind.address=${node0} -Djboss.bind.address.management=${node0} -Djboss.bind.address.unsecure=${node0}</server.jvm.args> | ||
<node0>${node0}</node0> | ||
</systemPropertyVariables> | ||
</configuration> | ||
</plugin> | ||
|
||
<plugin> | ||
<artifactId>maven-compiler-plugin</artifactId> | ||
<version>${compiler-plugin.version}</version> | ||
<configuration> | ||
<compilerArgs> | ||
<arg>-parameters</arg> | ||
</compilerArgs> | ||
</configuration> | ||
</plugin> | ||
</plugins> | ||
</build> | ||
|
||
</project> |
Oops, something went wrong.