Skip to content

Commit

Permalink
Enable GraphQL endpoints (#41)
Browse files Browse the repository at this point in the history
  • Loading branch information
QubitPi authored Sep 13, 2023
1 parent 29e7071 commit b2a25c2
Show file tree
Hide file tree
Showing 5 changed files with 172 additions and 34 deletions.
3 changes: 3 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,6 @@ ARG WS_VERSION=1.0-SNAPSHOT
ENV JETTY_WEBAPPS_DIR /var/lib/jetty/webapps

COPY ./target/jersey-ws-template-$WS_VERSION.war $JETTY_WEBAPPS_DIR/ROOT.war

RUN java -jar "$JETTY_HOME/start.jar" --add-module=annotations,server,http,deploy,servlet,webapp,resources,jsp
RUN rm -rf /var/lib/jetty/start.d/websocket.ini
90 changes: 75 additions & 15 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,16 @@
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>

<version.elide>7.0.0-pr6</version.elide>
<version.validation.api>3.0.1</version.validation.api>
<version.jersey>3.1.1</version.jersey>
<hibernate.version>6.2.4.Final</hibernate.version>
<version.jcip.annotations>1.0</version.jcip.annotations>
<version.slf4j>2.0.7</version.slf4j>
<version.logback>1.4.7</version.logback>
<version.owner>1.0.12</version.owner>
<version.groovy>4.0.6</version.groovy>
<version.jetty>11.0.15</version.jetty>

<version.maven.war.plugin>3.2.2</version.maven.war.plugin>
<version.maven.javadoc.plugin>3.5.0</version.maven.javadoc.plugin>
Expand Down Expand Up @@ -68,6 +73,13 @@
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-bom</artifactId>
<version>${version.jetty}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>

Expand All @@ -93,31 +105,62 @@
<dependency>
<groupId>com.yahoo.elide</groupId>
<artifactId>elide-core</artifactId>
<version>7.0.0-pr6</version>
<exclusions>
<exclusion>
<groupId>com.yahoo.elide</groupId>
<artifactId>elide-graphql</artifactId>
</exclusion>
</exclusions>
<version>${version.elide}</version>
</dependency>
<dependency>
<groupId>com.yahoo.elide</groupId>
<artifactId>elide-standalone</artifactId>
<version>7.0.0-pr6</version>
<exclusions>
<exclusion>
<groupId>com.yahoo.elide</groupId>
<artifactId>elide-graphql</artifactId>
</exclusion>
</exclusions>
<artifactId>elide-datastore-jpa</artifactId>
<version>${version.elide}</version>
</dependency>
<dependency>
<groupId>com.yahoo.elide</groupId>
<artifactId>elide-graphql</artifactId>
<version>${version.elide}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.yahoo.elide</groupId>
<artifactId>elide-test-helpers</artifactId>
<version>${version.elide}</version>
<scope>test</scope>
</dependency>

<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.49</version>
</dependency>

<dependency>
<groupId>jakarta.validation</groupId>
<artifactId>jakarta.validation-api</artifactId>
<version>${version.validation.api}</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet</artifactId>
<version>${version.jersey}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.inject</groupId>
<artifactId>jersey-hk2</artifactId>
<version>3.0.0</version>
<scope>compile</scope>
</dependency>

<!-- Hibernate -->
<dependency>
<groupId>org.hibernate.orm</groupId>
<artifactId>hibernate-core</artifactId>
<version>${hibernate.version}</version>
</dependency>
<dependency>
<groupId>org.hibernate.orm</groupId>
<artifactId>hibernate-hikaricp</artifactId>
<version>${hibernate.version}</version>
</dependency>

<!-- Concurrency -->
<dependency>
<groupId>net.jcip</groupId>
Expand Down Expand Up @@ -157,6 +200,23 @@
<scope>test</scope>
</dependency>

<!--Jetty-->
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-server</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-webapp</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-servlet</artifactId>
<scope>test</scope>
</dependency>

<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@
*/
package com.qubitpi.ws.jersey.template.application;

import static com.yahoo.elide.standalone.Util.combineModelEntities;

import com.yahoo.elide.Elide;
import com.yahoo.elide.ElideSettings;
import com.yahoo.elide.ElideSettingsBuilder;
Expand Down Expand Up @@ -44,6 +42,7 @@
import org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl;
import org.hibernate.jpa.boot.internal.PersistenceUnitInfoDescriptor;

import jakarta.persistence.Entity;
import jakarta.persistence.EntityManager;
import jakarta.persistence.EntityManagerFactory;
import jakarta.persistence.spi.PersistenceUnitInfo;
Expand All @@ -53,8 +52,10 @@

import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Properties;
import java.util.function.Consumer;
import java.util.stream.Collectors;

/**
* A binder factory builds a custom binder for the Jersey application.
Expand Down Expand Up @@ -167,7 +168,7 @@ private EntityManagerFactory buildEntityManagerFactory() {

final PersistenceUnitInfo persistenceUnitInfo = new PersistenceUnitInfoImpl(
"astraios",
combineModelEntities(classScanner, modelPackageName, false),
getAllEntities(classScanner, modelPackageName),
getDefaultDbConfigs(),
classLoader
);
Expand All @@ -179,6 +180,24 @@ private EntityManagerFactory buildEntityManagerFactory() {
).build();
}

/**
* Get all the entities in a package.
*
* @param scanner An object that picks up entities by Elide annotation
* @param packageName A fully qualified package name under which contains all entities
*
* @return all entities found in the provided package.
*/
@NotNull
public static List<String> getAllEntities(
@NotNull final ClassScanner scanner,
@NotNull final String packageName
) {
return scanner.getAnnotatedClasses(packageName, Entity.class).stream()
.map(Class::getName)
.collect(Collectors.toList());
}

/**
* Returns a collection of DB configurations, including connecting credentials.
* <p>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@
@ApplicationPath("/v1/data/")
public class ResourceConfig extends org.glassfish.jersey.server.ResourceConfig {

private static final String ENDPOINT_PACKAGE = "com.yahoo.elide.jsonapi.resources";
private static final String GRAPHQL_ENDPOINT_PACKAGE = "com.yahoo.elide.graphql";
private static final String JAON_API_ENDPOINT_PACKAGE = "com.yahoo.elide.jsonapi.resources";
private static final OAuthConfig OAUTH_CONFIG = ConfigFactory.create(OAuthConfig.class);

/**
Expand All @@ -58,12 +59,12 @@ public ResourceConfig(final ServiceLocator injector) {
* @param binderFactory An object that produces resource binder
* @param oauthEnabled Flag on whether or not to enable auth feature, mainly for differentiating dev/test and prod
*/
public ResourceConfig(
private ResourceConfig(
@NotNull final ServiceLocator injector,
@NotNull final BinderFactory binderFactory,
final boolean oauthEnabled
) {
packages(ENDPOINT_PACKAGE);
packages(JAON_API_ENDPOINT_PACKAGE, GRAPHQL_ENDPOINT_PACKAGE);

register(CorsFilter.class);
if (oauthEnabled) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ package com.qubitpi.ws.jersey.template.application

import com.yahoo.elide.jsonapi.JsonApi

import com.qubitpi.ws.jersey.template.web.filters.OAuthFilter

import org.apache.http.HttpStatus
import org.eclipse.jetty.server.Server
import org.eclipse.jetty.servlet.ServletContextHandler
Expand All @@ -27,6 +29,7 @@ import org.testcontainers.containers.MySQLContainer
import org.testcontainers.spock.Testcontainers

import io.restassured.RestAssured
import io.restassured.builder.RequestSpecBuilder
import spock.lang.Shared

@Testcontainers
Expand All @@ -41,7 +44,10 @@ class ResourceConfigITSpec extends AbstractITSpec {

@Override
def childSetupSpec() {
System.setProperty("OAUTH_ENABLED", "false")
RestAssured.requestSpecification = new RequestSpecBuilder()
.addHeader(OAuthFilter.AUTHORIZATION_HEADER, OAuthFilter.AUTHORIZATION_SCHEME + " " + "someAccessToken")
.build()

System.setProperty(
"DB_URL",
String.format("jdbc:mysql://localhost:%s/elide?serverTimezone=UTC", MYSQL.firstMappedPort)
Expand All @@ -51,7 +57,6 @@ class ResourceConfigITSpec extends AbstractITSpec {
@Override
def childCleanupSpec() {
System.clearProperty("DB_URL")
System.clearProperty("OAUTH_ENABLED")
}

@SuppressWarnings('GroovyAccessibility')
Expand All @@ -61,20 +66,16 @@ class ResourceConfigITSpec extends AbstractITSpec {

jettyEmbeddedServer.setHandler(servletContextHandler)

ServletHolder jsonApiServlet = servletContextHandler.addServlet(ServletContainer.class, "/v1/data/*")
jsonApiServlet.setInitOrder(0)
jsonApiServlet.setInitParameter("jersey.config.server.provider.packages", ResourceConfig.ENDPOINT_PACKAGE)
jsonApiServlet.setInitParameter("jakarta.ws.rs.Application", ResourceConfig.class.getCanonicalName())
ServletHolder jerseyServlet = servletContextHandler.addServlet(ServletContainer.class, "/v1/data/*")
jerseyServlet.setInitOrder(0)
jerseyServlet.setInitParameter(
"jersey.config.server.provider.packages",
[ResourceConfig.JAON_API_ENDPOINT_PACKAGE, ResourceConfig.GRAPHQL_ENDPOINT_PACKAGE].join(";")
)
jerseyServlet.setInitParameter("jakarta.ws.rs.Application", ResourceConfig.class.getCanonicalName())

jettyEmbeddedServer.start()
}

def cleanup() {
jettyEmbeddedServer.stop()
jettyEmbeddedServer.destroy()
}

def "JSON API allows for POSTing and GETing a book"() {
expect: "database is initially empty"
RestAssured
.given()
Expand All @@ -83,7 +84,14 @@ class ResourceConfigITSpec extends AbstractITSpec {
.then()
.statusCode(200)
.body("data", Matchers.equalTo([]))
}

def cleanup() {
jettyEmbeddedServer.stop()
jettyEmbeddedServer.destroy()
}

def "JSON API allows for POSTing, GETing, PATCHing, and DELETing a book"() {
when: "an entity is POSTed via JSON API"
RestAssured
.given()
Expand Down Expand Up @@ -113,5 +121,52 @@ class ResourceConfigITSpec extends AbstractITSpec {
]
]
]))

when: "we update that entity"
RestAssured
.given()
.contentType(JsonApi.MEDIA_TYPE)
.accept(JsonApi.MEDIA_TYPE)
.body("""
{"data": {"type": "book", "id": "elide-demo", "attributes": {"title": "Pride and Prejudice"}}}
""")
.when()
.patch("book/elide-demo")
.then()
.statusCode(HttpStatus.SC_NO_CONTENT)

then: "we can GET that entity with updated attribute"
RestAssured
.given()
.when()
.get("book")
.then()
.statusCode(200)
.body("data", Matchers.equalTo([
[
type: "book",
id: "elide-demo",
attributes: [
title: "Pride and Prejudice"
]
]
]))

when: "the entity is deleted"
RestAssured
.given()
.when()
.delete("book/elide-demo")
.then()
.statusCode(HttpStatus.SC_NO_CONTENT)

then: "that entity is not found in database anymore"
RestAssured
.given()
.when()
.get("book")
.then()
.statusCode(200)
.body("data", Matchers.equalTo([]))
}
}

0 comments on commit b2a25c2

Please sign in to comment.