How to pass query parameter to Sling model exporter - aem

I have to implement one API where the API should export the JSON data. For example, there is one container component and many child components. Lets suppose, container component is holding the country and child component is strong different states and its population etc.
So the responsibility of the API is to search the population based on the state name or other query parameter.
One of the option I am thinking about using Sling model exporter because I do not have to write Sling servlet and it is easy to export the child components as json but the problem is, I could not find an option to pass request parameter to Sling model.
For example http://some.com/country/jcr:content/parent-component.model.json will give the result of child components but here how can I pass request parameter to this model endpoint for a specific state?
I know its possible to create a sling servlet but is it possible to do it using Sling model exporter?

You can inject the SlingHttpServletRequest in your model, and get the request parameter there from. Either in the getters or in your #PostConstruct method.
But there are no injectors available for the RequestParameters. This was for security reasons. So if you just use #Inject, then it just cannot happen that unwanted values are injected.
PS: The #RequestAttribute injector is for request-attributes, which are NOT query parameters.

I did face exactly the same issue and looks like the sling model exporter is dropping the parameters however I was able to solve this using request.getHeader("referrer") which gives us the complete URL including the parameters from which we can extract parameters.

Related

How to validate multiple Typo3 action parameters in combination?

The Typo3 documentation describes #Validate annotations which can be used to validate parameters for a single controller action:
https://docs.typo3.org/m/typo3/book-extbasefluid/master/en-us/9-CrosscuttingConcerns/2-validating-domain-objects.html
However, it is only described how to add a custom validator for a single parameter. It is possible to add multiple validation annotations, but then again each of them can validate just a single parameter, not multiple parameters in combination.
First question: It is possible to add a validator which checks multiple parameters, or even all parameters, of a specific controller action?
Of course the obvious workaround is to combine multiple arguments in a single argument, using e.g. an array or an object. But this is especially annoying if the arguments themselves are already (independent) model objects.
Second question: If the answer to the first question is "it's impossible", what is the recommended way to combine the arguments of a controller action?
(e.g.: Should one use an array? That seems to be not preferred in Typo3 due to the lack of type safety and other features. Should one create a class? But which kind of class would that be? A Utility class? A Model class? But that model class would then need suppressed persistence? This seems to be all messy.)
I'm using version 9.5 of Typo3, but if things are different in version 10, that would be interesting as well.
To the best of my knowledge I suggest using a data transfer object (DTO) for this purpose.
If your models have to be validated in combination, but do not belong to any other entity, combining them in a DTO is probably the best way to go. Consequently the validation logic is then clustered in a single validator.
See also this blog post about DTOs: https://usetypo3.com/dtos-in-extbase.html

Adding global session filter to repository entity

I need to add a global filter to a repository entity, i.e. it has to be applied everywhere this entity is accessed on Application service layer. My filter contains two conditions. Whereas adding the first condition, which depends on a constant, is easy and applied in OnModelCreating using HasQueryFilter, I have no idea how to apply automatically the second one, which depends on the currently selected (or default) UI language.
Use dependency injection via constructor in your DbContext class. Set the currently selected UI language inside the class implementing the interface. Use the injected implementation in the OnModelCreating method to apply the filter globally with .HasQueryFilter() method like you normally would.
If you're using something like a .NET Core API, you could build a middleware that determines the language of the current incoming request. I guess the same will work for MVC too.

Pushing OData filters down through layers

