API Specification v0


#1

This topic describes and discusses the basics of Incommon API.

This is not an official specification: it will be specified in code using the OpenAPI model.

General Information

  • title: Incommon API
  • version: v0
  • codename: John (refers to Dewey)
  • description:
    Incommon API is a simple way to describe, produce and consume resources for social cartography and notably to identify, promote, and defend the commons.

This document describes the abstractions used in the API (Models) and the URIs used to interact with the resources (Routes).

Models

High-level Models

These models aggregate resources from the Incommon specification.

Agent

An agent is an Entity that manages a Resource.
An agent can be an individual but, more generally, is an organization.

Example: a university, a municipality, an association, a neighborhood council

In Dewey Maps: equivalent to a resource type manager.

An agent can have one or more users who will be able to manage resources on behalf of the Agent. Agents usually match #welcome:transition-actors groups here.

Event

An event associates a Resource to a Moment in time.
An event can be recurrent.

Location

A location associates a Resource to a Position in space.

Map

A map defines a collection of Resources according to a specific Classification. In other words, a map provides a specific view on the Incommon database, that is sufficient to display resources on a dynamic or static map, e.g., with Leaflet.

To simply display an existing map, calling the Incommon API with the Map ID is sufficient and will return either the JSON data to feed into Leaflet, or a complete map in an <iframe> through a <script> tag. E.g., <script src="https://api.incommon.cc/v1/maps/123.js"></script>.

In Dewey Maps: equivalent to a frame.

Classifications

In Incommon API, a classification is a two-level hierarchical categorization to present social cartographic data. Many classifications can ordinate the same data, with each giving way to a specific view. Incommon API limits categorization of data to two levels to avoid complexity, since already with two levels some data can appear in more than one category. Other forms of clustering data exist in the form of Descriptors (see below) or contextual grouping (e.g., at scale) offering dynamic filters for grouping data points using complex and evolving views – fitting different world views.

Type Description Example
Classification The set of containers The Dewey Maps classification
Category The grouping container in this Classification Drinking and Eating
Section The container for data points in this Category Cooking Classes

Descriptors

Descriptors are non-hierarchical organizations.

Type Description
Moment A time descriptor (Date, duration and recurrence)
Position A spatial descriptor (GIS position, e.g., Point or Polygon)
Tag A free-form textual descriptor

Resources

Resources are the proper data objects being mapped.

Type Description
Collection A group of other Resources, e.g., forming a route or a journey, or a thematic grouping
Entity A human individual or group, e.g., an organization, an association
Place A specific portion of territory in the world, e.g., a building, a bridge, a road, a forest
Service A form of human support that can be given or exchanged
Thing Something else, e.g., a tree, a fountain


La Ferme Maximilien
La Ressourcerie Namuroise
CORS: Cross-Origin Resource Sharing
#2

hello! thank you for this work. would is there any movement expected on this front ? we would like to contribute to this with reinventing brussels community of mappers. keep me in the loop @bigkid


#3

Salut HK,
ça clarifie les choses . Mais, je trouve la dĂ©finition de “place” un peu floue. Pourquoi ne pas la dĂ©finir comme “portion of territory, or large piece or infrastructure”?
On ne proposerait pas Ă  Marc d’intĂ©grer d’intĂ©grer une variable “type de ressource” sur maps.dewey.be
biseke

Collection
group of ressources (e.g., forming a route, a journey, or a thematic g.)

Service
form of human support that can be given or exchanged

Entity
human group (e.g., an organization, an association
)

Place
portion of territory, or large piece of infrastructure (a building, a bridge)

Thing
small object, (e.g., a tree, a fountain
)


#4

Routes

Voici les routes utilisĂ©es par l’API (v0). PATCH et PUT sont ici Ă©quivalents. Les routes correspondent aux URLs (adresses) Ă  appeler pour obtenir les ressources correspondantes.

