Git Product home page Git Product logo

commercetools / commercetools-sdk-java-v2 Goto Github PK

View Code? Open in Web Editor NEW
33.0 12.0 15.0 572.12 MB

The e-commerce SDK from commercetools for Java.

Home Page: https://commercetools.github.io/commercetools-sdk-java-v2/javadoc/index.html

License: Apache License 2.0

Java 99.80% Shell 0.01% Makefile 0.01% Kotlin 0.07% RAML 0.13% JavaScript 0.01%
commercetools-java-sdks sdk commercetools java commercetools-sdk java-sdk commercetools-java-sdk audit-sdk commercetools-scp

commercetools-sdk-java-v2's Introduction

commercetools Composable Commerce JAVA SDK

Introduction

This repository contains the commercetools Composable Commerce and Import API Java SDKs generated from our API reference.

Installation

Java SDK with Gradle

The latest stable SDK release can be retrieved from Maven Central with:

ext {
    versions = [
        commercetools: "17.11.0"
    ]
}

sourceCompatibility = 1.8

repositories {
    mavenCentral()
}

dependencies {
    implementation "com.commercetools.sdk:commercetools-http-client:${versions.commercetools}"
    implementation "com.commercetools.sdk:commercetools-sdk-java-api:${versions.commercetools}"
    implementation "com.commercetools.sdk:commercetools-sdk-java-importapi:${versions.commercetools}"
}

Java SDK with Maven

<properties>
    <commercetools.version>17.11.0</commercetools.version>
</properties>
<dependencies>
    <dependency>
      <groupId>com.commercetools.sdk</groupId>
      <artifactId>commercetools-http-client</artifactId>
      <version>${commercetools.version}</version>
    </dependency>
    <dependency>
      <groupId>com.commercetools.sdk</groupId>
      <artifactId>commercetools-sdk-java-api</artifactId>
      <version>${commercetools.version}</version>
    </dependency>
    <dependency>
      <groupId>com.commercetools.sdk</groupId>
      <artifactId>commercetools-sdk-java-importapi</artifactId>
      <version>${commercetools.version}</version>
    </dependency>
</dependencies>

Modules

  • commercetools-http-client: alias for commercetools-async-http-client
  • commercetools-okhttp-client3: uses OkHttp client 3.0
  • commercetools-okhttp-client4: uses OkHttp client 4.0
  • commercetools-apachehttp-client: uses Apache HTTP async client 5.1
  • commercetools-async-http-client: uses Async HTTP client 2.12
  • commercetools-reactornetty-client: uses Reactor Netty HTTP Client
  • commercetools-javanet-client: uses HTTP client (java.net.http.HttpClient) included in JDK 11+
  • commercetools-sdk-java-api: models and request builders for the product API
  • commercetools-sdk-java-importapi: models and request builders for the import API
  • commercetools-sdk-java-history: models and request builders for the audit log API
  • commercetools-sdk-compat-v1: Compatibility layer for Java v1 SDK
  • commercetools-money: Provider for JSR-354 money instances
  • commercetools-monitoring-newrelic: Middleware to integrate NewRelic monitoring
  • commercetools-monitoring-datadog: Middleware to integrate Datadog monitoring
  • commercetools-monitoring-opentelemetry: Middleware to collect metrics using OpenTelemetry
  • commercetools-graphql-api: type safe support for the commercetools GraphQL API

Migration Guidelines

To migrate from the 1.x to the 2.x, there is a guideline below:

Documentation

commercetools-sdk-java-v2's People

Contributors

acbeni avatar alex-ct avatar ashishhk avatar barbara79 avatar ct-sdks[bot] avatar evansinho avatar jenschude avatar jherey avatar johthor avatar katmatt avatar kodiakhq[bot] avatar lojzatran avatar pintomau avatar renovate-bot avatar renovate[bot] avatar salander85 avatar skyriakou avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

