Use interface as a swagger schema - NestJS DTO - swagger

I have the following code:
import { IsNotEmpty, IsArray, ArrayMinSize } from 'class-validator';
import { ApiProperty } from '#nestjs/swagger';
export class PublishDto {
#IsNotEmpty()
#IsArray()
#ArrayMinSize(1)
#ApiProperty({
type: [Product]
})
products: Product[];
}
interface Product {
id: string;
title: string;
sku: string;
stock: number;
description: string;
shortDescription: string;
imagesUrl: string[];
price: number;
department: string;
category: string;
brand: string;
keywords: string[];
isActive: boolean;
}
I'm trying to put the interface Product as a schema on swagger, but it's not working, I am getting an error.
Any idea?

The type property is expecting a value that is available at runtime, for example an actual Class or the Javascript String type. Interfaces exist only at compile time and so they aren't valid to be passed in this way.
You'll have to convert it to a Class if you want to pass it manually otherwise you could take a look at using the NestJS Swagger compiler plugin which uses some cool compile-time magic to automatically try and figure some of this stuff out for you

Related

Can I update the object property with patch?

I have the state like, I don't want to touch the rest of the state but specific property of an object in the state.
export interface User {
name: string;
email: string;
userGroup: string;
notification: boolean;
}
export interface SettingState {
user: User | null,
logs: any[],
trail: any[],
}
I want to update the user notification. Can I use patch for that purpose. I tried following but getting error.
patchNotfication(value: boolean) {
this.patchState({ user.notification: value})
}
and this code snippet gives another error
patchNotfication(value: boolean) {
this.patchState((state) => ({
user: value
}));
}
I get following error
What method would serve me best here?

Protocols and Enums in Swift with Apollo

I am using Apollo for Swift in an iOS app. I have multiple types that all represent the same object. These types are auto-generated from a schema file and look something like this.
struct CurrentUser {
var id: String
...
}
struct MyUser {
var id: String
...
}
Basically Apollo generates multiple Swift types (one for each query) for the same underlying data type.
I want to create a new struct that unifies these types.
I would like to do something like this:
protocol UserProtocol {
var id: String { get }
}
struct User {
var id: String
...
init(_ data: UserProtocol) {
self.id = data.id
...
}
}
This approach however gives me an error when I try to construct a user object, telling me that "Type MyUser does not conform to UserProtocol". If I try to coerce the type with data as! UserProtocol I get a crash.
The only solution I've found is the following:
enum UserType {
case .currentUser(CurrentUser)
case .myUser(MyUser)
}
struct User {
var id: String
...
init(_ data: UserType) {
switch data {
case .myUser(let user):
self.id = data.id
...
case .currentUser(let user):
self.id = data.id
...
}
}
}
This approach works, but it leads to a lot of duplicated code in the init function. Is there a better way to do this in Swift?
I suspect the problem is that you need to explicitly conform the Apollo generated types to your protocol:
extension CurrentUser: UserProtocol { }
extension MyUser: UserProtocol { }
Remember that Swift is not duck-typed like some other languages, so a type with member var id: String is not UserProtocol until you declare it as such.
If for some reason you need to do some transformation of the Apollo types to fit the app models in the future, those extensions are a good place to do that, too.

How do I get a list of subnet IDs from one stack to another using SSM when StringListParameter doesn't work?

According to this bug and this bug, ssm.StringListParameter doesn't work in the CDK due to some issues with CFT.
I need to be able to export an arbitrarily length list of subnetIds from one stack and import the list into another using SSM, as the lifetime of subnetIds is completely different than the lifetime of the consumer of subnetIds in a second stack (especially in production, though not in a sandbox). I cannot hard code the subnet IDs, as when creating a sandbox the IDs would vary from sandbox to sandbox. I want the latest version of whatever is in the SSM key.
However, the bugs appear to not be resolvable, and I cannot find a work around.
I tried serializing using JSON, but the item passed around the code is is a late binding Token, which is treated as a string, and the deserialized items is a string [], so it's not possible to get such code to compile.
Here's an example of what I attempted. It doesn't compile:
export function getOtherStackOutputList(stack: cdk.Stack, mangledOtherStackName: string, key: string): string [] {
const globallyUniqueKey = `/${mangledOtherStackName}/${key}`;
const jsonResult = ssm.StringParameter.fromStringParameterName(stack, key + 'SSM', globallyUniqueKey).stringValue;
if (cdk.Token.isUnresolved(jsonResult)) {
return jsonResult;
} else {
const result = JSON.parse(jsonResult);
return result;
}
};
which would be used by code that looks like this:
const efsVpcIsolatedSubnetsIds = StackValueShare.getOtherStackOutputList(this, mangledStackName + efsDbStackSuffix,
'efsTimeSeriesDatabaseVpcIsolatedSubnets');
This works for me:
import { Construct } from '#aws-cdk/core';
import { AwsCustomResource, AwsSdkCall } from '#aws-cdk/custom-resources';
import iam = require("#aws-cdk/aws-iam");
interface SSMParameterReaderProps {
parameterName: string;
region: string;
}
export class SSMParameterReader extends AwsCustomResource {
constructor(scope: Construct, name: string, props: SSMParameterReaderProps) {
const { parameterName, region } = props;
const ssmAwsSdkCall: AwsSdkCall = {
service: 'SSM',
action: 'getParameter',
parameters: {
Name: parameterName
},
region,
physicalResourceId: {id:Date.now().toString()} // Update physical id to always fetch the latest version
};
super(scope, name, { onUpdate: ssmAwsSdkCall,policy:{
statements:[new iam.PolicyStatement({
resources : ['*'],
actions : ['ssm:GetParameter'],
effect:iam.Effect.ALLOW,
}
)]
}});
}
public getParameterValue(): string {
return this.getResponseField('Parameter.Value').toString();
}
}