On considĂšre l’hĂŽte de l’API comme Ă©tant :

  • en dĂ©veloppement : api.example.net
  • en production : api.incommon.cc
                 Prefix Verb   URI Pattern                                             Controller#Action
                   root GET    /                                                       home#index
                 status GET    /status(.:format)                                       status#index
          api_v0_agents GET    /v0/agents(.:format)                                    api/v0/agents#index {:subdomain=>"api", :format=>:json}
                        POST   /v0/agents(.:format)                                    api/v0/agents#create {:subdomain=>"api", :format=>:json}
           api_v0_agent GET    /v0/agents/:id(.:format)                                api/v0/agents#show {:subdomain=>"api", :format=>:json}
                        PATCH  /v0/agents/:id(.:format)                                api/v0/agents#update {:subdomain=>"api", :format=>:json}
                        PUT    /v0/agents/:id(.:format)                                api/v0/agents#update {:subdomain=>"api", :format=>:json}
                        DELETE /v0/agents/:id(.:format)                                api/v0/agents#destroy {:subdomain=>"api", :format=>:json}
          api_v0_events GET    /v0/events(.:format)                                    api/v0/events#index {:subdomain=>"api", :format=>:json}
                        POST   /v0/events(.:format)                                    api/v0/events#create {:subdomain=>"api", :format=>:json}
           api_v0_event GET    /v0/events/:id(.:format)                                api/v0/events#show {:subdomain=>"api", :format=>:json}
                        PATCH  /v0/events/:id(.:format)                                api/v0/events#update {:subdomain=>"api", :format=>:json}
                        PUT    /v0/events/:id(.:format)                                api/v0/events#update {:subdomain=>"api", :format=>:json}
                        DELETE /v0/events/:id(.:format)                                api/v0/events#destroy {:subdomain=>"api", :format=>:json}
       api_v0_locations GET    /v0/locations(.:format)                                 api/v0/locations#index {:subdomain=>"api", :format=>:json}
                        POST   /v0/locations(.:format)                                 api/v0/locations#create {:subdomain=>"api", :format=>:json}
        api_v0_location GET    /v0/locations/:id(.:format)                             api/v0/locations#show {:subdomain=>"api", :format=>:json}
                        PATCH  /v0/locations/:id(.:format)                             api/v0/locations#update {:subdomain=>"api", :format=>:json}
                        PUT    /v0/locations/:id(.:format)                             api/v0/locations#update {:subdomain=>"api", :format=>:json}
                        DELETE /v0/locations/:id(.:format)                             api/v0/locations#destroy {:subdomain=>"api", :format=>:json}
            api_v0_maps GET    /v0/maps(.:format)                                      api/v0/maps#index {:subdomain=>"api", :format=>:json}
                        POST   /v0/maps(.:format)                                      api/v0/maps#create {:subdomain=>"api", :format=>:json}
             api_v0_map GET    /v0/maps/:id(.:format)                                  api/v0/maps#show {:subdomain=>"api", :format=>:json}
                        PATCH  /v0/maps/:id(.:format)                                  api/v0/maps#update {:subdomain=>"api", :format=>:json}
                        PUT    /v0/maps/:id(.:format)                                  api/v0/maps#update {:subdomain=>"api", :format=>:json}
                        DELETE /v0/maps/:id(.:format)                                  api/v0/maps#destroy {:subdomain=>"api", :format=>:json}
