Skip to content

Commit

Permalink
Merge branch 'release/1.1' into 'master'
Browse files Browse the repository at this point in the history
Release/1.1

See merge request yuanwq/shopify4j!36
  • Loading branch information
YuanWenqing committed Apr 20, 2021
2 parents d836987 + f91648a commit 576d19a
Show file tree
Hide file tree
Showing 47 changed files with 9,058 additions and 150 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ build
gen
out
.idea
store.properties
test.properties

# Ignore Gradle GUI config
gradle-app.setting
Expand Down
39 changes: 27 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ Java SDK for Shopify APIs, including:
* GraphQL Admin API
* GraphQL Storefront Schema
* GraphQL Storefront API
* GraphQL Partner Schema
* GraphQL Partner API
* [INCOMPLETE] REST Admin API Models
* [INCOMPLETE] REST Admin API
* ...
Expand All @@ -29,13 +31,23 @@ implementation("xyz.codemeans.shopify4j:graphql-admin-schema:1.0")
```

GraphQL Storefront

```groovy
// api
implementation("xyz.codemeans.shopify4j:graphql-storefront-api:1.0")
// schema
implementation("xyz.codemeans.shopify4j:graphql-storefront-schema:1.0")
```

GraphQL Partner

```groovy
// api
implementation("xyz.codemeans.shopify4j:graphql-partner-api:1.0")
// schema
implementation("xyz.codemeans.shopify4j:graphql-partner-schema:1.0")
```

REST Admin
```groovy
// api
Expand Down Expand Up @@ -102,12 +114,12 @@ OauthAccessToken accessToken = oauthFlow.exchangeAccessToken(app, redirection);
HMAC Verification

```java
boolean verified = HmacVerification.verifyHmac(queryString, app.getClientSecret());
boolean verified = HmacVerification.verifyQueryString(app.getClientSecret(), queryString);
```

## Multi-Stores

If you are integrating with multiple shopify stores in one sysmtem, just like we do, `StoreFactory` will be very helpful.
If you are integrating with multiple shopify stores in one sysmtem, just like we do, `ClientFactory` will be very helpful.

If information of your stores is saved in some persistent database, you can just implement a `StoreSettingStorage` to retrieve data and build out a `StoreSetting`.

Expand All @@ -117,9 +129,9 @@ Here is an example for REST & GraphQL API:
StoreSettingStorage settingStorage = ...;

