Raccourci clavier : P -> permet d'afficher le plan Raccourci clavier : C -> permet d'ouvrir une autre fenêtre avec les slides
Bonjour à tous. Merci d'être venu si nombreux.
Je m'appelle François Dume.
Raccourci clavier : P -> permet d'afficher le plan Raccourci clavier : C -> permet d'ouvrir une autre fenêtre avec les slides
Bonjour à tous. Merci d'être venu si nombreux.
Je m'appelle François Dume.
-->
Au niveau numérique, ARTE édite un certain nombre de sites internet : arte.tv
Future, plateforme dédiée à la science
Creative, plateforme dédiée aux arts visuels et numériques
Concert, anciennement Arte Live Web
Cinéma, qui permet de retrouver les films diffusés à l'antenne
Tracks, exemple de site d'une émission
...
On développe une solution de CatchUP (ARTE+7). Cette solution est packagée dans la plupart des box des opérateurs. On développe également des applications pour les TV connectées (hbbtv).
Pour pouvoir développer ces magnifiques applications, nous avons besoin d'API.
plage de droits, heures de diffusion
{ "videos": [ { "id": "055075-000-A_SHOW_ALW_FR_fr", "programId": "055075-000-A", "channel": "FR", "language": "fr", "kind": "SHOW", "platform": "ALW", "title": "Angus & Julia Stone \u00e0 la Maroquinerie", "originalTitle": "Angus & Julia Stone \u00e0 la Maroquinerie", "durationSeconds": 3101, "shortDescription": "Depuis Down The Way en 2010, Angus et Julia s'\u00e9taient \u00e9chapp\u00e9s chacun de leur c\u00f4t\u00e9 chantant l'un sans l'autre pendant un temps. La s\u00e9paration ne f\u00fbt heureusement pas d\u00e9finitive puisque les fr\u00e8res et soeurs retrouvent aujourd'hui le chemin vers de nouvelles sc\u00e8nes. Les retrouvailles se scellent \u00e9galement dans un troisi\u00e8me album o\u00f9 les puret\u00e9s folk et les m\u00e9lodies fredonn\u00e9es c\u00f4toient les ballades cotonneuses et les mots doux. ", "producer": "ARTE FRANCE", "videoRightsBegin": "2014-08-25T17:00:00Z", "videoRightsEnd": "2015-02-25T22:59:00Z", "mainImage": { "name": "055075-000_1392179_32_202.jpg", "extension": "jpg", "caption": "Angus & Julia Stone", "url": "http:\/\/www.arte.tv\/prog_img\/IMG_APIOS\/055000\/055000\/055075-000_1392179_32_202.jpg" }, "programmingId": 1781191, "mainReassembly": true, "reassembly": "A", "reassemblyRef": "A",
Nous disposons déjà d'une API qui permet de mettre à disposition le contenu antenne.
Pas seulement le contenu broadcast mais également les contenus développés pour le web. On a de plus en plus de contenu créé uniquement pour le web qui dispose d'un workflow différent de publication.
Mis en production pour 24h Jerusalem en avril 2014. Début du développement décembre. Utilisé par Tracks.
curl https://.../oauth/token?client_id=...&client_secret=...&grant_type=credentials
Réponse :
{"access_token":"MDBjYzMzNTRjNTQxM...","expires_in":3600,"token_type":"bearer","scope":"user","refresh_token":"ZTJjZTEyOWFiNjQ1YTkw...","roles":["USER"],"rate_limit":1000}
curl -I https://.../api1/resource?access_token=MDBjY...
HTTP/1.1 200 OKServer: openrestyDate: Thu, 23 Oct 2014 19:51:39 GMTContent-Type: application/vnd.api+jsonVary: X-ARTE-RolesX-Rate-Limit-Limit: 1000X-Rate-Limit-Remaining: 999X-Rate-Limit-Reset: 1412887899...
curl -I https://.../api1/resource?access_token=MDBjY...
HTTP/1.1 429 Too Many RequestsServer: openresty
Un Reverse Proxy qui protège toutes nos applications. Une application oauth : Symfony2, FOSOauthServerBundle, fournisseur d'identités Plusieurs API (api1, api2). Une base de données clé-valeurs associée au serveur nginx. Cette base de donnée sert de cache et de stockage du suivi de l'usage (Redis, mémoire partagée, memcache).
(1) L'utilisateur fait une requête à une de nos API avec un token
curl -I https://.../api1/resource?access_token=MDBjY...
Il passe en paramètre le access_token oAuth.
(2) nginx va essayer de valider le token oAuth en effectuant une sous-requête au fournisseur d'identité (oAuth 2.0) :
local token = ngx.var.arg_access_tokenlocal subrequest = ngx.location.capture( '/oauth/verifToken?access_token=' .. token)if subrequest.status == ngx.HTTP_OK then local content = subrequest.body ...end
Cette sous-requête ne sera exécutée que lorsque nginx ne connait pas le token.
(3) Si le token est valide, le serveur oAuth va retourner au serveur nginx des informations liées au token :
HTTP/1.1 200 OKServer: openresty...{"client": "Tracks","rateLimit": 1000,"expires": 3600,"roles" : "USER"...}
(4) Ces informations seront stockées par nginx dans une base de données clé-valeur, le compteur de requêtes est décrémenté.
local succ, err, forcible = cache:set( key, content, contentLife)...cache:incr('throttle_' .. key, 1)
N.B : À la requête suivante, le Reverse Proxy n'interrogera plus le serveur oAuth, il lira son cache et décrémentera le compteur de requêtes (remaining).
(5) Si le token est valide, le Reverse Proxy accepte de rediriger la requête au backend et ajoute des entêtes à la requête (rôles) :
GET http://api1.local/api1/resourceX-ARTE-Roles: USER
La réponse du backend contient bien un entête pour faire varier le cache :
Vary: X-ARTE-Roles
(6) Le backend traite la réponse. En renvoyant la réponse, le Reverse Proxy ajoute les entêtes de suivi d'usage :
ngx.header["X-Rate-Limit-Limit"] = userRateLimitngx.header["X-Rate-Limit-Remaining"] = remainingngx.header["X-Rate-Limit-Reset"] = expiresAt
(7) \o/ L'utilisateur reçoit la réponse
HTTP/1.1 200 OKServer: openrestyContent-Type: application/vnd.api+jsonCache-Control: max-age=60, public, s-maxage=60Vary: X-ARTE-RolesX-Rate-Limit-Limit: 5000X-Rate-Limit-Remaining: 4997X-Rate-Limit-Reset: 1413659922{ "content" : ...}
location /api1 { # lua_code_cache off; # Dev : disable cache set $roles ''; # This variable is set by lua script access_by_lua_file /dir/oauth-throttle.lua; header_filter_by_lua_file /dir/header-filter.lua; proxy_pass http://api1.local; proxy_set_header X-Roles $roles;}# api2 n'est pas protégé par oAuthlocation /api2 { proxy_pass http://api2.local;}
Pour aller plus loin, documentation du module Lua pour nginx
Description des directives
Prévision :
Configuration mutualisée sur toute la plate-forme, difficilement modifiable
S'appuyer sur un standard pour construire toutes nos API. Il n'a rien de très révolutionnaire. Ce standard décrit certains mécanismes qui sont des standards de facto. Il détaille à la fois le format de la réponse JSON mais également la manière de requêter l'API.
L'objectif de JSON API est conçu pour limiter le nombre de requêtes et la taille des requêtes à réaliser entre le client et le serveur.
A JSON object MUST be at the root of every JSON API document. This object defines a document's "top level".
A document's top level SHOULD contain a representation of the resource or collection of resources primarily targeted by a request (i.e. the "primary resource(s)").
The primary resource(s) SHOULD be keyed either by their resource type or the generic key "data".
A document's top level MAY also have the following members:
- "meta": meta-information about a resource, such as pagination.
- "links": URL templates to be used for expanding resources' relationships URLs.
- "linked": a collection of resource objects, grouped by type, that are linked to the primary resource(s) and/or each other (i.e. "linked resource(s)").
No other members should be present at the top level of a document.
GET /posts?limit=1
{ "links": { "posts.author": { "href": "http://example.com/people/{posts.author}", "type": "people" }, "posts.comments": { "href": "http://example.com/comments/{posts.comments}", "type": "comments" } }, "posts": [{ "id": "1", "href" : "http://example.com/posts/1" "title": "Rails is Omakase", "links": { "author": "9", "comments": [ "5", "12", "17", "20" ] } }]}
{json:api} décrit la manière d'inclure des sous-documents (réduction du nombre de requêtes)
GET /users?limit=1&include=groups
{... "users": [ { "id": "gaston", "username": "Gaston", "href": "https://server/users/gaston", "links": { "groups": {"href": "https://server/groups?user=gaston"} } } } ], "linked" : { "groups": [ { "id": "group1", "name" : "group1", "href": "https://server/groups/group-1", }, { "id": "group-2", "name" : "group2", "href": "https://server/groups/group-2", }, ] }}
{json:api} décrit comment limiter les attributs retournés :
GET /users?limit=1&fields=id
{"users": [ { "id": "gaston", "href": "https://server/users/gaston", "links": { "groups": {"href": "https://server/groups?user=gaston"} } } } ]}
GET /users?limit=1&fields=id,name
{"users": [ { "id": "gaston", "name": "Gaston", "href": "https://server/users/gaston", "links": { "groups": {"href": "https://server/groups?user=gaston"} } } } ]}
GET /users?enable=true&tags=marsupilami,spirou&fields=name&include=groups&sort=-id
Retourne la liste des utilisateurs actifs triés par id possédant les tags marsupilami et spirou en incluant les groupes associés à ces utilisateurs. On ne retourne que le champ name.
utilisation d'annotations pour ajouter les links à la volée ('serializer.post_serialize')
use Hateoas\Configuration\Annotation as Hateoas;/** * @Hateoas\Relation("programs", * href = @Hateoas\Route("arte_api_v2_programs", * parameters = { * "programId" = "expr(object.getProgramId())", * "language" = "expr(object.getLanguage())", * "kind" = "expr(object.getKind())" * }, * absolute = true * ) * )
va générer : https://server/api1/programs?programId=0123456-FZD&language=fr&kind=SHOW
utilisation d'un 'serializer.post_serialize'
mise en place d'une classe ExclusionStrategy (ping @damienalexandre)
namespace Acme\Bundle\ApiBundle\Serializer\Exclusion;use JMS\Serializer\Exclusion\ExclusionStrategyInterface;class FieldsListExclusionStrategy implements ExclusionStrategyInterface.../** * {@inheritDoc} */public function shouldSkipProperty(PropertyMetadata $property, Context $navigatorContext){ if (empty($this->fields)) { return false; } $name = $property->serializedName ?: $property->name; return !in_array($name, $this->fields);}
Juste pour information, voici notre stack technique. Historiquement, nous faisions beaucoup de Java. Nous avons de plus en plus de Drupal. On a un peu de Go, de Ruby. On a bien sûr du Symfony2. Et puisque c'est la mode, on fait aussi un peu de docker ;-)
Je m'appelle François Dume.
Keyboard shortcuts
↑, ←, Pg Up, k | Go to previous slide |
↓, →, Pg Dn, Space, j | Go to next slide |
Home | Go to first slide |
End | Go to last slide |
b | Toggle blackout mode |
f | Toggle fullscreen mode |
c | Clone slideshow |
p | Toggle presenter mode |
w | Pause/Resume the presentation |
t | Restart the presentation timer |
?, h | Toggle this help |
Esc | Back to slideshow |