commercetools-sdk-java-v2's Issues

Is it possible to enhance headers for example `User-Agent` header ?

I want to add a header as below for the User-Agent and an existing header might stay:
custom-client , commercetools-java-sdks/1.6.0 Java/13.0.2+8 (Mac OS X; x86_64)

But I could not change the user-agent client, by default middleware overrides it. I think currently the only way is creating all middleware from scratch, or I am missing something?

final OAuthHandler oAuthHandler = new OAuthHandler(tokenSupplier);
return asList(
(request, next) -> next.apply(request.withHeader(ApiHttpHeaders.USER_AGENT, userAgent)),
new ErrorMiddleware(),

apiClient = ApiFactory.defaultClient(
            ClientCredentials.of().withClientId(clientId)
                             .withClientSecret(clientSecret)
                             .build(),
            ServiceRegion.GCP_EUROPE_WEST1.getOAuthTokenUrl(),
            ServiceRegion.GCP_EUROPE_WEST1.getApiUrl(),
            Collections.singletonList(
                (request, next) -> next.apply(request.withHeader(ApiHttpHeaders.USER_AGENT, "custom-client"))
            )
        );

Add retry on conflict logic

We should evaluate whether how we can add a retry logic to our SDK, it would be a good exercise to see if our middleware chaining would allow such a use case.

More understandable validation errors

Is your feature request related to a problem? Please describe.
When sending a variant creation request, there might be problems related to product type attribute constraints. The following is an example error message from submitting a variant with over 40 of such attributes :

child "resources" fails because ["resources" at position 0 fails because [child "attributes" fails because ["attributes" at position 0 fails because [child "value" fails because ["value" must be a boolean], child "value" fails because ["value" must be an array], child "value" fails because ["value" is not allowed to be empty], child "value" fails because ["value" must be an array], child "value" fails because ["value" is not allowed to be empty], child "value" fails because ["value" must be an array], child "type" fails because ["type" must be one of [enum]], child "value" fails because ["value" must be an array], child "type" fails because ["type" must be one of [lenum]], child "value" fails because ["value" must be an array], child "value" fails because ["value" must be an object], child "value" fails because ["value" must be an array], child "value" fails because ["value" must be an object], child "value" fails because ["value" must be an array], child "value" fails because ["value" must be a number], child "value" fails because ["value" must be an array], child "value" fails because ["value" must be an object, "value" must be an object, "value" must be an object, "value" must be an object, "value" must be an object, "value" must be an object, "value" must be an object, "value" must be an object, "value" must be an object, "value" must be an object, "value" must be an object, "value" must be an object, "value" must be an object, "value" must be an object], child "value" fails because ["value" must be an array], child "value" fails because ["value" is not allowed to be empty], child "value" fails because ["value" must be an array], child "type" fails because ["type" must be one of [time]], child "value" fails because ["value" must be an array]]]]]

The error does not mention which attribute and what value caused the problem.

Describe the solution you'd like
It would be essential to see the name of the attribute causing the error, plus(if possible) any other information such as the value causing the error.

Describe alternatives you've considered
At least the name of the attribute should be mentioned.

Remove legacy hostnames

Description

To improve the developer experience and easen our support and training burden all existing references to *.sphere.io and .commercetools.co host names should be removed in favor of not defaulting to a specific region (a common complaint of US and AWS customers is that EU is defaulted everywhere) or, if needed for backwards compatibility, be replaced with the new *.europe-west1.gcp.commercetools.com notation.

Expected Behavior

full text search over the repository for ".sphere.io" and ".commercetools.co" should yield zero results

Context

https://docs.commercetools.com/release-notes#releases-2020-02-03-aws-and-new-hostnames

New Import API configuration not working in Maven

Describe the bug
The newly released version 1 of the API causes problems with Maven, namely the ClientCredentials package(and the entire io.vrap.* package) is not visible from client side.

To Reproduce
Steps to reproduce the behavior:

  1. Create a maven project as described in README of the import project in GitHub
  2. Try to use the ImportApiFactory

Expected behavior
Code samples in README should also work with Maven

Screenshots
If applicable, add screenshots to help explain your problem.
image

Remove generated code

Now the generated code is uploaded, the intention for this was to review the code resulting from generation. but it gets too verbose, and we lose sense of the details since for the slightest spec change we get a huge PR, so i think it makes sense to remove the generated code now.

Make enums forward compatible

Why: There is a high chances that the backend team might add more values in the enums, even there was one case when BMU teamc changhed the name of the enum and it failed in the compilation.

Acceptance Criteria

  • Enums are backward compatible.

  • When deserializing an unknown value of enum it shouldn't be breaking.

  • Once completed open a task for .NET if this is really important.(Generated only)

Complexity : Medium

Error on Import API Product creation

Describe the bug
Using the newly released sdk, upon creating a product, the following error happens:

java.lang.RuntimeException: com.fasterxml.jackson.databind.exc.InvalidFormatException: Cannot deserialize value of type `com.commercetools.importapi.models.importoperations.ImportOperationState` from String "Unresolved": not one of the values accepted for Enum class: [ValidationFailed, Accepted]
 at [Source: (byte[])"{"operationStatus":[{"state":"Unresolved","errors":[],"operationId":"64b31793-967d-42ef-919d-bf8212a9d91f"}]}"; line: 1, column: 30] (through reference chain: com.commercetools.importapi.models.importrequests.ImportResponseImpl["operationStatus"]->java.util.ArrayList[0]->com.commercetools.importapi.models.importoperations.ImportOperationStatusImpl["state"])

To Reproduce
Steps to reproduce the behavior:

  1. Create a product and execute it, an example:
         def productRequest = ProductImportRequestBuilder.of()
                .resources([ProductImportBuilder.of()
                                    .key("product1")
                                    .name(LocalizedStringBuilder.of().values(["de-DE" : "produkt1"]).build())
                                    .slug(LocalizedStringBuilder.of().values(["de-DE": "PRD1"]).build())
                                    .productType(ProductTypeKeyReferenceBuilder.of().key("default").build())
                                    .description(LocalizedStringBuilder.of().values(["de-DE": "sehr tolles Produkt2"]).build())
                                    .build()]
                ).build()
        def response1 = client.withProjectKeyValue(projectKey).products()
                .importSinkKeyWithImportSinkKeyValue("products")
                .post(productRequest)
                .executeBlocking()
                .getBody()
  1. Error happens after executing response1

Expected behavior
UNRESOLVED should also be included in the returned enum type or the state machine has to be updated so that the product request never returns UNRESOLVED state

What is the best way to test http client ?

I am implementing a service using the new SDK but having a hard time to test (unit test) the results? What is your suggestion,
I could not find any examples in the repository.

Below example I could not pass the middlewares, so it's failing in the Auth middleware, I managed to write a test with using the fake client below :

public class Scenario {

    @Test
    public void fetchSample_WithUnexpectedException_ShouldFailWithConcurrentModificationException() {
        final VrapHttpClient fakeHttpClient = new FakeHttpClient<>(409, "");

        final ByProjectKeyRequestBuilder requestBuilder = ApiFactory
            .create(fakeHttpClient,
                ClientCredentials.of().withClientId("your-client-id")
                                 .withClientSecret("your-client-secret")
                                 .withScopes("your-scopes")
                                 .build(),
                ServiceRegion.GCP_EUROPE_WEST1.getOAuthTokenUrl(),
                ServiceRegion.GCP_EUROPE_WEST1.getApiUrl())
            .withProjectKey("projectKey");

        Throwable throwable = requestBuilder
            .products()
            .withKey("key")
            .get()
            .execute()
            .handle((response, exception) -> exception).join();

        // but was an instance of: <io.vrap.rmf.base.client.oauth2.AuthException>
        Assertions.assertThat(throwable)
                  .hasCauseInstanceOf(ConcurrentModificationException.class);
    }

    private static class FakeHttpClient<T> implements VrapHttpClient {
        private final T response;
        private final int statusCode;

        private FakeHttpClient(
            final int statusCode, @Nonnull final T response) {
            this.statusCode = statusCode;
            this.response = response;
        }

        private FakeHttpClient(@Nonnull final T response) {
            this(200, response);
        }

        @Override
        public CompletableFuture<ApiHttpResponse<byte[]>> execute(ApiHttpRequest request) {
            return CompletableFuture.completedFuture(
                new ApiHttpResponse<>(statusCode, null, getBody()));
        }

        private byte[] getBody() {
            byte[] body = null;
            try {
                body = VrapJsonUtils.getConfiguredObjectMapper().writeValueAsBytes(response);
            } catch (JsonProcessingException e) {
                e.printStackTrace();
            }
            return body;
        }
    }
}

Is it possible to provide equals methods for the types.

It's hard to assert types as equals methods are not implemented, what is the best practice for testing types?

What's the suggestion here? I would expect an equals but not sure how you might do it with code generation without
using reflection 🤔

   @Test
    public void equals_withSameData_shouldReturnTrue () {
        Map<String, String> values = new HashMap<>();
        values.put("en", "val");

        Assert.assertEquals(
            ProductChangeNameActionBuilder.of().name(LocalizedStringBuilder.of().values(values).build()).build(),
            ProductChangeNameActionBuilder.of().name(LocalizedStringBuilder.of().values(values).build()).build());
    }

LocalizedString is not easy to construct.

I would like to have a better builder pattern (fluent) same as other builder methods for the LocalisedString.

Current

final LocalizedStringImpl slug = LocalizedString.of();
oldSlug.setValue("en", "slug"); // returns void

// then I could use the slug.

Describe alternatives you've considered

// so I expect builder methods with allows me to specify as below.
LocalizedStringBuilder.of().value(Locale.ENGLISH, "value").value(....).build();

I would also expect the value will check if the locale already exists.

DefaultApiRoot doesn't seem to be in the maven repo

Using the following maven dependency definition

<dependency>
            <groupId>com.commercetools</groupId>
            <artifactId>import-api-default</artifactId>
            <version>1.0.0-20191212134215</version>
            <type>pom</type>
</dependency>

The class for DefaultApiRoot does not seem to be included in the maven jar file and is therefore not accessible.

Create examples for training of Java 2

Why: help training team be successful on generated SDK in Java.

AC

Tasks

Target 2nd November.

Adding an attribute to existing product type

Describe the bug
After the initial creation of the product type, there might be a requirement to add a new optional attribute to it(which will later be used to update the products accordingly). Currently the API does not seem to allow such a change.

To Reproduce
Consider the following integration test in groovy :

def productTypeRequest = ProductTypeImportRequestBuilder.of()
                            .resources([ProductTypeImportBuilder.of()
                                                .key("default")
                                                .name("default")
                                                .description("another field")
                                                .attributes([AttributeDefinitionBuilder.of()
                                                                     .name("color")
                                                                     .label(CommerceToolsProductWriter.createLocalizedString("de", "Farbe"))
                                                                     .isRequired(false)
                                                                     .type(AttributeSetTypeBuilder.of()
                                                                             .elementType(AttributeTextType.of())
                                                                             .build())
                                                                     .build(),
                                                             AttributeDefinitionBuilder.of()
                                                                     .name("size")
                                                                     .label(CommerceToolsProductWriter.createLocalizedString("de", "Größe"))
                                                                     .isRequired(false)
                                                                     .type(AttributeSetTypeBuilder.of()
                                                                             .elementType(AttributeTextType.of())
                                                                             .build())
                                                                     .build()
                                                ])
                                                .build()]).build()

def response1 = client.withProjectKeyValue("...").productTypes()
                    .importSinkKeyWithImportSinkKeyValue("producttypes")
            .post(productTypeRequest)
            .executeBlocking()
            .getBody()
// wait for a while
def response2 = client.withProjectKeyValue("...").productTypes()
                    .importSinkKeyWithImportSinkKeyValue("producttypes")
            .importOperations()
            .get().executeBlocking().getBody()

at first, both the response1 and response2 will be completed successfully, afterwards if we do it again, but with an extra attribute weight :

def productTypeRequest = ProductTypeImportRequestBuilder.of()
                            .resources([ProductTypeImportBuilder.of()
                                                .key("default")
                                                .name("default")
                                                .description("another field")
                                                .attributes([AttributeDefinitionBuilder.of()
                                                                     .name("color")
                                                                     .label(CommerceToolsProductWriter.createLocalizedString("de", "Farbe"))
                                                                     .isRequired(false)
                                                                     .type(AttributeSetTypeBuilder.of()
                                                                             .elementType(AttributeTextType.of())
                                                                             .build())
                                                                     .build(),
                                                             AttributeDefinitionBuilder.of()
                                                                     .name("size")
                                                                     .label(CommerceToolsProductWriter.createLocalizedString("de", "Größe"))
                                                                     .isRequired(false)
                                                                     .type(AttributeSetTypeBuilder.of()
                                                                             .elementType(AttributeTextType.of())
                                                                             .build())
                                                                     .build(),
                                                             AttributeDefinitionBuilder.of()
                                                                     .name("weight")
                                                                     .label(CommerceToolsProductWriter.createLocalizedString("de", "Gewicht"))
                                                                     .isRequired(false)
                                                                     .type(AttributeSetTypeBuilder.of()
                                                                             .elementType(AttributeTextType.of())
                                                                             .build())
                                                                     .build()
                                                ])
                                                .build()]).build()

def response1 = client.withProjectKeyValue("...").productTypes()
                    .importSinkKeyWithImportSinkKeyValue("producttypes")
            .post(productTypeRequest)
            .executeBlocking()
            .getBody()
// wait for a while
def response2 = client.withProjectKeyValue("...").productTypes()
                    .importSinkKeyWithImportSinkKeyValue("producttypes")
            .importOperations()
            .get().executeBlocking().getBody()

Then reponse2 will contain the following error : The given attributes must be equal to the type attributes.

Expected behavior
The extra attribute definition should be imported without errors, or there has to be another way to introduce a new attribute to the product-types/products.

Release generated JAVA SDK as stable.

  • sync with Matthias for knowledge on generated Java SDK
  • add user agents if required.
  • make first release from automated process.
  • Make sure to have automated process for next release.

Note
For now the scope of release is only Bintray.

Evaluate rate limitting

While in general, we shouldn't force the SDK user to a limited rate, It would be useful to pull back on some errors (for example 503), since retries in that case would just make the situation worse.

ApiMethod refactoring

The request builders using a common ApiMethod class. To have better generic support the ApiMethod has to be declared abstract and the methods for execution have to added.

To avoid having side effect the ApiMethod and inheriting classes will be designed as immutable

Why UpdateActions types are not implementing the UdpateAction interface ?

public interface UpdateAction {
@NotNull
@JsonProperty("action")
public String getAction();
public void setAction(final String action);

I would expect the interface is implemented for the other update actions, so it could be used for generic implementations 🤔 I also could not reason the need for helper methods like withProductUpdateAction 🤔

public interface ProductUpdateAction {
@NotNull
@JsonProperty("action")
public String getAction();
default <T> T withProductUpdateAction(Function<ProductUpdateAction, T> helper) {
return helper.apply(this);
}
}

Validation failure on subsequent product import request with the same product key

Describe the bug
if the same ProductImportRequest is sent multiple times with the same product key, regardless of whether any of the properties are updated; it is generating the following validation error:
“Can not remove the variant [ID:1] for XXX since it's the master variant”

To Reproduce
Steps to reproduce the behavior:

  1. The following pseudo-code in Groovy can be used to create a product with the "default" product type(already exists)
     def productRequest = ProductImportRequestBuilder.of()
                .resources([ProductImportBuilder.of()
                                    .key("product1")
                                    .name(LocalizedStringBuilder.of().values(["de-DE" : "produkt1"]).build())
                                    .slug(LocalizedStringBuilder.of().values(["de-DE": "PRD1"]).build())
                                    .productType(ProductTypeKeyReferenceBuilder.of().key("default").build())
                                    .description(LocalizedStringBuilder.of().values(["de-DE": "sehr tolles Produkt"]).build())
                                    .build()]
                ).build()
        def response1 = client.withProjectKeyValue(projectKey).products()
                .importSinkKeyWithImportSinkKeyValue("products")
                .post(productRequest)
                .executeBlocking()
                .getBody()
        def response2 = client.withProjectKeyValue(projectKey).products()
                .importSinkKeyWithImportSinkKeyValue("products")
                .importOperations()
                .get()
                .executeBlocking()
                .getBody()
       def variantRequest = ProductVariantImportRequestBuilder.of()
                .resources([ProductVariantImportBuilder.of()
                                    .key("product-var1")
                                    .sku("12345")
                                    .product(ProductKeyReferenceBuilder.of().key("product1").build())
                                    .isMasterVariant(true)
                                    .build()]
                ).build()
        client.withProjectKeyValue(projectKey).productVariants()
                .importSinkKeyWithImportSinkKeyValue("variants")
                .post(variantRequest)
                .executeBlocking()
                .getBody()

  1. If the product does not exist, running it will successfully create the product with one variant.
  2. Running it again, when the description of the product changes(or when nothing changes) will result in response1 to be ACCEPTED and response2 to have VALIDATION_ERROR with the following error :
    “Can not remove the variant [ID:1] for XXX since it's the master variant”

Expected behavior
There should be no error, and the product description should change upon subsequent requests.

Screenshots
image

Getting detailed information about InvalidJsonInput errors(question)

when trying to execute the following test code :

   def productTypeRequest = ProductTypeImportRequestBuilder.of()
                            .resources([ProductTypeImportBuilder.of()
                                                .key("default")
                                                .name("default")
                                                .description("some type")
                                                .build()]).build()

    def response1 = client.withProjectKeyValue(PROJECT_KEY).productTypes()
            .importSinkKeyWithImportSinkKeyValue("producttypes")
    .post(productTypeRequest)
    .executeBlocking()
    .getBody()

    def response2 =  client.withProjectKeyValue(PROJECT_KEY).productTypes()
            .importSinkKeyWithImportSinkKeyValue("producttypes")
    .importOperations()
    .get().executeBlocking().getBody()

(client and import-sinks are all successfully created) response1 indicates that the request is ACCEPTED, however response2 gives the following error :
image

Is there a way to get slightly more information about which part of the request is false or missing?

Not working code in Readme.md

Describe the bug
The following code is not working in Readme.md.
CategoryDraft categoryDraft = CategoryDraftBuilder.of()
.name("name")
.slug("slug")
.description("description")
.externalId("random-id")
.key("random-key")
.metaDescription("metaDescription")
.orderHint("hint")
.build();
To Reproduce
Steps to reproduce the behavior:

  1. Copy code above or from your Readme.md
  2. Paste it to your favorite IDE
  3. See error

Expected behavior
No error in compile time should be occur.

Screenshots
Use the following screenshot.
image

Desktop (please complete the following information):

  • OS: Windows
  • Browser Chrome
  • Version Latest stable

Additional context
Please, provide working examples for your SDK.
Thank you so much!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.