I have a working project with the following layers:
DataAccess - The project hits multiple DBs and web services. This layer defines the interfaces to each of them. It exposes the native types for each source (EF types for DBs, SOAP-defined types for web services, etc.). Let's say it exposes an EFProject and SoapProject.
Repository - This layer stiches results from the various sources to form a single entity, and exposes it. Let's call this ModelProject
Service - Adds REST attributes to to the entity (action links, etc.). This exposes a ProjectDTO.
WebApi - The controller spits out the ProjectDTO directly.
I'm trying to implement OData, specifically to page the results of very large queries. I've read a lot of examples, but they all seem to expose the source objects directly, and then map them to the final DTOs in the controller.
I would like to somehow push the ODataQueryOptions down to the Repository. This would allow me to keep the existing structure, and pass the query logic down to SQL. I understand that, because the ODataQueryOptions reference the ProjectDTO type, they can't be applied until an object of that type is available. Is there a way to "translate" the ODataQueryOptions from one type to another? Is there another way of doing this that I'm not aware of?
It is able to change the ODataQueryOptions, and such actions in a controller are for you to handle the options yourself:
public IQueryable Get(ODataQueryOptions queryOptions)
public IQueryable Get(int key, ODataQueryOptions queryOptions)
Here is a sample about this:
https://aspnet.codeplex.com/SourceControl/latest#Samples/WebApi/OData/v4/ODataQueryableSample/Controllers/OrdersController.cs .
For your reference, the source code of ODataQueryOptions is: https://aspnetwebstack.codeplex.com/SourceControl/latest#src/System.Web.OData/OData/Query/ODataQueryOptions.cs
Is there a way to "translate" the ODataQueryOptions from one type to another? Is there another way of doing this that I'm not aware of?
There is a way to actually translate the IQueryable<DomainModel> to IQueryable<DtoModel>.
I've done something similar in the past by leveraging AutoMapper's projection functionality. By calling the Project<TSource>/To<TTarget> methods, you can change an IQueryable that points to your domain models to another IQueryable that targets the Dto models, without actually executing it.
This means that you can now perform any OData operations on the DTO level and they will transfer through projection to the DAL layer into EntityFramework and SQL. In a scenario like this, there shouldn't be any need to manually handle the query logic so you can just use [EnableQuery] on the API route and let OData do its thing on the resulting IQueryable<DtoModel>.
I used this very successfully in one of the projects I worked on: as long as you rely just on AutoMapper projection to convert the types, it should work fine.
Granted, you can't do a lot of fancy mapping that way. The project methods will not be able to apply all kinds of mappings that you create, so I recommend checking the documentation on that front.
You also have to keep in mind that the original IQueryable needs to be exposed outside of the repository layer for this to work properly, otherwise the query will be executed too early. Some people will find that a boundary violation and will advocate for materializing the query inside the repository layer, but I don't have an issue with that particular aspect.

What are the differences of using value proxies for my entities instead of entity proxies?

So far i understand that i will have no more need to define an #version field in my entitites and no more need to use an entity locator. And for value proxies i will have to usenormal editors. Any other diffrences, advantages, disadvantages? What about in the context of using request factory in conjunction with spring
The main difference is that with EntityProxy, the client can send a diff of changes rather than the entire object graph. This is made possible because EntityProxys have an identity, so the server can fetch the identity from the datastore and then apply the diff/patch sent from the client, and only then the entity will be passed to your service methods.
With ValueProxy you basically have an equivalent of GWT-RPC: the object is reconstructed from scratch on the server, and not associated with your datastore (in the case of JPA for instance, it's not attached to the session). Depending on your datastore API, this can make things more complex to handle in your service methods.
Other than that, you'll also lose the EntityProxyChange events.

Transfering OWL data from client to server using GWT

I am working on a web application which is being developed using GWT. I am also using OWL ontologies and Jena framework to structure semantic contents in the application.
A simple function in the application would be getting some data from the user and send it to the servers side to be stored as a data graph using the ontology. I suppose one way would be to store the data as java class objects equivalent to the ontology classes and send them using the GWT async communication. To convert OWL classes to java, I used Jastor.
My question is that after the server receives the java class, is it possible to easily convert is to an OWL individual and add it to the data graph, using the functions of Jena and/or Jastor? For instance in the server side interface implementation we call something like this:
Public void StoreUser (User userObj) {
//User: a Jastor created java class. userObj is instantiated using the user data on the client side.
OntModel ontModel = ModelFactory.createOntologyModel(OntModelSpec.OWL_DL_MEM);
//Open the ontology here using inputstream and ontModel.read!
Individual indiv = (Individual) userObj.resource();
//Add the individual to the model here! }
Unfortunately I wasn't able to find any Jena function that can add an existing individual to the model.
Would you suggest another way to pass the ontology data to server side and store it, rather than using Jastor created classes (for instance using an XML file)?
Thanks for your help
There are two parts to the answer. First, an Individual is a sub-class of a Jena Resource, which is definitely something that you can add to a model. However, individual resources, or properties or literals are not stored in a Model. A Model stores only triples, represented as Statement objects in the Java API. So to add some resource to a model, you have to include it in a triple.
In Jena, an individual is defined as a subject of a triple whose predicate is rdf:type and whose object is not one of the built-in language classes. So if you have:
ex:my_car rdf:type ex:Ferrari .
ex:Ferrari rdf:type owl:Class .
(note: this example is entirely fictitious!), then ex:my_car would be an individual, but ex:Ferrari would not (because OWL Class is a built-in type). So, to add your individual to your model, you just need to assert that it is of some type. Since I don't know GWT and don't use Jastor, I can't say whether the type association that is normally part of a Jena Individual is retained after serialization. I suspect not, in which case you'll need to have some other means of determining the type of the individual you want to add, or use a different predicate than rdf:type to add the resource to the the Model.
All that said, personally I probably wouldn't solve your problem this way at all. Typically, when I'm working with client-side representations of server-side RDF, I send just the minimal information (e.g. URI and label) to the client as JSON. If I need any more data on a given resource, I either send it along with the initial JSON serialization, or it's just an Ajax call away. But, as I say, I don't use GWT so that advice may not be of any use to you.