Loopback POST array of entry? - post

I want to insert 10 entries with one query against 10 queries.
I read that it's possible to do it by sending an array like this :
But I get this error:
Do I need to set something? I don't know what to do at all.
Repo with a sample : https://github.com/mathias22osterhagen22/loopback-array-post-sample
Edit:
people-model.ts:
import {Entity, model, property} from '#loopback/repository';
#model()
export class People extends Entity {
#property({
type: 'number',
id: true,
generated: true,
})
id?: number;
#property({
type: 'string',
required: true,
})
name: string;
constructor(data?: Partial<People>) {
super(data);
}
}
export interface PeopleRelations {
// describe navigational properties here
}
export type PeopleWithRelations = People & PeopleRelations;

The problem with your code was :
"name": "ValidationError", "message": "The People instance is not
valid. Details: 0 is not defined in the model (value: undefined);
1 is not defined in the model (value: undefined); name can't be
blank (value: undefined).",
Here in above as in your #requestBody schema, you are applying to insert a single object property, where as in your body are sending the array of [people] object.
As you can see in your people.model.ts you have declared property name to be required, so system finds for the property "name", which obviously not available in the given array of object as primary node.
As you are passing index array, so its obvious error that you don't have any property named 0 or 1, so it throws error.
The below is the code hat you should apply to get insert the multiple, items of the type.
#post('/peoples', {
responses: {
'200': {
description: 'People model instance',
content: {
'application/json': {
schema: getModelSchemaRef(People)
}
},
},
},
})
async create(
#requestBody({
content: {
'application/json': {
schema: {
type: 'array',
items: getModelSchemaRef(People, {
title: 'NewPeople',
exclude: ['id'],
}),
}
},
},
})
people: [Omit<People, 'id'>]
): Promise<{}> {
people.forEach(item => this.peopleRepository.create(item))
return people;
}
You can also use this below
Promise<People[]> {
return await this.peopleRepository.createAll(people)
}
You can pass the array of your people model by modifying the request body.If you need more help you can leave comment.
I think you have a clear solution now. "Happy Loopbacking :)"

Related

How can I display multiple ResponseDTOs' schemas in Swagger/NestJS?

I have this route which can return one of these two different DTOs:
#Get()
#ApiQuery({ name: 'legacy', description: "'Y' to get houses legacy" })
async findAllHouses(
#Query('legacy') legacy: string,
): Promise<HousesDto[] | HousesLegacyDto[]> {
...
}
I want to display both of these ResponseDTOs in swagger.
I've tried this decorator:
#ApiOkResponse({
schema: { oneOf: refs(HousesDto, HousesLegacyDto) },
})
// OR
#ApiOkResponse({
schema: {
oneOf: [
{ $ref: getSchemaPath(HousesDto) },
{ $ref: getSchemaPath(HousesLegacyDto) },
],
},
})
with #ApiExtraModels() on top of DTO classes and #ApiProperty() on each properties.
But I still get empty objects in Swagger and I suppose it would not have even taken array types in consideration.
How can I display both of these schemas properly?
Seems to me like a lot of very obscure solutions have been posted here and there, so I will try to clarify what needs to be done.
You have two DTOs:
export class SomeStatusDto {
#ApiProperty({
description: 'Id',
example: 1,
})
#IsNumber()
id: number;
#ApiProperty({
description: 'Status',
example: 'in_progress',
})
#IsString()
status: string;
}
export class ErrorStatusDto {
#ApiProperty({
description: 'Id',
example: 1,
})
#IsNumber()
id: number;
#ApiProperty({
description: 'Error',
example: 'Some error string',
})
#IsString()
error: string;
}
Then you have your controller:
#UseGuards(AccountTypesGuard)
#ApiOperation({ summary: 'Get status of...' })
#Get('status')
#ApiExtraModels(SomeStatusDto, ErrorStatusDto)
#ApiOkResponse({
schema: { anyOf: refs(SomeStatusDto, ErrorStatusDto) },
})
async getPullStatus(
#Request() req,
#Param('id', ParseIntPipe) someId: number,
): Promise<SomeStatusDto | ErrorStatusDto> {
// check if someId belongs to user
const idBelongsToUser = await this.myService.validateSomeId(
req.user.id,
someId,
);
if (!idBelongsToUser) {
throw new ForbiddenException(
`SomeId does not belong to user (someId=${someId}, userId=${req.user.id})`,
);
}
const key = `status-${someId}`;
const response = await this.redisService.getByKey(key);
return response ? response : {};
}
Note the solution below. You need to reference the DTOs as #ApiExtraModels() and then you can add them as anyOf: refs(...) in your schema.
#ApiExtraModels(SomeStatusDto, ErrorStatusDto)
#ApiOkResponse({
schema: { anyOf: refs(SomeStatusDto, ErrorStatusDto) },
})
Hope this helps somebody :)
so I encountered a similar issue and this is how you could get the output shown in the image above.
Using the #ApiResponse decorator you could set the two responses using the examples property, try the code sample below
#ApiResponse({
status: 200,
description: 'Successful response',
content: {
'application/json': {
examples: {
HousesDto: { value: HousesDto },
HousesLegacyDto: { value: HousesLegacyDto },
},
},
},
})

