How do you combine multiple profiles and/or include un-profiled data?

65 views
Skip to first unread message

Stephen Karger

unread,
Jan 19, 2016, 10:14:21 PM1/19/16
to API Craft
Hello all,

In an attempt to follow Mike Amundsen's advice in "Restful Web APIs," I'm trying to design an API that uses existing profiles for application semantics, as opposed to making up my own taxonomy. For people familiar with the book, chapters 8, 9, and 10 are relevant to this question.

I've found a few formats that come close but don't cover everything I need. Ideally I could combine the handful of profiles that each partially fit my domain, but I'm not sure how to do that, especially not in the same document.
Furthermore, some of my needed semantics are not covered by any of these profiles. It's not feasible for me to create a formal profile that encompasses all my semantics - I don't have the resources to register/extend profiles published by IANA, schema.org, and the like. Therefore I'll need to have fields in my API that aren't covered by a profile.

I'm curious if any of you have dealt with situations like this and how you proceeded.
1. How have you combined multiple semantic profiles in an API? Or do you avoid doing so?
2. How do you treat un-profiled fields?
3. How do you merge domain specific formats with pure hypermedia formats like HTML, HAL, JSON-API, UBER, etc.?


To make this more concrete I'll give a summary of my domain and the profiles:

I'm designing an API related to bus transit. The goal is to show bus routes, stop locations, arrival times, alerts about changes and disruptions in service, and other related information. Many people have put thought into this domain already and there are several existing profiles:

- General Transit Feed Specification (GTFS):  https://developers.google.com/transit/gtfs/?hl=en
-- Formatted as a collection of CSV files, intended for infrequently updated service info, like a public transit agencies quarterly schedules.

-- Uses google protocol buffers, intended to pass timely info to clients, like the fact that a bus is 3 minutes away from a stop right now.

-- The documentation encourages embedding the schema.org semantics within JSON-LD documents, although they also have some microdata/RDFa examples.

Again I also have semantics specific to other aspects of a user's interaction with our business, and aren't covered in these existing transit profiles. Those are the un-profiled semantics I mentioned above. I'm not sure how to include those attributes in my API along with the profiled data.

Finally, the profiles above do not directly support hypermedia (aside from JSON-LD in schema.org). Therefore I would like to embed them within a media type like vnd.api+json or application/vnd.amundsen-uber+json. The problem however is that by cramming the domain-specific schemas inside the schema defined by a media type, I may undermine clients' ability to parse the domain specific profile. For example, existing GTFS parsers that expect CSV will not be able to parse a JSON translation of the GTFS schema that's embedded inside the `data` element of an UBER or JSON-API document.

I'm wondering if it's even helpful to make the effort to "reconcile names" to these domain specific schemas, given that we'll need to create custom clients to parse the combined profiles anyway.

Thanks in advance for any input you all have on these topics.
Stephen

mca

unread,
Feb 28, 2016, 6:13:25 PM2/28/16
to api-...@googlegroups.com
haven't seen anyone jump in on this, so i'll offer my take on it.


when designing ALPS, one of the drivers was the need to combine bits and pieces of other vocabularies. ALPS was designed, in part, to be the place to do this combination.  So, pulling some elements from GTFS, schema.org, IANA, etc. into a single ALPS document is very easy. We need to improve the provenance element (it's not easy to indicate sources in machine-readable form ATM), but the design elements are there.

also, through experience in writing clients that consume ALPS profiles, i;m finding it to be difficult to parse out *multiple* profile references at runtime. for this reason, i'm finding it a "best practice" to use just a single profile reference in the headers (or at the top of a doc). 

finally, it is technically possible to refer to other ALPS document *within* a single doc (a kind of XML include pattern). I've done this a bit, but the runtime resolution gets messy quickly -- as does the semantic resolution for name conflicts, etc. for this reason, i am establishing another BP to *not* do much external document referencing in ALPS.

so the pattern that seems most effective, both at design-time and runtime is to use ALPS as a "collection point" from various vocabularies, create a single flat ALPS document that describes the domain details directly w/o nesting, and send only one ALPS reference in each response.

hope this helps and would love to hear more about your project.

cheers.



--
You received this message because you are subscribed to the Google Groups "API Craft" group.
To unsubscribe from this group and stop receiving emails from it, send an email to api-craft+...@googlegroups.com.
Visit this group at https://groups.google.com/group/api-craft.
For more options, visit https://groups.google.com/d/optout.

sgoto

unread,
Mar 2, 2016, 5:01:58 PM3/2/16
to api-...@googlegroups.com
Just as a data point, schema.org has an extension mechanism that allows you to add new properties to existing types or new types. 


Might be worth looking into it.

Example:

<script type="application/ld+json">
{
    "@context": "http://schema.org/",
    "@vocab": "http://gs1.schema.org/",
    "@id": "http://id.manufacturer.com/gtin/05011476100885",
    "gtin13": "5011476100885",
    "@type": "TradeItem",
    "tradeItemDescription": "Deliciously crunchy Os, packed with 4 whole grains. Say Yes to Cheerios",
    "healthClaimDescription": "8 Vitamins & Iron, Source of Calcium & High in Fibre",
    "hasAllergenRelatedInformation": {
        "@type": "gs1:AllergenRelatedInformation",
        "allergenStatement": "May contain nut traces"
    },
    "hasIngredients": {
        "@type": "gs1:FoodAndBeverageIngredient",
        "hasIngredientDetail": [
            {
                "@type": "Ingredient",
                "ingredientseq": "1",
                "ingredientname": "Cereal Grains",
                "ingredientpercentage": "77.5"
            },
            {
                "@type": "Ingredient",
                "ingredientseq": "2",
                "ingredientname": "Whole Grain OATS",
                "ingredientpercentage": "38.0"
            }
      ]
    },
    "nutrientBasisQuantity": {
        "@type": "Measurement",
        "value": "100",
        "unit": "GRM"
    },
    "energyPerNutrientBasis": [
        {
            "@type": "Measurement",
            "value": "1615",
            "unit": "KJO"
        },
        {
            "@type": "Measurement",
            "value": "382",
            "unit": "E14"
        }
    ],
    "proteinPerNutrientBasis": {
        "@type": "Measurement",
        "value": "8.6",
        "unit": "GRM"
    }
}

</script>

--
f u cn rd ths u cn b a gd prgmr !
Reply all
Reply to author
Forward
0 new messages