FamilySearch / familysearch-javascript-sdk

See the FamilySearch API Javascript SDK documentation at
http://familysearch.github.io/familysearch-javascript-sdk
MIT License
42 stars 25 forks source link

Create Source Reference failing #160

Open dovy opened 8 years ago

dovy commented 8 years ago

I keep trying all I can, but I can't get a source to attach to a person.

var $sourceRef = fsAPI.createSourceRef(
        {
            'tags': tags,
            'sourceDescription': $rootScope.data.sourceDescription,
            'attachedEntityId': $rootScope.data.attach.pid
        }
    );

That works fine, but the $sourceRef.save() won't seem to work no matter what I do. I've tried passing in ('', 'Attach note here') or even fetching the person again and placing in there. Save fails every time.

Any ideas? What should it be?

Also, where can you specify the source box id as well? is moveSourceDescriptionsToCollection the only way? In the past it was part of the constructor if I recall.

justincy commented 8 years ago

I guess the docs aren't very clear on this.

fsAPI.createSourceRef() creates the SourceReference, which has this schema:

    {
      "attribution" : {
        "changeMessage" : "Family is at the same address found in other sources associated with this family.  Names are a good match.  Estimated births are reasonable."
      },
      "description" : "https://familysearch.org/platform/sources/descriptions/MMMM-MMM",
      "tags" : [ {
        "resource" : "http://gedcomx.org/Name"
      }, {
        "resource" : "http://gedcomx.org/Gender"
      }, {
        "resource" : "http://gedcomx.org/Birth"
      } ]
    }

So one obvious problem is that your schema is wrong.

Second, the SourceReference.save() method has this signature: save(url, changeMessage). The docs explain what the URL is: "url for a person, couple, or child and parents source references endpoint."

You can either fetch that url yourself via person.getLink('source-references').href which gives you

sourceRef.save(person.getLink('source-references').href, 'A change message')

Or you can call person.addSource($rootScope.data.sourceDescription, 'A change message', tags).

All that convoluted mess is due to collections and the requirement that URLs be obtained via specific resource paths.

Now, that's how it used to work. But the updated version of the API no longer returns the source-references link so right now it's practically impossible with the SDK. At least I don't know how. You'll have to ask FS how sources are attached.

stoicflame commented 8 years ago

The source-references link is defined as an "embedded link" on the person. So if the person doesn't have a link to source-references, then you just assume that source references are included on the person and you POST the source reference directly to the person.

Before Tree Foundation, source references were a separate resource. After Tree Foundation, source references are included on the person. Hence the link was removed. The same concept also applies to discussion references, memory references, child relationships, spouse relationships, and parent relationships.

Hypermedia is a tricky concept, and FamilySearch hasn't done a good job of explaining how it's working, so this bug is really on us. But it is a bug in the SDK and not a breaking change in the API, so it needs to get fixed here.

(And just for the record, this doesn't really have anything to do with collections; it worked this way before collections, too.)

jimmyz commented 8 years ago

The change that removed the "source-references" link conforms to the GEDCOM X RS spec regarding "Embedded States". Therefore, it was considered a backwards compatible change. I will note that this wasn't well understood or communicated during the SDK's hypermedia implementation.

See the spec information on a Person's Embedded States.

My understanding is that if the source references are embedded on the person, the source references would be posted to the Person's resource URI similar to adding facts to the person. However, the Source References docs don't reflect this.

Confirmed by @stoicflame. (His post hit 10 seconds before mine)

stoicflame commented 8 years ago

Wow. Jimmy and I were responding to this at the exact same time :-).

dovy commented 8 years ago

I updated my code to bypass the helper functions of the SDK. Here's what I did:

var id = $sourceRef.data.links['source-reference'].href.split('?')[0].split('/');
id = id[id.length-1];

This provided me with the proper sourceRef id, and I was able to proceed forward.

Can we update the SDK so getId() works for the $sourceRef, please?

justincy commented 8 years ago

@stoicflame Any tips on how embedded states can be detected? Do we just need to mark certain links/objects as embedded and program logic to check whether a link exists for them?

justincy commented 8 years ago

@dovy What's the context here? getId() only fails when the object doesn't have an id property. The SDK isn't setup to extract IDs from URLs. If that's necessary then you're probably doing something the hard way.

justincy commented 8 years ago

@stoicflame I see now that the RS spec lists embedded states for each application state.

FWIW, it's unlikely that this SDK will ever support that.

justincy commented 8 years ago

Adapting to the current changes in the behavior of source references will require breaking changes (remove obsolete getSourceRefs() method on the client object and change getSourceRefs() on persons and relationships to be return the data if available locally instead of retrieving it from the API) and thus requires a major release. I don't know when that will happen.