how to implement mutation responses on a local falcor Model dataset

Given that I have an example Model:
var model = new falcor.Model({
cache: {
userById: {
"1": {
name: "User",
email: "user#email.com"
}
},
users: {
current: null
}
}
});
This is a local model that I'm using for testing purposes, and I would like to implement it on a call to users.login so the user so that I can call:
model.call(['users', 'login'], ['user', 'password'])
I realized that if I do this:
var model = new falcor.Model({
cache: {
userById: {
"1": {
name: "User",
email: "user#email.com"
}
},
users: {
current: null,
login: function(user, password) {
console.log('this code is reached', user, password);
// what to return in order to mutate model?
}
},
}
});
When I do the call it gets there, but I can't figure out how to mutate the model as part of the response; on the server side we return the paths with values and invalidates, and it just works, but here I tried:
// trying returning as a jsonGraph response, don't work
login: function() {
return {
jsonGraph: {
users: {
current: {$type: "ref", value: ['userById', '1']}
}
},
paths: [['users', 'current']]
}
}
// trying returning as a path set mutation list, don't work
login: function() {
return [{path: ['users', 'current'], value: {$type: "ref", value: ['userById', '1']}}]
}
// trying force call to set on the model, don't work
login: function() {
this.set([
{path: ['users', 'current'], value: {$type: "ref", value: ['userById', '1']}}
])
}
// trying using ModelResponse, got an example on some external sources, don't work
login: funtion() {
return new ModelResponse((observer) => {
observer.onNext({
jsonGraph: {
users: {
current: {$type: "ref", value: ['userById', '1']}
}
},
paths: [['users', 'current']]
});
observer.onCompleted();
});
}
Now I don't know what else to try; I need a simple way to declare mutations after a call into a local model, if you know how to solve this, please let me know here.
Thanks.
The client model cache only supports JSONGraph, which b/c it is essentially just JSON with some conventions, doesn't support functions. So, when working with a falcor model cache and no dataSource/middle tier router, it is not possible to implement calls.
This can be kind of annoying when prototyping/testing, as a router is conceptually more difficult than a simple JSON cache object. I ran into this a while ago, so I wrote a dataSource module to support it: falcor-local-datasource. The dataSource is initialized with a graph object that does support function nodes, and as with your above examples, will mutate the graph based on the function's returned JSONGraphEnvelope or an array of PathValues.

Error loading entities with a navigation property using custom metadata

I have the following implementation of a custom metadata scenario using the boiler plate with breeze.metadata-helper 1.0.7 and BreezeJS 1.4.16:
function addFoo() {
addType({
shortName: 'Foo',
dataProperties: {
Id: { type: ID },
BarId: { type: ID }
},
navigationProperties: {
Bar: {
entityTypeName: 'Bar',
associationName: 'Foo_Bar',
foreignKeyNames: ['BarId']
}
}
});
}
function addBar() {
addType({
shortName: 'Bar',
dataProperties: {
Id: { type: ID },
}
});
}
Upon completion of query (provided below) execution i receive the following error: TypeError: newValue.getProperty is not a function.
var query = breeze.EntityQuery.from('Foos').expand('Bar');
manager.execute(query).catch(function(error) { });
HTTP response contains the following JSON:
[{"Id":1,"BarId":2,"Bar":{"Id":2}}]
Though this query works fine if i replace foreignKeyNames: ['BarId'] with invForeignKeyNames: ['Id']. And still, in the latter case the navigation property Bar() of foo entity is not of entity type Bar but a simple javascript object.
The questions are:
1) Why the query with foreignKeyNames fails
2) Why foo.Bar() is not an entity of type Bar
Thanks.
I think the issue is with how you are serializing the result of your query. Take a look at the JsonResultsAdapter documentation where it discusses how to handle references in the json payload. You may need a custom JsonResultsAdapter ( pretty easy to write once you understand the idea).

