Skip to content
This repository has been archived by the owner on Jan 25, 2019. It is now read-only.

Including attributes into relationship object #181

Open
mareapp opened this issue May 8, 2017 · 4 comments
Open

Including attributes into relationship object #181

mareapp opened this issue May 8, 2017 · 4 comments

Comments

@mareapp
Copy link

mareapp commented May 8, 2017

I am trying to implement save(POST) to my back-end, here is my request body:

  "data": {
    "type": "account",
    "relationships": {
      "account_type": {"data": {"type": "account_type", "id": "1"} },
      "user": {
        "data": {
          "type": "user",
          "attributes": {
            "email": "[email protected]",
            "firstname": "John",
            "lastname": "Doe",
            "company_name": "test company",
            "phone": "381 11 232 342",
            "address": " Venizelosova 43, 11000 Beograd, Serbia",
            "latitude": 44.8112,
            "longitude": "20.5342",
            "description": "some description",
            "website_url": "ar-ty.com",
            "password": "password123",
            "password_confirmation": "password123"
          },
          "relationships": { "role": { "data": {"type": "role", "id": "3"} } }
        }
      }
    }
  }
}

Does your lib support including attributes into relationship object, like in this json where relationship object has user with attributes. Please could you give me code example how to do this if possible?
Thanks in advance

@markst
Copy link

markst commented May 10, 2017

Hey @mareapp I'm not sure if this is valid JSONAPI, however I'm currently achieving the same example by creating my own Relationship field type, here's an example:

public struct ToOneLinkage<T: Resource> : Relationship {

    public typealias Linked = T
    
    public var name: String
    public var serializedName: String
    public var isReadOnly: Bool = false

    private var shouldSerializeAttributes: Bool = false

    public func serializeAttributes() -> ToOneLinkage {
        var newField = self
        newField.shouldSerializeAttributes = true
        return newField
    }

    public init(_ name: String, to linkedType: T.Type) {
        self.name = name
        self.serializedName = name
    }
    
    public func serialize(from resource: Resource,
                          into serializedData: inout [String: Any],
                          withKeyFormatter keyFormatter: KeyFormatter,
                          withValueFormatters valueFormatters: ValueFormatterRegistry,
                          withOptions options: SerializationOptions) {
        let key = keyFormatter.format(self)

        if options.contains(.IncludeToOne) {
            let linkedResource: Linked?

            let fieldValue = resource.value(forField: self.name)
            if let linkingObjects = fieldValue as? RLMLinkingObjects {
                if linkingObjects.count > 1 {
                    fatalError("Should only use `ToOneLinkage` for to one linkage...")
                }
                linkedResource = linkingObjects.firstObject() as? Linked
            } else {
                linkedResource = fieldValue as? Linked
            }
            
            var serializedResourceData: [String: Any] = [:]

            // Serialize type
            serializedResourceData["type"] = Linked.resourceType

            // Serialize ID
            if let resourceId = linkedResource?.id {
                serializedResourceData["id"] = resourceId
            }

            // Serialize Attributes
            if self.shouldSerializeAttributes, let fields = linkedResource?.fields {
                for field in fields where !field.isReadOnly && field is Attribute {
                    field.serialize(from: linkedResource!,
                                    into: &serializedResourceData,
                                    withKeyFormatter: keyFormatter,
                                    withValueFormatters: valueFormatters,
                                    withOptions: options)
                }
            }
            
            let serializedRelationship = [ "data": linkedResource != nil ? serializedResourceData : NSNull() as Any]
            
            if serializedData["relationships"] == nil {
                serializedData["relationships"] = [key: serializedRelationship]
            } else {
                var relationships = serializedData["relationships"] as! [String: Any]
                relationships[key] = serializedRelationship
                serializedData["relationships"] = relationships
            }
        }
    }

Which can be used in place of your user relationship instead of a ToOneRelationship

@mareapp
Copy link
Author

mareapp commented May 15, 2017

Thanks for answer, yeah its true my back end has not followed standard about JSON API but only when need POST operation, so I dont have any problem with GET but when I need to send this kind of request body it is problem , by the way I tried something like your example but didnt work for me

@markst
Copy link

markst commented May 22, 2017

@mareapp ah sorry, my example won't work unless you're using branch here: #154

@markst
Copy link

markst commented May 22, 2017

Not sure if the above can be archived without modifying or writing your own SerializeOperation

let serializedRelationship = [

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants