Integrating customised APIs in Spartacus Storefront - spartacus-storefront

our Hybris instance has some custom REST APIs, for example the addEntry. This version of the API requires an extra boolean parameter in the payload, let's call it fooBar.
Here’s an example of payload:
{"quantity": 1, "product": {"code": "1234567"}, "fooBar": false}
Here’s the list of what we’ve done in order to have this extra parameter in the service that actually made the http call:
Overridden the AddToCartComponent
Modified the addToCart method passing the fooBar parameter to the addEntry method of the E2ActiveCartService
Extended ActiveCartService in E2ActiveCartService
Modified the addEntry method passing the fooBar parameter to the addEntry method of the E2MultiCartService
Extended MultiCartService in E2MultiCartService
Modified the addEntry method passing the fooBar parameter to the payload of the E2CartAddEntry action
Implemented a copy of the CartAddEntry action (called E2CartAddEntry) with its own type (i.e. '[E2-Cart-entry] Add Entry')
Implemented a new CartEntryEffects (called E2CartEntryEffects) that listens to the E2CartAddEntry action
Created a second effect called processesIncrement$ that dispatches the CartActions.CartProcessesIncrement action (we did this because the E2CartAddEntry cannot extends the EntityProcessesIncrementAction class)
Copied the addEntry$ effect from the original CartEntryEffects adding the fooBar parameter to the add method of the E2CartEntryConnector
Extended CartEntryConnector in E2CartEntryConnector
Modified the add method passing the fooBar parameter to the add method of the E2CartEntryAdapter
Extended CartEntryAdapter in E2CartEntryAdapter
Modified the abstract add method adding the fooBar parameter
Created E2OccCartEntryAdapter that extends OccCartEntryAdapter and implements E2CartEntryAdapter
Modified the add method adding fooBar to the payload of the POST call made from HttpClient
Finally, in our main module we changed the providers:
[
{ provide: ActiveCartService, useClass: E2ActiveCartService },
{ provide: MultiCartService, useClass: E2MultiCartService },
E2CartEntryEffects,
{ provide: CartEntryConnector, useClass: E2CartEntryConnector },
{ provide: E2CartEntryAdapter, useClass: E2OccCartEntryAdapter },
]
This solution seems to work but we think that's pretty complex for a relatively simple change and we would like to know if our approach is correct or if there is a better, cleaner way.
Kind regards

Currently, it seems like the correct way for this specific use case.
You did not exactly specify what fooBar is used for, but I assume, it's used and can be toggled inside the top-level layer (in UI component) and has to be passed by all other layers down to the adapter.
On the other hand, if for example, fooBar would just be a property of the Product model, then it would be a matter of extending only the 'Product' model + the changes where it's important (component, adapter), and all other places could be left intact (would just pass extended model).
Can you please give some more context of the required change, so we can better understand it, and make it easier in the future?
In near future, we are considering unifying the payload of our facade services through all the layers in Spartacus, so adding more context to any core logic will be much simplified (basically will come down to the second example, regarding extending the Product model).

Related

How I can add condition with context attribute in Orocommerce API processor?

In Oro docs I found that I can add condition to run api processor only when certain attribute in context object exists/not exists:
But I can't understand what is context attribute. Is it not the same as underlying entity attribute?
I tried to add this to processor condition, but it seems always not exist even if it is in the context entity:
client_bundle.api.fill_order_line_item_price:
parent: oro_order.api.fill_order_line_item_price
tags:
- { name: oro.api.processor, action: customize_form_data, event: post_validate, requestType: '!frontend', class: Oro\Bundle\OrderBundle\Entity\OrderLineItem, fromExternalSource: exists, priority: -20 }
How can I use this condition to run processor only for some entities and not interfering into processor logic?
Context is an object that is used to store the input and output data and share data between processors.
Here is the documentation about the Context class methods: https://doc.oroinc.com/backend/api/actions/#context-class.
There are many useful entity-related attributes in it.

Array vs hashmap in the request body of a (POST) rest API

I'm building an application that involves a frontend (javascript browser-based client) and a backend (a Java-based service).
For one of the APIs (POST method) that will be called from the browser to the backend service (upon filling a form in the frontend), I'm planning on passing the request body (JSON) as follows
{
data: [
{
"fieldId": "123sda121231",
"fieldValue": "some_user_input_for_field_1",
},
{
"fieldId": "223sda121231",
"fieldValue": "some_user_input_for_field_2",
},
{
"fieldId": "323sda121231",
"fieldValue": "some_user_input_for_field_3",
}
]
}
However, now I'm confused and I'm wondering if I should probably do it the following way.
{
data: {
"123sda121231": "some_user_input_for_field_1",
"223sda121231": "some_user_input_for_field_2",
"323sda121231": "some_user_input_for_field_3"
}
}
Can someone help me understand which would probably be the better way to structure this request body?
P.S. FieldIds are predefined in the backend.
Usually, in design problems, there is no single correct answer, a solution can be good for one problem and it can be bad for another problem.
I prefer the approach of creating an array of Object ( lets call our class as FieldData). In above example, FieldData class is:
public class FieldData{
String fieldId;
String fieldValue;
}
The benefits I see with this approach:
The response is very flexible, in future we can easily add one more field in the FieldData object without breaking the API contract.
The response sent is easier for the client to understand, the client will know that fieldId contains the id of the field and fieldValue contains its value. Whereas in the case of a map this logic is not explicitly available.
Also in your case, if in scenario 1, the field1 value is somehow for 2 or more null, then it might be override other values.
Also applies to scenarios where you have same key, but different values. This might create unnecessary bugs.
OOPS suggest data encapsulation so creating a class in JAVA to handle request separately is good practise as well as better testable.
As already pointed out by #Deepak, also extensible.