GraphqlInvoker invoker = new OkHttpGraphqlInvoker(new PrivateAppAdminAccessTokenProvider(settingStorage));
StoreFactory<GraphqlAdmin> storeFactory = new DefaultGraphqlAdminFactory(settingStorage, invoker);
storeFactory = CachedStoreFactory.of(storeFactory); // cache created stores, avoiding duplicated creation
GraphqlAdmin store1 = storeFactory.getStore(domain1);
ClientFactory<GraphqlAdmin> clientFactory = new DefaultGraphqlAdminFactory(settingStorage, invoker);
clientFactory = CachedClientFactory.of(clientFactory); // cache created stores, avoiding duplicated creation
GraphqlAdmin store1 = clientFactory.getClient(domain1);
```

## Release
Expand All @@ -136,11 +148,13 @@ GraphqlInvoker invoker = new OkHttpGraphqlInvoker(AccessTokenProvider.constant(s
GraphqlAdmin admin = new DefaultGraphqlAdmin(setting, invoker);

// get a product with: title, handle ...
QueryRootQuery queryRootQuery = Operations.query(
query -> query.product(id,
product -> product.title()
.handle()
...));
QueryRootQuery queryRootQuery = Operations.query(query -> query
.product(id, product -> product
.title()
.handle()
...
)
);
Product product = admin.query(queryRootQuery).getData().getProduct();
~~~

Expand All @@ -154,8 +168,9 @@ You can customize your implementation on any http library you like.

## Reference

* GraphQL Admin API Documentation: https://shopify.dev/docs/admin-api/graphql/reference
* GraphQL Storefront API Documentation: https://shopify.dev/docs/storefront-api/reference
* GraphQL Admin API Documentation: https://shopify.dev/docs/admin-api/graphql/
* GraphQL Storefront API Documentation: https://shopify.dev/docs/storefront-api/
* GraphQL Partner API Documentation: https://shopify.dev/docs/partner-api/
* Starter Tutorial: https://www.shopify.com/partners/blog/getting-started-with-graphql
* Codegen: https://github.com/Shopify/graphql_java_gen/
* Find GraphQL schema: https://community.shopify.com/c/Shopify-APIs-SDKs/Admin-API-Graphql-shema-endpoint/m-p/837807
Expand Down
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ buildscript {
// git version
apply plugin: "org.ajoberstar.grgit"
int commits = grgit.log().size()
version = "1.0"
version = "1.1"
String pubRepo = rootProject.hasProperty("pub") ? rootProject.property("pub") : "nexus"
if (pubRepo != "oss") {
version = "${version}.${commits}"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package codemeans.shopify4j.graphql.admin;


import codemeans.shopify4j.core.base.ClientFactory;
import codemeans.shopify4j.graphql.GraphqlInvoker;
import codemeans.shopify4j.core.store.CachedStoreFactory;
import codemeans.shopify4j.core.store.StoreFactory;
import codemeans.shopify4j.core.base.CachedClientFactory;
import lombok.Data;
import lombok.NonNull;

Expand All @@ -12,7 +12,7 @@
* @date: 2021-01-12
*/
@Data
public class GraphqlAdminFactory implements StoreFactory<GraphqlAdmin> {
public class GraphqlAdminFactory implements ClientFactory<GraphqlAdmin> {

private final GraphqlInvoker graphqlInvoker;
private String apiVersion = "2021-01";
Expand All @@ -22,17 +22,17 @@ public GraphqlAdminFactory(@NonNull GraphqlInvoker graphqlInvoker) {
}

@Override
public GraphqlAdmin getStore(String myshopifyDomain) {
public GraphqlAdmin getClient(String myshopifyDomain) {
return new DefaultGraphqlAdmin(myshopifyDomain, apiVersion, graphqlInvoker);
}

public CachedGraphqlAdminFactory cached() {
return new CachedGraphqlAdminFactory(this);
}

public static class CachedGraphqlAdminFactory extends CachedStoreFactory<GraphqlAdmin> {
public static class CachedGraphqlAdminFactory extends CachedClientFactory<GraphqlAdmin> {

protected CachedGraphqlAdminFactory(StoreFactory delegate) {
protected CachedGraphqlAdminFactory(ClientFactory delegate) {
super(delegate);
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
package codemeans.shopify4j.graphql.admin;

import codemeans.shopify4j.core.auth.PrivateAppAdminAccessTokenProvider;
import codemeans.shopify4j.core.store.CachedStoreFactory;
import codemeans.shopify4j.core.store.MemoryStoreSettingStorage;
import codemeans.shopify4j.core.store.StoreFactory;
import codemeans.shopify4j.core.store.StoreSetting;
import codemeans.shopify4j.core.base.CachedClientFactory;
import codemeans.shopify4j.core.base.ClientFactory;
import codemeans.shopify4j.core.base.MemoryStoreSettingStorage;
import codemeans.shopify4j.core.base.StoreSetting;
import codemeans.shopify4j.graphql.GraphqlInvoker;
import codemeans.shopify4j.graphql.OkHttpGraphqlInvoker;
import java.io.File;
Expand All @@ -28,14 +28,14 @@ public class ContextForTest {

public static final GraphqlInvoker INVOKER = OkHttpGraphqlInvoker.admin(
new PrivateAppAdminAccessTokenProvider(STORE_SETTING_STORAGE));
public static final StoreFactory<GraphqlAdmin> FACTORY = CachedStoreFactory
public static final ClientFactory<GraphqlAdmin> FACTORY = CachedClientFactory
.of(new GraphqlAdminFactory(INVOKER));
public static final GraphqlAdmin TEST_STORE = FACTORY
.getStore(STORE_SETTING.getMyshopifyDomain());
.getClient(STORE_SETTING.getMyshopifyDomain());

private static StoreSetting loadTestStore() {
File workdir = new File(System.getProperty("user.dir")).getParentFile();
File propertiesFile = new File(workdir, "store.properties");
File propertiesFile = new File(workdir, "test.properties");
try (FileInputStream inputStream = new FileInputStream(propertiesFile)) {
PROPERTIES.load(inputStream);
return StoreSetting.fromProperties(PROPERTIES);
Expand Down
21 changes: 21 additions & 0 deletions graphql-partner-api/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
dependencies {
// lombok
annotationProcessor("org.projectlombok:lombok:$lombokVersion")
compileOnly("org.projectlombok:lombok:$lombokVersion")
testCompileOnly("org.projectlombok:lombok:$lombokVersion")

api(project(":shopify4j-core"))
api(project(":graphql-partner-schema"))

api("com.squareup.okhttp3:okhttp:$okhttpVersion")

api("commons-io:commons-io:$commonsIOVersion")

// test
testImplementation("junit:junit:$junitVersion")
testImplementation("org.apache.logging.log4j:log4j-slf4j-impl:$log4jVersion")

}

description "Java SDK for Shopify Partner GraphQL API"
apply from: "$rootDir/publish.gradle"
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package codemeans.shopify4j.graphql.partner;

import codemeans.shopify4j.core.exception.GraphqlApiException;
import codemeans.shopify4j.graphql.GraphqlInvoker;
import codemeans.shopify4j.graphql.partner.exception.GraphqlPartnerQueryException;
import codemeans.shopify4j.graphql.partner.exception.GraphqlPartnerSchemaException;
import codemeans.shopify4j.graphql.partner.types.QueryResponse;
import codemeans.shopify4j.graphql.partner.types.QueryRootQuery;
import com.shopify.graphql.support.SchemaViolationError;

/**
* @author: yuanwq
* @date: 2021-01-26
*/
public class DefaultGraphqlPartner implements GraphqlPartner {

private final String organizationId;
private final String apiVersion;
private final String graphqlEndpoint;
private final GraphqlInvoker invoker;

public DefaultGraphqlPartner(String organizationId, String apiVersion,
GraphqlInvoker invoker) {
this.organizationId = organizationId;
this.apiVersion = apiVersion;
this.graphqlEndpoint = String.format("https://partners.shopify.com/%s/api/%s/graphql.json",
this.organizationId, apiVersion);
this.invoker = invoker;
}

@Override
public String getOrganizationId() {
return organizationId;
}

@Override
public String getApiVersion() {
return apiVersion;
}

@Override
public String getGraphqlEndpoint() {
return graphqlEndpoint;
}

@Override
public String request(String query) throws GraphqlApiException {
return invoker.request(graphqlEndpoint, query);
}

@Override
public QueryResponse query(QueryRootQuery query) throws GraphqlApiException {
String resp = null;
try {
String queryBody = query.toString();
resp = invoker.request(graphqlEndpoint, queryBody);
QueryResponse response = QueryResponse.fromJson(resp);
if (response.getErrors() != null && !response.getErrors().isEmpty()) {
throw new GraphqlPartnerQueryException(query, response);
}
return response;
} catch (SchemaViolationError schemaViolationError) {
throw new GraphqlPartnerSchemaException(query, resp, schemaViolationError);
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package codemeans.shopify4j.graphql.partner;

import codemeans.shopify4j.core.exception.GraphqlApiException;
import codemeans.shopify4j.graphql.partner.types.QueryResponse;
import codemeans.shopify4j.graphql.partner.types.QueryRootQuery;

/**
* @author: yuanwq
* @date: 2021-01-26
*/
public interface GraphqlPartner {

String getOrganizationId();

String getApiVersion();

String getGraphqlEndpoint();

/**
* 原始请求
*/
String request(String query) throws GraphqlApiException;

QueryResponse query(QueryRootQuery query) throws GraphqlApiException;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package codemeans.shopify4j.graphql.partner;

import codemeans.shopify4j.core.base.CachedClientFactory;
import codemeans.shopify4j.core.base.ClientFactory;
import codemeans.shopify4j.graphql.GraphqlInvoker;
import lombok.Data;
import lombok.NonNull;

/**
* @author: yuanwq
* @date: 2021-01-12
*/
@Data
public class GraphqlPartnerFactory implements ClientFactory<GraphqlPartner> {

private final GraphqlInvoker graphqlInvoker;
private String apiVersion = "2021-04";

public GraphqlPartnerFactory(@NonNull GraphqlInvoker graphqlInvoker) {
this.graphqlInvoker = graphqlInvoker;
}

@Override
public GraphqlPartner getClient(String organizationId) {
return new DefaultGraphqlPartner(organizationId, apiVersion, graphqlInvoker);
}

public CachedGraphqlPartnerFactory cached() {
return new CachedGraphqlPartnerFactory(this);
}

public static class CachedGraphqlPartnerFactory extends CachedClientFactory<GraphqlPartner> {

protected CachedGraphqlPartnerFactory(ClientFactory delegate) {
super(delegate);
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package codemeans.shopify4j.graphql.partner.exception;

import codemeans.shopify4j.core.exception.GraphqlApiException;
import codemeans.shopify4j.graphql.partner.types.QueryResponse;
import codemeans.shopify4j.graphql.partner.types.QueryRootQuery;
import com.shopify.graphql.support.Error;
import java.util.Collections;
import java.util.List;
import lombok.Getter;

/**
* @author: yuanwq
* @date: 2021-01-26
*/
public class GraphqlPartnerQueryException extends GraphqlApiException {

@Getter
private QueryRootQuery query;
@Getter
private QueryResponse response;
@Getter
private List<Error> errors;

public GraphqlPartnerQueryException(QueryRootQuery query, QueryResponse response) {
super("Query: " + query + ", Response: " + response.toJson());
this.query = query;
this.response = response;
this.errors = response.getErrors() != null ? response.getErrors() : Collections.emptyList();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package codemeans.shopify4j.graphql.partner.exception;

import codemeans.shopify4j.core.exception.GraphqlApiException;
import com.shopify.graphql.support.Query;
import com.shopify.graphql.support.SchemaViolationError;
import lombok.Getter;

/**
* @author: yuanwq
* @date: 2021-01-26
*/
public class GraphqlPartnerSchemaException extends GraphqlApiException {

@Getter
private Query query;
@Getter
private SchemaViolationError schemaViolationError;

public GraphqlPartnerSchemaException(Query query, String resp,
SchemaViolationError schemaViolationError) {
super("Query: " + query + ", Resp: " + resp, schemaViolationError);
this.query = query;
this.schemaViolationError = schemaViolationError;
}

}
Loading

0 comments on commit 576d19a

Please sign in to comment.