commercetools / nodejs

Everything related to the Node.js ecosystem for the commercetools platform.
https://commercetools.github.io/nodejs/
MIT License
75 stars 70 forks source link

Where are docs for the request-builder? #1195

Closed StarpTech closed 5 years ago

StarpTech commented 5 years ago

Hello, my company is evaluating commercetools. While the documentation looks good on the first sight, I can't find any useful node.js examples. If you look at the docs for the request-builder here I can't find examples which illustrate the full capabilities of the interface. I'm looking for an api documentation for the SDK.

It takes more time to go through the sourcecode and the docs rather to use the http api directly. Do I miss something?

Could you answer me following questions?

emmenko commented 5 years ago

Hi, thanks for reaching out to us.

The request builder is just a helper library to construct the request URI (mostly query parameters) using a chaining syntax. Depending on the complexity of your query request it might be helpful to use it but you don't necessarily need to in order to make API requests.

The documented feature capabilities (query, queryExpand, search, etc) will expose specific methods that you can use and chain together when building the request URI. Those methods will then map to the supported query parameters of the commercetools HTTP API. So it depends on the HTTP API that you want to send requests to, which query parameters are supported. For example, the where method will be used to build query predicates.

With that said,

I'm looking for an api documentation for the SDK.

Do you mean how to send API requests with the JS SDK? Here and here are some example on how you can get started.

It takes more time to go through the sourcecode and the docs rather to use the http api directly. Do I miss something?

If something is missing or confusing you, please let us know so that we can improve the documentation and make it easier to get started.


Could you answer me following questions?

Sure, although those questions are more related on how to use the HTTP API.

How can I fetch a product only by a matched property e.g slug ?

You need to use the query predicate syntax, for example:

const uri =
  `/{projectKey}/product-projections?where=${encodeURIComponent(`slug(en="${mySlug}")`)}`;

Specifically for products, you can also use the search API that has better search capabilities.

How can I fetch the count of products refer to a category?

If you want to know the number of products in a specific category, you can use a query predicate and get the total value of the paged query result.

const uri =
  `/{projectKey}/product-projections?where=${encodeURIComponent(`categories(id="${categoryId}")`)}`;

// in the response payload
const totalProductsInCategory = response.total;

Alternatively you can use the GraphQL API to query for number of products for categories

image

How can I fetch a product by its language?

You mean the localized fields like name, description, etc? If so, it's the same principles as above.

How can I use projection in order to receive only selected properties?

The REST API does not support that, you would need to use GraphQL queries in order to get only the properties you need.


Hopefully this will help you further with your tasks. Again, if something is not clear/missing to you, let us know so that we can improve it.

Thanks

StarpTech commented 5 years ago

Hi @emmenko, this helps a lot! Thank you very much for the links and examples! I didn't know that graphql is supported.

StarpTech commented 5 years ago

Hopefully this will help you further with your tasks. Again, if something is not clear/missing to you, let us know so that we can improve it.

In the beginning, I had completely different expectations from that SDK. I expected a more fluent interface so that I don't have to care about the whole architecture. It's very time-consuming to go through the complete HTTP API and to understand custom DSL's as the query syntax slug(en="${mySlug}").I also wish more SDK specific tutorials and examples for common use-cases. Due to the diversity of the documentation (different styles for code-examples, interface description, themes, many entry points) and technologies, it's hard to keep it simple in my mind. It would extremely help to unify it as stripe do. https://stripe.com/docs/api/pagination?lang=node (In best case it's possible to fire queries right in the browser) another point would be great to provide autointellisense for the custom filter and where syntax.

StarpTech commented 5 years ago

A very good example is this: I'm looking for a solution to add a product to an anonymous cart. I look at the cart API docs here.

How should the JSON body look like?

    const result = await this.client.execute({
      // creates a cart that is tied to the logged in anonymous token
      uri: `/${PROJECT_KEY}/me/carts/${cart.id}`,
      method: 'POST',
      body: {
        actions: ['addLineItem']
        // should the LineItemDraft included here?
        ...LineItemDraft
      }
    });
StarpTech commented 5 years ago

I found it by crawling through the docs :smile:

"actions": [{
    "action": "addLineItem",
    "productId": "<product-id>",
    "variantId": 1,
    "quantity": 1
  }]
emmenko commented 5 years ago

I expected a more fluent interface so that I don't have to care about the whole architecture.

Could you be a bit more specific about what you are referring to? Do you mean the JS SDK specifically (its architecture, etc), the documentation website, or something else?

It's very time-consuming to go through the complete HTTP API and to understand custom DSL's as the query syntax

I understand and I think we can make it easier to start with it by providing more tutorials/examples.

another point would be great to provide autointellisense for the custom filter and where syntax.

I'm afraid that it would require a lot of effort to achieve something like that and we currently don't have the resources to invest in it. One of the tricky aspects of it is that while the DSL format is the same across the different APIs, the query predicates differ from API to API (e.g. slug is available only in products and categories). So I think it would be more useful to learn the mechanics of the DSL and apply them to the specific APIs.