Spartacus Extend AuthService

Is it possible to extend the Auth Service and add additional parameters to it?
Currently trying to extend but encounter error such as below:
ERROR in src/app/service/auth/auth-extend.service.ts(15,3): error TS2416: Property 'authorize' in type 'AuthExtendService' is not assignable to the same property in base type 'AuthService'.
Type '(userId: string, password: string, countryCode: string, businessType: string) => void' is not assignable to type '(userId: string, password: string) => void'.
src/app/service/auth/auth-extend.service.ts(21,7): error TS2345: Argument of type '{ userId: string; password: string; countryCode: string; businessType: string; }' is not assignable to parameter of type '{ userId: string; password: string; countryCode: string; businessType: string; }'.
Object literal may only specify known properties, but 'businessType' does not exist in type '{ userId: string; password: string; countryCode: string; businessType: string; }'. Did you mean to write 'businessType'? "
Any one here to tries to do this, like adding new parameters.
Typescript does not support such an overloading out of the box. One way of doing it would be by using optional parameters such as:
export class AuthExtendService extends AuthService {
authorize(userId: string, password: string, businessType?: string): void {
console.log(businessType);
this.store.dispatch(
new AuthActions.LoadUserToken({
userId: userId,
password: password,
})
);
}
}
This is how you should add extra parameters.

How to store relational (one to many or many to one) data with Amplify iOS (AppSync)?

today checking some of the amplify documentation (I know this one says it is a preview in the iOS scenario) but I have ran into a road block.
Assumptions
Amplify is correctly configured in my iOS project. I can push data to Person and query the Amplify.API
The schema has been defined as:
type Person #model {
id: ID!
name: String!
possessions: [Thing] # list of things this person owns.
#connection(keyName: "byPerson", fields: ["id"])
}
type Thing #model
#key(name: "byPerson", fields: ["personId"]) {
id: ID!
name: String!
personId: ID!
ownerOfThings: Person # defining the 'belongsTo' property.
#connection(fields: ["personId"])
}
This generates the following code:
public struct Person: Model {
public let id: String
public var name: String
public var possessions: List<Thing>?
public init(id: String = UUID().uuidString,
name: String,
possessions: List<Thing>? = []) {
self.id = id
self.name = name
self.possessions = possessions
}
}
public struct Person: Model {
public let id: String
public var name: String
public var ownerOfThings: Person?
public init(id: String = UUID().uuidString,
name: String,
ownerOfThings: Person? = nil) {
self.id = id
self.name = name
self.ownerOfThings = ownerOfThings
}
}
Here is where I ran into trouble. Amplify.API doesn't seem be saving my object and its associated data in a single mutation. I have to call it as nested operations to have an effect.
// sample on how I am trying to save data.
var thing = Thing(name: "Long Claw")
let person = Person(
name: "Jon Snow",
possessions: List([ thing ])
)
Amplify.API.mutate(of: person, type: .create) { ev in
// doing something with the event.
print(String(describing: ev)) // this works. It saves the instance to DynamoDB
// unfortunately, it did not save the instance of thing... let's try to correct this.
thing.ownerOfThings = person
Amplify.API.mutate(of: thing, type: .create) { ev2 in
// do something else with this...
print(String(describing: ev2))
// this ^ crashes badly...
}
}
The code above will generate an output similar to:
Result.success(Person(id: "EC4BEEE1-C1A1-4831-AB86-EA1E22D8AD48", name: "Jon Snow", possessions: nil))
GraphQLResponseError<Thing>: GraphQL service returned a successful response containing errors: [Amplify.GraphQLError(message: "Variable \'input\' has coerced Null value for NonNull type \'ID!\'", locations: Optional([Amplify.GraphQLError.Location(line: 1, column: 26)]), path: nil, extensions: nil)]
I've tried declaring the relationship as:
type Person #model {
id: ID!
name: String!
possessions: [Thing] # list of things this person owns.
#connection(keyName: "byPerson", fields: ["id"])
}
type Thing #model
#key(name: "byPerson", fields: ["personId"]) {
id: ID!
name: String!
personId: ID!
# ownerOfThings: Person
# #connection(fields: ["personId"]) # Not belongsTo for you!
}
Or a variation of this, defining the possessions as possessions: [Thing] #connection.
All of them generate various (although some what related) errors, preventing me from storing my data.
So, the question is:
How do you specify the relationship in iOS to save it?

Resources