10

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

  1. Amplify is correctly configured in my iOS project. I can push data to Person and query the Amplify.API
  2. 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?

rodrigoelp
  • 2,550
  • 1
  • 19
  • 29
  • If you got to this hoping for an answer... I created an issue at their github and the official answer at this stage is: "it is not implemented yet..." – rodrigoelp Feb 18 '20 at 04:37
  • I was using @connection in a project with similar relationships for a User. Translated to this case, what I did was create the Person first with no possessions, then perform the Mutation. After that, I create the Thing and pass the already created Person. Have you tried something like this? (Not performing two mutations at once, but doing them separatedly) – Victor Sanchez Mar 11 '20 at 05:45
  • Hi @VictorSanchez. I have tried the approach you mentioned here. It works in AppSync but (at the time I was trying it) it didn't work in Amplify iOS. Had a long discussion with the dev team and they mentioned that the documentation is ahead of what it is implemented. We decided to stop using amplify and went the pure graphql way a few months ago, so I haven't checked if there is an update on this. – rodrigoelp Mar 11 '20 at 07:53
  • I see. I got it working with Amplify iOS + Dynamo last week. Couldn't get it working with Amplify iOS + RDS Aurora though, only works with Aurora if I use the iOS AppSync Client. Maybe in a few months! – Victor Sanchez Mar 11 '20 at 08:05
  • 1
    This issue seems to exist nearly two years later... I can't believe this isn't handled yet – Matthew Knippen Jan 22 '22 at 04:19
  • Yup, my team decided to move away from amplify (as in forever) and we found we had a lot less friction and a significant lower operational cost (amplify creates a gazillion services for minor things). We are doing everything with graphql and some manual work that amplify would have automated, but we opted in for a more flexible approach. – rodrigoelp Jan 27 '22 at 00:35

0 Answers0