NB : Dies ist ein Entwurf von zwei neuen Kapiteln meines Buches ĂŒber API-Design. Der Text enthĂ€lt Verweise auf die vorherigen Kapitel.
Starke KonnektivitÀt und damit verbundene Probleme
In den vorherigen Abschnitten haben wir versucht, theoretische Regeln und Prinzipien anzugeben und diese anhand praktischer Beispiele zu veranschaulichen. Das VerstĂ€ndnis der Prinzipien fĂŒr das Entwerfen einer API, die gegenĂŒber Ănderungen widerstandsfĂ€hig ist, erfordert jedoch mehr Ăbung als alles andere. Das Wissen, wo man "den Strohhalm legt", ist in vielerlei Hinsicht "der Sohn schwieriger Fehler". Sie können nicht alles vorhersehen - aber Sie können das notwendige MaĂ an technischer Intuition entwickeln.
Daher werden wir in diesem Abschnitt wie folgt vorgehen: Nehmen Sie unsere Modell-API aus dem vorherigen Abschnitt und ĂŒberprĂŒfen Sie sie an jedem möglichen Punkt auf StabilitĂ€t. Wir werden eine "Variationsanalyse" unserer Schnittstellen durchfĂŒhren. Insbesondere werden wir uns jeder EntitĂ€t mit der Frage "Was wĂ€re wenn?" Ansprechen. - Was ist, wenn wir den Partnern die Möglichkeit geben mĂŒssen, ihre eigene unabhĂ€ngige Implementierung dieser Logik zu schreiben?
Der erste wichtige Punkt, auf den Sie achten sollten: Wir sprechen speziell ĂŒber die Optionen fĂŒr die Implementierung der Produktlogik . Nicht zu den Optionen fĂŒr die Implementierung der EntitĂ€t : Ănderungen in der API werden hauptsĂ€chlich vorgenommen, um es zu ermöglichen, etwas zu tun, das im ursprĂŒnglichen Design nicht vorgesehen war - etwas NĂŒtzliches. Ihre Kunden werden Schnittstellen nicht einfach so neu implementieren.
Diese Ăberlegung fĂŒhrt bestimmte EinschrĂ€nkungen ein, die es uns ermöglichen, die Schnittstellen nicht blind zu variieren (schlieĂlich gibt es unendlich viele solcher Optionen, und fĂŒr alle ist Sisyphean-Arbeit vorzusehen): Wir mĂŒssen zunĂ€chst verstehen, warum bestimmte Ănderungen sind erforderlich, und von hier aus werden wir bereits verstehen, wie sie eingefĂŒhrt werden sollten.
Der zweite wichtige Punkt ist, dass viele der Lösungen, die diese Variation ermöglichen, bereits in das Design der API integriert sind. Wir haben einige von ihnen (zum Beispiel das Problem der Bestimmung der Bereitschaft) in den vorherigen Kapiteln ausfĂŒhrlicher behandelt, und einige haben kommentarlos angegeben - es ist Zeit zu erklĂ€ren, warum diese Entscheidungen getroffen wurden.
NB: , ; ad hoc , . API ; , , .
, . ?
- , «» ;
- , .
. , ? , «»: , . , :
// POST /v1/recipes { "id", "product_properties": { "name", "description", "default_value" // , // ⊠}, "execution_properties": { // "program_id", // "parameters" } }
, , . , â .
, 11: . :
"product_properties": { // "l10n" â // "localization" "l10n" : [{ "language_code": "en", "country_code": "US", "name", "description" }, /* */ ⊠] ]
â default_volume
? , , , . , , , «300 », «10 ». :
- , ;
- , .
, API - â , API. , â . .
, , API . â name
description
? , . â /v1/search
, : search
?
â , UI . -, name
description
â , ( ) ( ). , API . , UI ? , , : name
â «-» , . -, , UI; -, . , , «», «» «» « » « ».
â UI ( ) , ( , , ). product_properties
, , .
, â . , , , () ( , ). API « », . , : . .
: , . â , (, , .. API) .
, . - , API, â , API . - API :
l10n.volume.format(value, language_code, country_code) // l10n.formatVolume('300ml', 'en', 'UK') â '300 ml' // l10n.formatVolume('300ml', 'en', 'US') â '10 fl oz'
API , , , . , , :
// // PUT /formatters/volume/ru { "template": "{volume} " } // // «» PUT /formatters/volume/ru/US { // // , "value_preparation": { "action": "divide", "divisor": 30 }, "template": "{volume} ." }
NB: , , , , , (, , ), (.. ). .
name
description
. , , (, , API) «». name
description
, UI. UI .
GET /v1/layouts/{layout_id} { "id", // , // // "kind": "recipe_search", // , // // "properties": [{ // , `name` // // â // `seach_title` "field": "search_title", "view": { // , // "min_length": "5em", "max_length": "20em", "overflow": "ellipsis" } }, âŠ], // "required": ["search_title", "search_description"] }
, , . :
PUT /v1/recipes/{id}/properties/l10n/{lang} { "search_title", "search_description" }
:
POST /v1/layouts { "properties" } â { "id", "properties" }
, UI , , .
â , â execution_properties
, , . :
POST /v1/recipes { "id" } â { "id" }
, «» , . , , -, :
POST /v1/recipe-builder { "id", // "product_properties": { "default_volume", "l10n" }, // "execution_properties" // "layouts": [{ "id", "kind", "properties" }], // "formatters": { "volume": [ { "language_code", "template" }, { "language_code", "country_code", "template" } ] }, // , // // ⊠}
, â . , â , , - . , , , , : ( ), , 11.
POST /v1/recipes/custom { // : // , "namespace": "my-coffee-company", // "id_component": "lungo-customato" } â { "id": "my-coffee-company:lungo-customato" }
, : , . , "common", . (, , , API .)
, . , API 9 «» « ». , program-matcher
:
GET /v1/recipes/{id}/run-data/{api_type} â { /* API */ }
:
- API -;
- API ;
- API .
, â , , API -. , «», , «».
program_run_id
, . .
, , . API - API. , , -, API. API , - ?
, API : , () . API â , :
// // - PUT /partners/{id}/coffee-machines { "coffee-machines": [{ "id", ⊠"program_api": { "program_run_endpoint": { /* - */ "type": "rpc", "endpoint": <URL>, "format" }, "program_state_endpoint", "program_stop_endpoint" } }, âŠ] }
NB: API ( program_run_endpoint
, program_state_endpoint
, .)
API , , API . .
- (.. API), : , .
- : .
2 , 1. , , â , , . , , program_modify_endpoint
, ( , ). , , ( , ) .
- , . : , API , . , , , modify
API â , . , , , : , - , « ». , , , , , , , , , , , .
, , program_takeout_endpoint
. :
-
program_takeout_endpoint
,program_modify_endpoint
; -
program_modify_endpoint
,program_takeout_endpoint
.
, . , takeout
. - modify
, . , , â API , .
, API , . , , «» , , : , API -, . â , , â , , .
, . API « », .
? : , . ? - :
- API , ; , : - - , , - ;
- API , API ; , .
, , , : , . , « ».
:
- , ;
- : , .
, , (- ) . SDK :
/* - */ registerProgramRunHandler(apiType, (program) => { // // let execution = initExecution(âŠ); // // program.context.on('takeout_requested', () => { // , // execution.prepareTakeout(() => { // , // execution.context.emit('takeout_ready'); }); }); return execution.context; });
NB: HTTP API , GET /program-run/events
GET /partner/{id}/execution/events
, . , Apache Kafka Amazon SQS.
, , , , :
-
takeout
takeout_requested
/takeout_ready
; - , API ,
context
, ; - , .
. API , . API : . ? , ; - ( !) , ( ).
, . , :
- , API â ; , , ;
- â , , , .
, â , - .
, , (, ) API, , . program
( , , ); execution
( , , API). , execution
- , - API, program
- , .
, . API, , , , . , UI. , SDK.
, , . , â . :
/* - */ registerProgramRunHandler(apiType, (program) => { // // let execution = initExection(âŠ); // // program.context.on('takeout_requested', () => { // , // execution.prepareTakeout(() => { /* , , */ // execution.context.emit('takeout_ready') program.context.set('takeout_ready'); // : // program.setTakeoutReady(); }); }); // // - // return execution.context; }
, . : , . , , , , . .
, , , :
- , , â ;
- , , API . API , .
, API API , «» «-».
NB: . , â Redux. Redux :
execution.prepareTakeout(() => { // // , // // dispatch(takeoutReady()); });
, , â , API, . ( -) , , : , , .
execution.prepareTakeout(() => { // // , // // program.context.dispatch(takeoutReady()); });
// program.context.dispatch ProgramContext.dispatch = (action) => { // program.context // , // , globalContext.dispatch( // // // // this.generateAction(action); ) }
Dies ist ein Entwurf von zwei neuen Kapiteln im nĂ€chsten Abschnitt zur AbwĂ€rtskompatibilitĂ€t meines Buches ĂŒber die API-Entwicklung. Die Arbeit wird an Github erledigt . Die englische Version desselben Kapitels wird auf Medium veröffentlicht . Ich wĂ€re Ihnen dankbar, wenn Sie es auf reddit teilen könnten - ich selbst kann es nicht gemÀà den Richtlinien der Plattform tun.