As a side note, in the Merchant Center UI application we have built a predicate parser to validate the syntax of the DSL (which we use for the discounts builder). Maybe we can look into moving it to an SDK package to use it as a linter or something similar.

I also wish more SDK specific tutorials and examples for common use-cases. Due to the diversity of the documentation (different styles for code-examples, interface description, themes, many entry points) and technologies, it's hard to keep it simple in my mind. It would extremely help to unify it as stripe do.

Yes we are aware of that and we are working on a new documentation website / experience (cc @nkuehn @celeste-horgan)

How should the JSON body look like?

The actions field is an array of update actions, which are JSON objects. Each action always contains the field action plus fields related to the action itself. For example, for https://docs.commercetools.com/http-api-projects-me-carts#add-lineitem

{
  "actions": [
    {
      "action": "addLineItem",
      "productId": "123",
      "variantId": 1,
      // ...
    }
  ]
}

Do you which is this case some JSON examples or what was not clear about it?

StarpTech commented 5 years ago

Could you be a bit more specific about what you are referring to? Do you mean the JS SDK specifically (its architecture, etc), the documentation website, or something else?

I'm talking about the Javascript SDK. In my opinion the architecture is too low level. I wish the api would communicate through code e.g

import { eq } from 'filtering'
import { query } from 'query-predicate'
import { ProductEntity } from 'resources'

// fluent api
client().products.getAll().page(5).limit(10).filter(
  eq(ProductEntity.variants.foo, "bar")
  query(`not (${ProductEntity.name} = "Peter" and age < 42)`)
).count()

// projection
client().products.getById("<id>").project({
  name: 1,
  'variants.color': 1
})

// filtering
client().products.where(
  eq(ProductEntity.id, "<id>")
).remove()

// entity creation
client().products.create({
  ..data
})

// cursor support
const cursor = await client().products.filter(
  eq(ProductEntity.variants.foo, "bar")
)
cursor.next()
cursor.all()
// ....

I know GraphQL will provide a more pleasant experience due it's flexibility but it's in beta and it's a complete new stack.

It would be also great to have support on my fingertips :smile: I mean at least jsdocs or typescript types should be provided, the flow types are also not complete but that's a different case because the majority of the javascript community doesn't use flow.

I'm afraid that it would require a lot of effort to achieve something like that and we currently don't have the resources to invest in it. One of the tricky aspects of it is that while the DSL format is the same across the different APIs, the query predicates differ from API to API (e.g. slug is available only in products and categories).

Yes, that's not so trivial but it is really required in long term. I will have a look at the syntax checker, this could be quite useful. I also noticed that fields aren't validated in my condition. It would be great when the api would be more verbose when I have unknown / invalid fields in my conditions. I'm not talking about custom fields.

The actions field is an array of update actions, which are JSON objects. Each action always contains the field action plus fields related to the action itself. For example, for https://docs.commercetools.com/http-api-projects-me-carts#add-lineitem

Yes, after reading it more in detail you're right. A single example after each operation would be mindblowing :smiley:

emmenko commented 5 years ago

I'm talking about the Javascript SDK. In my opinion the architecture is too low level

Right, the core JS SDK was built with simplicity in mind to be flexible and extensible, based on our past experiences. You can read more about the design architecture here.

We have a couple of packages that help building the requests, like api-request-builder and sync-actions, but we can definitely have more "higher-level" packages that will provide more features for building requests. I think we might even go a step further and see if we can generate the code based on e.g. graphql schema.

So there is room for improvements and we just need to see how we can prioritize this and invest time on it (which is not really up to me as I am no longer a core maintainer of those packages).

I mean at least jsdocs or typescript types should be provided, the flow types are also not complete but that's a different case because the majority of the javascript community doesn't use flow.

Yes we are also thinking about this topic and typescript might be a better option as it's more used and has better support tooling. Again, it's at the end up to the team that maintains those packages to decide that, as it's also a matter of people being comfortable working with types.

Anyway, thanks for your valuable feedback, there are a lot of good points that we should look into!

StarpTech commented 5 years ago

Thank you for your feedback as well!

nkuehn commented 5 years ago

PS after it's closed: @StarpTech thanks for taking all the time to give specific feedback! And thanks @emmenko for doing a lot of the support team's job!

It'll take a bit of time until all the examples will pop up on the reference documentation, but we're on it. In the meanwhile you can also take a look at the examples we've now added to the (still inofficial, but pretty complete) API Reference specification repo: https://github.com/commercetools/commercetools-api-reference/tree/master/examples


It would be great when the api would be more verbose when I have unknown / invalid fields in my conditions.

Could you be so nice to create a support issue with a specific example? It's reaching the platform product teams better that way. If they close it, don't worry - the input is still kept.