api_v0_deck_suite_cards GET    /v0/decks/:deck_id/suites/:suite_id/cards(.:format)     api/v0/cards#index {:subdomain=>"api", :format=>:json}
                        POST   /v0/decks/:deck_id/suites/:suite_id/cards(.:format)     api/v0/cards#create {:subdomain=>"api", :format=>:json}
 api_v0_deck_suite_card GET    /v0/decks/:deck_id/suites/:suite_id/cards/:id(.:format) api/v0/cards#show {:subdomain=>"api", :format=>:json}
                        PATCH  /v0/decks/:deck_id/suites/:suite_id/cards/:id(.:format) api/v0/cards#update {:subdomain=>"api", :format=>:json}
                        PUT    /v0/decks/:deck_id/suites/:suite_id/cards/:id(.:format) api/v0/cards#update {:subdomain=>"api", :format=>:json}
                        DELETE /v0/decks/:deck_id/suites/:suite_id/cards/:id(.:format) api/v0/cards#destroy {:subdomain=>"api", :format=>:json}
     api_v0_deck_suites GET    /v0/decks/:deck_id/suites(.:format)                     api/v0/suites#index {:subdomain=>"api", :format=>:json}
                        POST   /v0/decks/:deck_id/suites(.:format)                     api/v0/suites#create {:subdomain=>"api", :format=>:json}
      api_v0_deck_suite GET    /v0/decks/:deck_id/suites/:id(.:format)                 api/v0/suites#show {:subdomain=>"api", :format=>:json}
                        PATCH  /v0/decks/:deck_id/suites/:id(.:format)                 api/v0/suites#update {:subdomain=>"api", :format=>:json}
                        PUT    /v0/decks/:deck_id/suites/:id(.:format)                 api/v0/suites#update {:subdomain=>"api", :format=>:json}
                        DELETE /v0/decks/:deck_id/suites/:id(.:format)                 api/v0/suites#destroy {:subdomain=>"api", :format=>:json}
           api_v0_decks GET    /v0/decks(.:format)                                     api/v0/decks#index {:subdomain=>"api", :format=>:json}
                        POST   /v0/decks(.:format)                                     api/v0/decks#create {:subdomain=>"api", :format=>:json}
            api_v0_deck GET    /v0/decks/:id(.:format)                                 api/v0/decks#show {:subdomain=>"api", :format=>:json}
                        PATCH  /v0/decks/:id(.:format)                                 api/v0/decks#update {:subdomain=>"api", :format=>:json}
                        PUT    /v0/decks/:id(.:format)                                 api/v0/decks#update {:subdomain=>"api", :format=>:json}
                        DELETE /v0/decks/:id(.:format)                                 api/v0/decks#destroy {:subdomain=>"api", :format=>:json}
         api_v0_moments GET    /v0/moments(.:format)                                   api/v0/moments#index {:subdomain=>"api", :format=>:json}
                        POST   /v0/moments(.:format)                                   api/v0/moments#create {:subdomain=>"api", :format=>:json}
          api_v0_moment GET    /v0/moments/:id(.:format)                               api/v0/moments#show {:subdomain=>"api", :format=>:json}
                        PATCH  /v0/moments/:id(.:format)                               api/v0/moments#update {:subdomain=>"api", :format=>:json}
                        PUT    /v0/moments/:id(.:format)                               api/v0/moments#update {:subdomain=>"api", :format=>:json}
                        DELETE /v0/moments/:id(.:format)                               api/v0/moments#destroy {:subdomain=>"api", :format=>:json}
       api_v0_positions GET    /v0/positions(.:format)                                 api/v0/positions#index {:subdomain=>"api", :format=>:json}
                        POST   /v0/positions(.:format)                                 api/v0/positions#create {:subdomain=>"api", :format=>:json}
        api_v0_position GET    /v0/positions/:id(.:format)                             api/v0/positions#show {:subdomain=>"api", :format=>:json}
                        PATCH  /v0/positions/:id(.:format)                             api/v0/positions#update {:subdomain=>"api", :format=>:json}
                        PUT    /v0/positions/:id(.:format)                             api/v0/positions#update {:subdomain=>"api", :format=>:json}
                        DELETE /v0/positions/:id(.:format)                             api/v0/positions#destroy {:subdomain=>"api", :format=>:json}
            api_v0_tags GET    /v0/tags(.:format)                                      api/v0/tags#index {:subdomain=>"api", :format=>:json}
                        POST   /v0/tags(.:format)                                      api/v0/tags#create {:subdomain=>"api", :format=>:json}
             api_v0_tag GET    /v0/tags/:id(.:format)                                  api/v0/tags#show {:subdomain=>"api", :format=>:json}
                        PATCH  /v0/tags/:id(.:format)                                  api/v0/tags#update {:subdomain=>"api", :format=>:json}
                        PUT    /v0/tags/:id(.:format)                                  api/v0/tags#update {:subdomain=>"api", :format=>:json}
                        DELETE /v0/tags/:id(.:format)                                  api/v0/tags#destroy {:subdomain=>"api", :format=>:json}
     api_v0_collections GET    /v0/collections(.:format)                               api/v0/collections#index {:subdomain=>"api", :format=>:json}
                        POST   /v0/collections(.:format)                               api/v0/collections#create {:subdomain=>"api", :format=>:json}
      api_v0_collection GET    /v0/collections/:id(.:format)                           api/v0/collections#show {:subdomain=>"api", :format=>:json}
                        PATCH  /v0/collections/:id(.:format)                           api/v0/collections#update {:subdomain=>"api", :format=>:json}
                        PUT    /v0/collections/:id(.:format)                           api/v0/collections#update {:subdomain=>"api", :format=>:json}
                        DELETE /v0/collections/:id(.:format)                           api/v0/collections#destroy {:subdomain=>"api", :format=>:json}
        api_v0_entities GET    /v0/entities(.:format)                                  api/v0/entities#index {:subdomain=>"api", :format=>:json}
                        POST   /v0/entities(.:format)                                  api/v0/entities#create {:subdomain=>"api", :format=>:json}
          api_v0_entity GET    /v0/entities/:id(.:format)                              api/v0/entities#show {:subdomain=>"api", :format=>:json}
                        PATCH  /v0/entities/:id(.:format)                              api/v0/entities#update {:subdomain=>"api", :format=>:json}
                        PUT    /v0/entities/:id(.:format)                              api/v0/entities#update {:subdomain=>"api", :format=>:json}
                        DELETE /v0/entities/:id(.:format)                              api/v0/entities#destroy {:subdomain=>"api", :format=>:json}
          api_v0_places GET    /v0/places(.:format)                                    api/v0/places#index {:subdomain=>"api", :format=>:json}
                        POST   /v0/places(.:format)                                    api/v0/places#create {:subdomain=>"api", :format=>:json}
           api_v0_place GET    /v0/places/:id(.:format)                                api/v0/places#show {:subdomain=>"api", :format=>:json}
                        PATCH  /v0/places/:id(.:format)                                api/v0/places#update {:subdomain=>"api", :format=>:json}
                        PUT    /v0/places/:id(.:format)                                api/v0/places#update {:subdomain=>"api", :format=>:json}
                        DELETE /v0/places/:id(.:format)                                api/v0/places#destroy {:subdomain=>"api", :format=>:json}
        api_v0_services GET    /v0/services(.:format)                                  api/v0/services#index {:subdomain=>"api", :format=>:json}
                        POST   /v0/services(.:format)                                  api/v0/services#create {:subdomain=>"api", :format=>:json}
         api_v0_service GET    /v0/services/:id(.:format)                              api/v0/services#show {:subdomain=>"api", :format=>:json}
                        PATCH  /v0/services/:id(.:format)                              api/v0/services#update {:subdomain=>"api", :format=>:json}
                        PUT    /v0/services/:id(.:format)                              api/v0/services#update {:subdomain=>"api", :format=>:json}
                        DELETE /v0/services/:id(.:format)                              api/v0/services#destroy {:subdomain=>"api", :format=>:json}
          api_v0_things GET    /v0/things(.:format)                                    api/v0/things#index {:subdomain=>"api", :format=>:json}
                        POST   /v0/things(.:format)                                    api/v0/things#create {:subdomain=>"api", :format=>:json}
           api_v0_thing GET    /v0/things/:id(.:format)                                api/v0/things#show {:subdomain=>"api", :format=>:json}
                        PATCH  /v0/things/:id(.:format)                                api/v0/things#update {:subdomain=>"api", :format=>:json}
                        PUT    /v0/things/:id(.:format)                                api/v0/things#update {:subdomain=>"api", :format=>:json}
                        DELETE /v0/things/:id(.:format)                                api/v0/things#destroy {:subdomain=>"api", :format=>:json}
                 api_v0 GET    /v0/*path(.:format)                                     home#dispatcher
                 api_v1 GET    /v1/*path(.:format)                                     home#dispatcher

#5

The difference between a Place and a Thing is not entirely easy to distinguish, especially if you say one is “large” and the other “small”. There can be large fountains and small bridges. The distinct trait to me is whether you can see a single object or consider a usable artifact: e.g., a building can be entered, a bridge can be crossed
 Already this distinction is problematic: a fountain or a tree can be climbed. Usually, a Place has an address, while a Thing belongs to a Place.


#6

@sylvainlohest, @Audrey,

pourriez-vous s’il vous plaĂźt jeter un Ɠil Ă  la spĂ©cification en cours et Ă©valuer l’intĂ©gration avec vos modĂšles?

Quels sont vos outils pour intégrer et partager de nouvelles données ?

Comment est structurée votre base de données ? Est-elle disponible par une API existante ?

Quelles opérations effectuez-vous sur ces données (avant de les partager) ? Notamment : import, édition, export, classification, transformation


Cela m’aidera à voir plus clair dans les contraintes à prendre en compte



#7

Pas de réponse, bonne réponse ?


#8

Nous importons 4 “flux” à travers le module FEEDS de notre site Drupal, qui mange du xml ou du fichier excel.

La base de donnĂ©es n’a pas Ă©tĂ© pensĂ©e pour la carto : j’ai simplement utilisĂ© le module “fields” du core de Drupal, qui crĂ©e
 une table par champ. TrĂšs facile et modulaire dans l’interface backend, mais un vrai casse-tĂȘte si l’on veut regarder la base de donnĂ©es MySQL :wink: !

Pour pouvoir afficher la carte, d’autres modules Drupal interviennent, notamment views qui gĂ©nĂšre un fichier GeoJSON que notre carte leaflet peut afficher.

Au moment de l’import avec le module FEEDS, j’applique quelques scripts PHP pour traiter les donnĂ©es : lier l’entitĂ© contact Ă  la bonne initiative, lier les bonnes communes Ă  l’initiative, parfois extraire l’adresse email ou le numĂ©ro de tĂ©lĂ©phone d’un popup Ă©crit en html (repair cafĂ©s)


#9

Ca reste un peu obscur pour moi, surtout en anglais ;-). Dans l’optique d’intĂ©grer la carte du RCR, il me semble important de pouvoir :

  • dĂ©finir diffĂ©rents types d’initiative, avec pour chaque type diffĂ©rents champs prĂ©cis (donc un modĂšle initiative que l’on pourrait Ă©tendre pour chaque type d’initiative – il y en a 6 actuellement)
  • attacher Ă  chaque initiative une OU PLUSIEURS personnes de contact ou association contact (donc un modĂšle contact Ă©tendu Ă  deux types : personne physique ou association)
  • lier chaque initiative Ă  la fois Ă  un point prĂ©cis et Ă  une ou plusieurs communes (place, si j’ai bien compris)

#10

Je suis curieux de le voir :slight_smile:

Cela va dans la classification : RCR aura sa propre classification qui correspondra à ces types d’initiatives.

Parmi les ressources (Resource) on a des entitĂ©s (Entity) qui peuvent ĂȘtre des organisations ou des personnes. Pour chaque initiative, on peut dĂ©finir un Agent qui est une entitĂ©, et auquel on peut associer un ou plusieurs utilisateurs (encore indĂ©finis : pour ĂȘtre compatible avec ActivityStreams et ActivityPub cela devrait ĂȘtre des “acteurs” (Actor)) : les personnes qui seront responsables des ressources intĂ©grĂ©es dans la base de donnĂ©e. Cela signifie que chaque Agent recevra des notifications sur les changements affectant les ressources dont il est responsable ; ainsi chaque personne reprĂ©sentant cet Agent pourra intervenir pour valider ou corriger les donnĂ©es.

Les initatives en ce sens sont des #welcome:transition-actors – des entitĂ©s (Entity). Les communes, effectivement sont des lieux (Place).

Bon, avec tous ces Ă©lĂ©ments je devrais pouvoir approcher le modĂšle plus simplement – ou 'complĂšxement` qu’un champ par table. :wink:


#11

@how ça donne ceci : https://www.asblrcr.be/donnerie_geojson.txt (exemple pour les donneries, il y en a un par initiative)


#12

While I understand the link with hierarchy and classification I find the idea of a card game very strange to associate to cartography, also not everyone is familiar with the card vocabulary. I would rather associate the classification with an idea of territory, maybe:

Type Description Metaphor equivalent
Territory Top-level container for a classification The largest area that hosts the projects
Domain A category in this classification A specific domain where similar projects are developed
Place A section in this category Where people gather under the same roof of ideas

Also as an important work on categorisation has been done by maps.dewey I suggest that we start by documenting this, since it might inspire and help a number of other cartographies.


#15

@natacha, I updated the description: can you validate?


#16

Agents

Agents manage Resources.

Agents are resources themselves, of type Entity, and as such may appear on
Incommon maps.

Originally, Agents came from the distinction made in Dewey Maps on ‘resource
manager types’:

In Dewey Maps: Resource Manager Types

Code Name Rank
individu individu ou ‘association de fait’ 0
collectif association (asbl, vzw etc.) 10
entreprise entreprise à finalité sociale 20
admin. publique administration publique 30
autre autre 50

Incommon Equivalent

‘Resource Manager Types’ are Agents in Incommon API, which are Resources
of type Entity.

Dewey Code Incommon Agent Class Code Description Example
individu CitizenAgent CIT citizen initiative an individual
collectif CollectiveAgent ORG formal organization Dewey ASBL
entreprise CommercialAgent COM social business Bees Coop
admin. publique InstitutionalAgent GOV public institution Wallonia Region
N/A InternationalAgent INT international body UNESCO
autre Agent UAG unspecified agent

Agents have and belong to many Users. All resources are managed by one
Agent. Unmanaged resources are said ‘orphan’ and are ‘given’ to the ‘Incommon
Agent’ (UAG).

Code Example

me = CitizenAgent.new
me.summary = 'I am an individual living in Brussels, interested in free software and collective practices.'
puts me.summary # => (CIT) I am an individual living in Brussels, interested in
                #    free software and collective practices.
me.type         # => CitizenAgent

uag = Agent.find_by(name: 'Incommon Agent')
uag.email.address # => unspecified-agent@incommon.cc