How to define relations using primary keys instead of entities in TypeORM WIth NestJS - orm

I'm using NestJS + TypeORM, and have two entities that looks like follows:
export class User {
#PrimaryColumn()
UserID: number;
#Column()
UserName: string;
#OneToOne(() => Blog)
#JoinColumn()
Blog: Blog;
}
export class Blog {
#PrimaryColumn()
BlogID: number;
#Column()
BlogName: string;
}
When a consumer sends a request to create a User like the following, with the BlogID in the request:
userRequest = {
"UserID": 1,
"UserName": "me",
"BlogID": 12
}
On the backend, I can't do userRepository.create(userRequest), I'll have to convert the BlogID sent in the request to an actual Blog entity object so that typeorm can process this. Now, the only way I can think of doing this is my injecting the Blog repository and doing:
userEntity = {
"UserID": userRequest.UserID
"UserName": userRequest.UserName
"Blog": await this.blogRepository.findOneBy({
BlogID: userRequest.BlogID
})
and finally doing:
userRepository.create(userEntity)
My main question: is there a way to do this without injecting the Blog repository into the User service? The problem that arises is that I also implement a functionality that requires me to inject the User repository into the Blog service, which creates a circular dependency. NestJS mandates that circular dependencies should be avoided at all costs, but I don't believe I'm trying to do anything that's programmatically bad practice by implementing this. If I could implement this without introducing a circular dependency, I would. And I believe the main thing that's stopping me from doing so is the fact that I need to import the repository of the entity into the service of the adjacent service. Any tips?

userEntity = {
"UserID": userRequest.UserID
"UserName": userRequest.UserName
"Blog": {id: userRequest.BlogId}
}
pass userRequest.BlogId as userEntity.Blog.id

Update your relation like this :
#OneToOne(() => Blog)
#JoinColumn({ name: "blogId" })
Blog: Blog;

Related

Traverse of linked entities with API client exposed by spring-data-rest

With a generated client by openapi-generator (typescript-axios in my case), it is easy to request an entity that is exposed by spring-data-rest, let's say a Person entity with
const endpoint = PersonEntityControllerApiFactory(configuration);
endpoint.getItemResourcePersonGet('5000')
which gives me an object like
{
"id" : "5000",
"name" : "Mr. Anderson",
"_links" : {
"self": {
"href": "http://localhost:8888/api/persons/5000"
},
"addresses": {
"href": "http://localhost:8888/api/persons/5000/addresses"
}
}
}
Now, is there an easy way to request the addresses collection of that entity with the generated API client (typescript-axios in my case)?
One compicated way comes to my mind to solve this. It's possible to provide a spring data rest projection for Person which inlines ids or complete Address entities into Person. But that would take some extra effort and would be against the HAL / HATEOAS idea.
Another way could be to perform a request on the provided addresses link manually (e.g. by calling axios). But that would question the use of a generated API client in general.

OData: Change URL value for entity type in EDM Model

I'm working with a ASP.NET Core Web Api project that uses OData for the exposed endpoints and are consumed with a Simple.OData.Client.
Some of my endpoints are:
http://{baseUrl}/odata/Vehicle --> this works perfectly
But I'm having issues with these two:
http://{baseUrl}/odata/Vehicle/Brand
http://{baseUrl}/odata/Vehicle/Type
Basicly, I can't modify my EDM Models for modifying the URL property that is exposed in the metadata of OData. My EDM looks like this:
private IEdmModel GetEdmModel()
{
var odataBuilder = new ODataConventionModelBuilder();
odataBuilder.EntitySet<Vehicle>("Vehicle");
odataBuilder.EntitySet<VehicleType>("VehicleType");
odataBuilder.EntitySet<VehicleBrand>("VehicleBrand");
return odataBuilder.GetEdmModel();
}
And the metadata that I get when I navigate through http://{baseUrl}/odata/ is the following:
{
"#odata.context": "https://localhost:44332/odata/$metadata",
"value": [
{
"name": "Vehicle",
"kind": "EntitySet",
"url": "Vehicle"
},
{
"name": "VehicleType",
"kind": "EntitySet",
"url": "VehicleType"
},
{
"name": "VehicleBrand",
"kind": "EntitySet",
"url": "VehicleBrand"
}
]
}
I couldn't find a way to maintain the name as it is, but modify the "url" property shown on the JSON to point to my proper endpoint. I want this result:
{
"name": "VehicleBrand",
"kind": "EntitySet",
"url": "Vehicle/Brand"
}
Any of the methods exposed on EntitySetConfiguration or ODataConventionModelBuilder seems to have a way to specify a different URI for a registered entity type.
Someone has faced this issue? I'm sure that might be some way of solving this.
Odata Route or Navigation Property?
Please have a look at that documentation here
Long story short - an OData URI consists of:
The service root
The OData path
Query options
For example. This is a Path that goes to the EntitySet "Products", takes the first, and then Navigates (see Navigation Properties) to its Supplier.
https://example.com/odata/Products(1)/Supplier?$top=2
------------base---------|-----Path-----------?---options---
So, everything you make accessible at root level should have its own path, and the / telling Odata to navigate onward from there.
So, now for OData, it would freak the hell out of most clients and surely be bad style if you would define an entitysets path as something that can be confused with another entititysets navigation property.
But if you REALLY need to do it, maybe you can achieve it by defining a custom routing convention.
But dont! It will only make trouble
Do you want a navigation property?
If you want the set that "Type" returns to be dependent on the Vehicle, you should define a navigation property on Vehicle instead.
Greetings, Mike

405 Response on post using axios in Vue 3.0 app to .Net Core 2.2 with AllowAnyMethod in policy

I am losing my mind and having read a lot of blogs, SO questions and documents I am sure it is a simple fix that I am now completely blind to.
I have an axios post call from a vuejs app to a .net core 2.2 api project. Following the Enable CORS guide from Microsoft I have used Access Policy in Services and decorated the controller. See the code below.
The pre-flight options response is 204 with a 405 response on the actual call citing allow: DELETE, GET, PUT as the permitted method ... what have I missed here? I have .AllowAnyMethod in the policy but it seems to be completely ignored. A colleague working with a WebAPI 2.2. project has the exact same code and it works.
StartUp.cs
services.AddCors(options =>
{
options.AddDefaultPolicy(
builder =>
{
builder.WithOrigins("http://example.com",
"http://www.contoso.com");
});
options.AddPolicy("VueFrontEnd",
builder =>
{
builder.WithOrigins("http://localhost:30001/")
.AllowAnyHeader()
.AllowAnyMethod();
});
});
Controller
[EnableCors("VueFrontEnd")]
[HttpPost]
public async Task<JsonResult> DoesItExist(string searchString)
{
var data = new string[] { "A", "B", "C" };
var result = data.Any(searchString.Contains);
return Json(JsonConvert.SerializeObject(result));
}
Vue
getClientsByPartialString(search: string) {
Axios({
method: 'post',
url: 'https://localhost:44380/api/values/DoesItExist',
crossDomain: true,
data: {
name: 'world',
},
})
}
This makes me sad. It was routing.
Adding [HttpPost("/TheApi")] decorator sorted it.
I am ashamed. I was using the full URL http://localhost:port/api/values/themethod and routing was failing me despite it being set on the controller.
The one thing that concerns me is why this worked with GET and PUT and ONLY failed on POST. I have no answer to that one.

Should "persistent" field appear in serialized PanacheEntity?

I am building a simple Jaxrs api in quarkus. When I call my index method it looks like jackson serializes the objects with the persistent field, that it gets from the PanacheEntityBase.
Example:
[
{
"persistent": true,
"id": 1,
"createdAt": "2019-03-18",
"updatedAt": "2019-03-18"
},
{
"persistent": true,
"id": 2,
"createdAt": "2019-03-18",
"updatedAt": "2019-03-18"
}
]
The persistent field isn't saved to the database, but it shows up in the response. I have looked into using #jsonIgnore and jackson mixins, but I would rather not have to do this, especially if this is just a configuration issue. I am curious if Panache should be doing this, or if anyone else is having this problem.
This happens when we use 3-rd party libraries as returned data type and provide it to Jackson serialisation process. PanacheEntity extends PanacheEntityBase which contains isPersistent method which is treated by Jackson like a POJO getter method.
public boolean isPersistent() {
return JpaOperations.isPersistent(this);
}
Jackson automatically takes all get* and is* methods and try to serialise it and include to result JSON. There is no way to configure it on quarkus level. Your solution with JsonIgnore and MixIn feature is good approach.
With Json-B add in your entity :
#JsonbTransient
public boolean isPersistent() {
return super.isPersistent();
}

changing meteor restivus PUT to implement upsert

i'm using restivus with meteor and would like to change the PUT schemantic to an upsert.
// config rest endpoints
Restivus.configure({
useAuth: false,
prettyJson: false
});
Restivus.addCollection("sensor", {
excludedEndpoints: ['getAll','deleteAll','delete'],
defaultOptions: {},
});
how does one do this?
Right now, the only way to do this would be to provide a custom PUT endpoint on each collection route:
Restivus.addCollection(Sensors, {
excludedEndpoints: ['getAll','deleteAll','delete'],
endpoints: {
put: function () {
var entityIsUpdated = Sensors.upsert(this.urlParams.id, this.bodyParams);
if (entityIsUpdated) {
var entity = Sensors.findOne(this.urlParams.id);
return {status: "success", data: entity};
}
else {
return {
statusCode: 404,
body: {status: "fail", message: "Sensor not found"}
}
}
}
}
});
The goal with Restivus is to provide the best REST practices by default, and enough flexibility to allow the user to override it with custom behavior where they desire. The proper RESTful behavior of PUT is to completely replace the entity with a given ID. It should never generate a new entity (that's what POST is for). For collections, Restivus will only allow you to define a PUT on a specific entity. In your example, an endpoint is generated for PUT /api/sensors/:id. If you aren't doing the PUT by :id, then you should probably be using POST instead (there's no "right way" to do this in REST, but at least you can POST without requiring an :id).
It sounds like what you want is a way to override the default behavior of the collections endpoints. That is extremely doable, but it would help me if you would make a feature request via the Restivus GitHub Issues so I can better track it. You can literally copy and paste your question from here. I'll make sure I add a way for you to access the collection in the context of any collection endpoints you define.
Last, but certainly not least, I noticed you are using v0.6.0, which needs to be updated to 0.6.1 immediately to fix an existing bug which prevents you from adding existing collections or using any collections created in Restivus anywhere else. That wasn't the intended behavior, and an update has been released. Check out the docs for more on that.