RxJS Is there a way to make ajax get request with params without building url

I am having trouble passing params to ajax get request.
Let's suppose i have to pass params {category: 'cat', type: 'type', searchKey: 'key' } to the url /search and I have the code below:
action$.ofType('QUERY')
.debounceTime(500)
.switchMap(action =>
ajax.get('/search', {//pass some parameters},)
.map(result => ({
type: 'FETCH_SUCCESS',
payload: result.response,
})),
As I am new to RxJs, Please suggest me the right way of doing this.
While it is technically permissible to provide a request body (and corresponding Content-Type header like application/x-www-form-urlencoded) for GET requests, nearly all servers assume GET do not contain one. Instead, POST (creation of a document) or PUT (updating a document) is used when a body is neccesary.
However, if what you're asking for is simply regular old query params, that's pretty normal but there is no built-in support in RxJS for converting an Object to a query string--mostly because there is no official spec on how complex objects/arrays should be serialized so every server has notable differences once you do more than simple key -> value.
Instead, you just include them in the URL. I realize you said "without building url" but the lack of a spec means RxJS will likely never add support because it's highly opinionated. You can just manually generate the string yourself or use a third-party utility that has a convention you like.
ajax.get(`/search?query=${query}&something=${something`)
// or using something like https://www.npmjs.com/package/query-string
ajax.get(`/search?${queryString.stringify(params)}`)
If you're interested in further understanding the opinionated nature of query params, consider how you might serialize { foo: [{ bar: 1 }, { bar: 2 }] }. Some might say it should be ?foo[0][bar]=1&foo[1][bar]=2 but I have also seen ?foo[][bar]=1&foo[][bar]=2, ?foo[bar]=1&foo[bar]=2, and other variants. Thing get even more hairy when dealing with duplicates. ?foo=true&foo=false should foo be true or false? (it's an opinion hehe)

REST API Design for Updating Object Graph

I'm designing a REST API and am looking for the recommended best practice for updating object graphs. My question is best explained in an example, so let's say that I have a GET resource as follows:
URI: /people/123
This URI returns an object graph like this:
{
"name":"Johnny",
"country":{"id":100,"name":"Canada"},
"likes":[
{"id":5,"name":"Fruit"},
{"id":100,"name":"Sports"}
]
}
When allowing the API consumer to update this resource, how would you expect the object to be updated via PUT or PATCH? Updating the "name" property is pretty straightforward, but I'm not certain about "country" or "likes", as the consumer can only only change the relationship to other objects and not create new ones.
Here is one way to request the update:
{
"name":"Bob",
"countryId":200
"likeIds":[3,10,22]
}
This update will change the resource to the following:
{
"name":"Bob",
"country":{"id":200,"name":"United States of America"},
"likes":[
{"id":3,"name":"Cars"},
{"id":10,"name":"Planes"},
{"id":22,"name":"Real Estate"}
]
}
This design explicitly and clearly asks the consumer to only update the "IDs" of the "Person", but I'm concerned that the object graph for a PUT/PATCH looks different than the GET, making the API hard to learn and remember. So another option is to request the PUT/PATCH as follows:
{
"name":"Bob",
"country":{"id":100},
"likes":[
{"id":3},
{"id":10},
{"id":22}
]
}
This will yield the same change as the previous update and does not alter the object graph. However, it doesn't make it clear to the API consumer that only the "IDs" can be updated.
In this scenario, which approach is recommended?
In my opinion you should stay with the same structure for both, GET and PUT requests. Why? Because it's quite common to map JSON/XML data into objects, and most (if not all) software that do the actual mapping work best if JSON schema is always the same.
So your webservice should accept a following JSON code:
{
"name":"Joe",
"country":{"id":200,"name":"United States of America"},
"likes":[
{"id":5,"name":"Fruit"}
]
}
However it doesn't have to take into account the country name and may focus only on the country id.

Web API, API Controller and how to update a model?

I'm trying out the API controller in MVC 4 and have a question about best practice when using put, updating an object.
I'm using RavenDB as data storage and I have created a custom MediaTypeFormatter that has a converter of type JsonDynamicConverter that can serialize and deserialize json to a dynamic object. With that said my API controllers Put method looks like this
public void Put(string id, dynamic model) {}
this dynamic object looks sorta like this:
pageModel = {
"id": "pages-2",
"metadata": {
"changed": "2012-02-28T17:16:27.323Z"
},
"parent": {
"id": "pages-1",
"slug": null
},
"children": []
}
so, so far so good but now I need to update my entity with id pages-2.
The UpdateModel does not exist in the ApiController so my question is what is the best/preferred way of doing this?
Simply call RavenDB to load the object with the appropriate ID, make the changes to its contents and persist it again.
No need to worry about any UpdateModel calls. It doesn't apply here.
Be aware of one potential issue since you are including the id in the model. If I sent a PUT command to http://server/controller/pages-3 with that body what would happen? You should probably send me a bad request response or something similar depending on how you want your API to work.
Is there any reason not to be explicit in your parameters? I would define an UpdateModel and take that as parameter instead of the dynamic. Then it also would be able to model validation.
ASP.NET WebApi includes handling of converting from both JSON and XML as input to your controller methods. I'm guessing your combination of custom mediatypeformatter and use of dynamic would be unneccesary in this case, if there is not something I'm missing.