KendoUI datasource: parseInt of filter value

I need to filter a Kendo datasource through the following filter item object:
filters: [
{
field: "FIELD",
operator: "lt",
value: "080"
}
]
That means, because of the way data are transmitted, I am trying to test a case like: "013" < "080".
But it does not work out of the box.
Is there a way to define a filter with something like a "parseInt" on the tested values?
Thank you!
Try defining FIELD as a number in model:
schema : {
model: {
fields: {
FIELD : { type: "number" }
}
}
},
If you do so, then FIELD is displayed as 13, 80,... If you want to display FIELD with leading 0, use the following in the column definition of the grid.
{ field: "FIELD", title: "Field", format: "{0:000}" }
Doing this FIELD is considered as a number even that it is displayed as 013, 080...
You should have something like:
var dataSource = new kendo.data.DataSource({
data : entries,
batch : true,
schema : {
model: {
fields: {
FIELD: { type: "number" }
}
}
}
});
var grid = $("#grid").kendoGrid({
dataSource: dataSource,
columns : [
{ field: "FIELD", title: "Field", format: "{0:000}" }
],
filterable: true
}).data("kendoGrid");
If you want to try it, see it in JSFiddle here
EDIT: Updated code for using format instead of template as Mateo Piazza suggested

ExtJS4.1: Why model.save() sends wrong thing to server?

I tried to use model.save() to POST a new user. But I check request payload and found that it not only sent the data, but also sent other parts of the model. That makes my server cannot parse the payload.
The request payload generated :
{"phantom":true,"internalId":"ext-record-58","raw":{},"data":{"userId":0,"userName":"Amy"},"modified":{"userName":""},"hasListeners":{},"events":{},"stores":[],"dirty":true,"id":"AM.model.User-ext-record-58"}
But the desired request payload should be :
{"userId":0,"userName":"Amy"}
And I am aware that the "phantom" of my model is false before I call model.save(). But it becomes true in the request payload. Is it a clue?
Model:
Ext.define('AM.model.User',{
extend: 'Ext.data.Model',
fields: [
{ name: 'userId', type: 'int' },
{ name: 'userName', type: 'string' },
{ name: 'createdTime', type: 'string' },
],
idProperty: 'userId',
associations: [
{
type: 'hasOne',
model: 'AM.model.ModelA',
name:'modelA',
associationKey:'modelA',
getterName:'modelA'
},
{
type: 'hasOne',
model: 'AM.model.ModelB',
name:'modelB',
associationKey:'modelB',
getterName:'modelB'
}
],
proxy: {
type: 'rest',
success:true,
url:'../restful/users',
writer:{
type:'json',
getRecordData:function(record){ //parse createdTime to the format Y-m-d
record.set('createdTime', Ext.Date.format(new Date(record.get('createdTime')), "Y-m-d"));
return record;
}
},
reader: {
type: 'json'
}
}
});
This is the view which has the data to be posted. The view will fill the data to the model:
Ext.define('AM.view.UserRegisterForm',{
extend:'Ext.form.Panel.',
alias:'widget.userRegisterForm',
fields:new Array(), //I want to render the fields in xtemplate, so instead of adding the fields to items, I use an array to manage them.
retrieveData(model){
model.set('userName', this.fields[0].getValue());
model.set('createdTime',this.fields[1].getValue());
}
}
The function in the controller, which sends the POST request:
postUser:function(){
var userRegisterForm= this.getUserRegisterForm();
var userModel = this.getUserModel();
var user= new userModel();
var me = this;
userRegisterForm.retrieveFieldData(user);
console.log(user); //the data in console looks fine!
user.save({
success: function(response) {
//do something...
},failure:function(response) {
alert('fail');
}
});
}
You are returning the full record when you override getRecordData Where as you are just meant to return the records data. record.getData()
Some extra advice. Don't override getRecordData to set the models creation date. Use the models defaultValue property to give assign it a new Date if one doesn't exist.

Resources