The FamilySearch API is designed to adhere to RESTful principles, especially that of caching. Caching influences much of the design of the API.

Why Caching?

The goal of caching is to increase performance. This is done in several ways:

  • Client caching can prevent the need for some network requests.

  • Reverse cache proxies can respond to requests without the origin servers and databases needing to respond.

  • Servers can be allowed to tell clients that their cache is still valid, decreasing the number of network requests.

The central point is to enable more work to be done without having to make a costly request to the server. The more requests that the reverse cache proxies can respond to, the faster the application runs and the more it can scale. Everyone benefits from caching.

ETags

"An ETag is an opaque identifier assigned by a web server to a specific version of a resource found at a URL. If the resource content at that URL ever changes, a new and different ETag is assigned. Used in this manner ETags are similar to fingerprints, and they can be quickly compared to determine if two versions of a resource are the same or not. Comparing ETags only makes sense with respect to one URL; ETags for resources obtained from different URLs may or may not be equal, so no meaning can be inferred from their comparison." -Wikipedia

The FamilySearch API provides ETags on Persons, Relationships, and Change History. The ETags are weak, meaning that resources with matching ETags are semantically equivalent, but not byte-for-byte identical. In other words, the data is the same but might be in a different order.

While ETags are a replacement for version numbers, they are not sequential. That is, a comparison can determine only whether two resources are the same; a comparison cannot determine which revision is most recent.

To check the current version of a resource without being sent the actual resource in the response, you can do a HEAD request and check the ETag that is returned. HEAD requests return the same headers that would be returned in a GET request.

Request

HEAD /platform/tree/persons/KWQY-DCB

Response

HTTP/1.1 200 OK Last-Modified: Thu, 24 Jan 2013 21:59:56 GMT ETag: W/"a7bd095f6058737fc90e709453352acc74903a0b" Content-Type: application/xml Cache-Control: no-transform, max-age=3600 Content-Location: /platform/tree/persons/KWQY-DCB

You can also perform a conditional GET by specifying the If-None-Match header. A conditional GET means the resource is returned only if the ETag in the If-None-Match header does not match the current version. When the specified ETag does match the current version, a 304 Not Modified is returned.

Request

GET /platform/tree/persons/KWQY-DCB
If-None-Match: W/"a7bd095f6058737fc90e709453352acc74903a0b"

Response

HTTP/1.1 304 Not Modified
Last-Modified: Thu, 24 Jan 2013 21:59:56 GMT
ETag: W/"a7bd095f6058737fc90e709453352acc74903a0b"
Content-Type: application/xml
Cache-Control: no-transform, max-age=3600
Content-Location: /platform/tree/persons/KWQY-DCB

Conditional GETs prevent the need to perform a HEAD request to check for a new version and then performing a GET request to get the new version when available.

You can also perform a conditional POST by specifying the If-Match and If-Unmodified-Since headers. A conditional POST means the resource is updated only if the ETag in the If-Match header matches the current version. If the current version does not match the value of the ETag as specified in the If-Match header, a 412 Precondition Failed is returned.

Request

POST /platform/tree/persons/KWQY-DCB
If-Unmodified-Since: Thu Jan 14 15:40:24 MST 2016
If-Match: J8Y5VFR

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<gedcomx xmlns="http://gedcomx.org/v1/" xmlns:fs="http://familysearch.org/v1/" xmlns:atom="http://www.w3.org/2005/Atom">
<person id="12345">
  <fact type="http://gedcomx.org/Birth" id="ABCDE">
    <attribution>
      <changeMessage>...change message...</changeMessage>
    </attribution>
    <date>
      <original>3 Apr 1836</original>
    </date>
    <place>
      <original>Moscow, Russia</original>
      <normalized xml:lang="en">Moscow, Moskva, Russia</normalized>
    </place>
  </fact>
</person>
</gedcomx>

Response

HTTP/1.1 412 Precondition Failed
Transfer-encoding: chunked
Cache-control: no-cache, no-store, no-transform, must-revalidate, max-age=0
Vary: Accept-Encoding
Vary: Accept, Accept-Language, Accept-Encoding, Expect
Date: Thu, 14 Jan 2016 22:40:24 GMT
Warning: 400 FamilySearch "Unable to check preconditions.: java.text.ParseException: Error parsing entity tag: Error parsing entity tag"
X-processing-time: 1
Content-location: /platform/tree/persons/12345

Authorization Header

Caching is also the reason we recommend using the Authorization header to authenticate requests. If you use the access_token query parameter, then resources can be cached only for that session (since the cache is keyed by the URL). This is why the following warning header is applied to the response when you use the access_token query parameter:

Warning: 199 FamilySearch Best Practice Violation: Authorization header should be used instead of using the access_token query parameter.

Note In order to avoid CORS preflight requests, we acknowledge that the query parameter may need to be used.

Best Practices

Cached data may cause security problems. If an authorized user reads data into cache and the cache is not purged at the end of that user’s session, it may still be available to the next unauthorized user. For this reason, you should not store cached data in local memory, and you should purge cached data at the end of each user session and if the browser back button is used.