Generate Link To Spring Data Rest Controller - spring-data-rest

I created a REST API with Spring Data Rest that forks fine. It must be possible to clone Projects via the API, so I added a custom #RestController to implement that via POST /projects/{id}/clone.
#RestController
#RequestMapping(value = "/projects", produces = "application/hal+json")
#RequiredArgsConstructor(onConstructor = #__(#Autowired))
public class ProjectCloneController {
private final ProjectRepo projectRepo;
#PostMapping("/{id}/clone")
public EntityModel<Project> clone(#PathVariable String id) {
Optional<Project> origOpt = projectRepo.findById(id);
Project original = origOpt.get();
Project clone = createClone(original);
EntityModel<Project> result = EntityModel.of(clone);
result.add(linkTo(ProjectRepo.class).slash(clone.getId()).withSelfRel());
return result;
}
I am stuck at the point where I need to add a Link to the EntityModel that points to an endpoint provided by Spring Data Rest. It will need to support a different base path, and act correctly to X headers as well.
Unfortunately, the line above (linkTo and slash) just generates http://localhost:8080/636f4aaac9143f1da03bac0e which misses the name of the resource.

Check org.springframework.data.rest.webmvc.support.RepositoryEntityLinks.linkFor

Related

SpringDoc Problem With Methods With Different Query Parameters

I want to do something like create two method for same url pattern with different arguments
#RequestMapping(value = "/searchUser", params = "userID")
public String searchUserById(#RequestParam long userID, Model model) {
// ...
}
#RequestMapping(value = "/searchUser", params = "userName")
public ModelAndView searchUserByName(#RequestParam String userName) {
// ...
}
Spring supports this and it works fine. SpringDoc does not. It creates a single endpoint with 2 parameters.Is this a known issue?
This is supported, but you will have to use swagger #Operation to describe your methods in one path.
One of the OpenAPI 3 rules.
Two POST methods for the same path are not allowed – even if they have different parameters (parameters have no effect on uniqueness).
More details are available on OpenAPI 3 site.
This has been explained here: https://github.com/springdoc/springdoc-openapi/issues/580

How can I combine database calls and REST calls into a single aggegrate?

I am currently developing an API which needs to "extend" its own data (my database) with the data I receive from another API.
I have an inventory class/aggregate in the domain layer with a repository interface which is implemented in the infrastructure layer.
Now I have injected via Dependency Injection both the Entity Manager for my own database as well as the RestClient for the external API.
public class RestInventoryRepository implements InventoryRepository {
#RestClient
#Inject
InventoryRestClient inventoryRestClient;
#Inject
EntityManager eM;
In the repository method implementation I first call the rest client and receive its representation of the requested inventory. I then map it to my inventory class with an Object Mapper. After that I try to get the additional information from my boxInventory by the same inventory id and then append it to the earlier received inventory.
The result is a rather big method which only gets bigger with other additions. My question now is if there is a good practise to handle situations like that? I found the API Composition pattern but I am not sure if I can handle mixing a database with a API the same way as if mixing different APIs.
public Optional<Inventory> findInventoryById(String inventoryId) {
JSONObject inventoryJSON = inventoryRestClient.getInventoryById(inventoryId);
if (inventoryJSON == null) {
return Optional.empty();
}
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerModule(new JavaTimeModule());
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
Inventory inventory = objectMapper.convertValue(inventoryJSON, Inventory.class);
//extracts boxTagInventory
TypedQuery<BoxInventory> typedQuery =
eM.createQuery("FROM BoxInventory WHERE INVENTORY_ID = :inventoryId",
BoxInventory.class);
typedQuery.setParameter("inventoryId", inventory.inventoryId());
List<BoxInventory> resultSet = typedQuery.getResultList();
if(resultSet.isEmpty()){
return Optional.empty();
}
inventory.addBoxInventory(resultSet.get(0));
return Optional.of(inventory);
}

How to implement an integration test to check if my circuit breaker fallback is called?

In my application, I need to call an external endpoint and if it is too slow a fallback is activated.
The following code is an example of how my app looks like:
#FeignClient(name = "${config.name}", url = "${config.url:}", fallback = ExampleFallback.class)
public interface Example {
#RequestMapping(method = RequestMethod.GET, value = "/endpoint", produces = MediaType.APPLICATION_JSON_VALUE, consumes = MediaType.APPLICATION_JSON_VALUE)
MyReturnObject find(#RequestParam("myParam") String myParam);
}
And its fallback implementation:
#Component
public Class ExampleFallback implements Example {
private final FallbackService fallback;
#Autowired
public ExampleFallback(final FallbackService fallback) {
this.fallback = fallback;
}
#Override
public MyReturnObject find(final String myParam) {
return fallback.find(myParam);
}
Also, a configured timeout for circuit breaker:
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds: 5000
How can I implement an integration test to check if my circuit break is working, i.e, if my endpoint (mocked in that case) is slow or if it returns an error like 4xx or 5xx?
I'm using Spring Boot 1.5.3 with Spring Cloud (Feign + Hystrix)
Note i donot know Feign or Hystrix.
In my opinion it is problematic to implement an automated integrationtest that simulates different implementatondetails of Feign+Hystrix - this implementation detail can change at any time. There are many different types of failure: primary-Endpoint not reachable, illegal data (i.e. receiving a html-errormessage, when exprecting xml data in a special format), disk-full, .....
if you mock an endpoint you make an assumption of implementationdetail of Feign+Hystrix how the endpoint behaves in a errorsituation (i.e. return null, return some specific errorcode, throw an exception of type Xyz....)
i would create only one automated integration test with a real primary-enpoint that has a never reachable url and a mocked-fallback-endpoint where you verify that the processed data comes from the mock.
This automated test assumes that handling of "networkconnection too slow" is the same as "url-notfound" from your app-s point of view.
For all other tests i would create a thin wrapper interface around Feign+Hystrix where you mock Feign+Hystrix. This way you can automatically test for example what happens if you receive 200bytes from primary interface and then get an expetion.
For details about hiding external dependencies see onion-architecture

Specifying route values for OData with Web API

I'm working on a new OData project, and am trying to do it with Web API 2 for the first time. The OData feed was pretty simple to put in place, which was great in comparison to WCF.
The problem I have now is that my OData feed will be used in a "multi-tenant" environment and I would like to use "friendly" URLs for the feed depending on the tenant. Therefore, I would ideally need the feed URLs to look like this:
/store/tenant1/Products
/store/tenant2/Products
Both URLs are pointing to the same controller and ultimately the same dataset, but I would like to enforce some entity filtering based on the tenant. Apparently this is going to be difficult and somewhat different to standard Web API routing since I can only specify a route prefix and not a route template.
So far, I've modified my OData controller to take the tenant name as a parameter and this works great when hitting the following url (which is not exactly what I want, see target above):
http://mydomainname/odata/Products?tenantName=test
Using this route definition:
ODataConventionModelBuilder modelBuilder = new ODataConventionModelBuilder();
modelBuilder.EntitySet<Product>("Products");
IEdmModel model = modelBuilder.GetEdmModel();
config.Routes.MapODataRoute(routeName: "OData", routePrefix: "odata", model: model);
And this is the sample action on my controller:
[Queryable]
public IQueryable<Product> GetPproducts(string tenantName)
{
return _products.Where(p=>p.TenantName == tenantName);
}
I'm not quite sure if this is possible and my last resort will be to use URL rewrite rules, but I'd rather avoid this and have everything in code, done the right way.
Thanks a lot for your help!
After some investigation I found it works in this way: Just apply the route prefix name to the query, for example:
public class MoviesController : ODataController
{
private MoviesContext _db = new MoviesContext();
public IHttpActionResult Get()
{
var routeName=Request.ODataProperties().RouteName;
ODataRoute odataRoute=Configuration.Routes[routeName] as ODataRoute;
var prefixName = odataRoute.RoutePrefix;
return Ok(_db.Movies.Where(m=>m.Title.StartsWith(prefixName)));
}
// Other methods here
}
Note: The above code is based on ODataActionsSample in https://aspnet.codeplex.com/SourceControl/latest#Samples/WebApi/OData/v4/
Now OData v4 has become a standard of OASIS, but v3 is not, so v4 seems a good start point.

WebApi and MVC 4: GetById and services in separate project

I'm working with webapi, MVC 4 project. (using repository pattern and Unit of Work)
I have two questions
1) The GetById of WebApi should return the entity or HttpResponseMessage?
If it's HttpResponseMessage, then Should it be...
[System.Web.Http.HttpGet]
public HttpResponseMessage Get(int id)
{
var car = Uow.Cars.GetById(id);
return car == null ? Request.CreateResponse(HttpStatusCode.OK, car) : Request.CreateResponse(HttpStatusCode.NotFound,);
}
or
[System.Web.Http.HttpGet]
public HttpResponseMessage Get(int id)
{
var car= Uow.Cars.GetById(id);
if (car!= null) {
return car;
}
throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.NotFound));
}
I'd like to follow RESTfull responses.
2) Is it logical to separate webapi services from the UI? I mean in one webapi project, the controllers with base ApiController and CRUD http opearations, so they can be called from anywhere/any devices directly, and then another webapi/MVC4 project which will call the services of the webapi project?
I'm asking this because having in the same controller the service and the handling that return a View for example sounds like coupling the service to the client which will be consuming it.
For example:
From this (in the same webapi controller):
[System.Web.Http.HttpGet]
public HttpResponseMessage Get(int id)
{
var car = Uow.Cars.GetById(id);
return car!= null ? Request.CreateResponse(HttpStatusCode.OK, car) : Request.CreateResponse(HttpStatusCode.NotFound,);
}
public ViewResult Details(long id)
{
return View(Get(id));
}
Go to this:
public ViewResult Details(long id)
{
return View(webapiService.Cars.Get(id));
}
Having the implementation of the Get in the service.
You could use HttpResponseMessage or the entity Car as the return type. If you use HttpResponseMessage you would get more control on customizing some of the HTTP properties when you create the response.
When the action creates a resource then using the HttpResponseMessage as the return type provide you much flexible option to set the status code (201) and the location where the created resource can be accessed. See this post for more info.
REST not care about which way you use all it cares is when the caller asks for a resource the server should return the resource in a format that the caller can accept it with proper status code (200 if exists else 404).
You can move the WebAPI controllers into separate project if there is really a choice that the service could be consumed from different clients else avoid doing that. Once you move the WebAPI controllers into a separate project then you will face Cross-Domain issues when you try to consume it from the javascript in MVC project.
Point 1:
It is logical to return the entity from actions in case of Web API but then we cannot control the HttpResponseMessage properties (like HttpStatusCode). Except that returning an entity is always a cleaner approach. We can control serialization, formatting etc in respective filters to get our job done. But you can never return car/HttpResponseMessage optionally as compiler will not let you compile a method with return type as HttpResponseMessage and return type Car.
Point 2:
Having separate controllers for view and rest calls is a good idea. I would suggest to have controllers with the same name but in different namespaces and then routes handle http calls separately (but prepending '/api/' to the rest calls. Having different actions in the same controller for ViewResult and HttpResponseMessage/Car is an option also but not as clean and separate.