From c86b40baf6237820bb6af7b203aaeefe55ebc481 Mon Sep 17 00:00:00 2001 From: John Gatward Date: Wed, 4 Mar 2026 12:16:25 +0000 Subject: [PATCH 1/5] Add api design chapter 1 --- .gitea/workflows/deploy.yaml | 44 ++++++++++ .gitignore | 3 + README.md | 3 + ci/mkdocs/Dockerfile | 9 +++ ci/mkdocs/requirements.txt | 3 + .../api_design_patterns/part1/chapter1.md | 80 +++++++++++++++++++ .../index.md | 3 - mkdocs.yml | 15 ++-- 8 files changed, 152 insertions(+), 8 deletions(-) create mode 100644 .gitea/workflows/deploy.yaml create mode 100644 .gitignore create mode 100644 README.md create mode 100644 ci/mkdocs/Dockerfile create mode 100644 ci/mkdocs/requirements.txt create mode 100644 docs/books/api_design_patterns/part1/chapter1.md delete mode 100644 docs/books/structure_and_interpretation_of_computer_programs/index.md diff --git a/.gitea/workflows/deploy.yaml b/.gitea/workflows/deploy.yaml new file mode 100644 index 0000000..7ccfad8 --- /dev/null +++ b/.gitea/workflows/deploy.yaml @@ -0,0 +1,44 @@ +name: Build and Deploy MkDocs + +on: + push: + branches: + - main + +jobs: + deploy: + runs-on: ubuntu-latest + + steps: + - name: Checkout Code + uses: actions/checkout@v4 + with: + fetch-depth: 0 # Important for switching branches + + - name: Build and Extract Site + run: | + docker build -t mkdocs-temp -f ci/mkdocs/Dockerfile . + docker create --name temp-container mkdocs-temp + # Copying content to a folder named 'output_content' to avoid naming collisions + docker cp temp-container:/build/site ./output_content + docker rm temp-container + + - name: Deploy to docs-static Branch + run: | + git config user.name "gitea-actions[bot]" + git config user.email "actions@noreply.gitea.io" + + # Increase buffer to handle larger media files + git config http.postBuffer 524288000 + + mv output_content /tmp/site_final + git checkout --orphan docs-static + git rm -rf . + cp -r /tmp/site_final/. . + + # Optional: Remove source maps to save space + find . -name "*.map" -type f -delete + + git add . + git commit -m "Automated MkDocs build" + git push origin docs-static --force diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..da69810 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +site/ +venv +.venv diff --git a/README.md b/README.md new file mode 100644 index 0000000..acbbe8a --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# Notes + +A repository to store the notes taken. diff --git a/ci/mkdocs/Dockerfile b/ci/mkdocs/Dockerfile new file mode 100644 index 0000000..283beab --- /dev/null +++ b/ci/mkdocs/Dockerfile @@ -0,0 +1,9 @@ +FROM ghcr.io/squidfunk/mkdocs-material:latest + +WORKDIR /build + +COPY . . + +RUN pip install --no-cache-dir mkdocs-minify-plugin + +RUN mkdocs build diff --git a/ci/mkdocs/requirements.txt b/ci/mkdocs/requirements.txt new file mode 100644 index 0000000..fa74f65 --- /dev/null +++ b/ci/mkdocs/requirements.txt @@ -0,0 +1,3 @@ +mkdocs==1.6.1 +mkdocs-material==9.7.3 +pymdown-extensions==10.21 diff --git a/docs/books/api_design_patterns/part1/chapter1.md b/docs/books/api_design_patterns/part1/chapter1.md new file mode 100644 index 0000000..c25e96a --- /dev/null +++ b/docs/books/api_design_patterns/part1/chapter1.md @@ -0,0 +1,80 @@ +# Introduction to APIs + +**API**: Application Programming Interface + +## What are web APIs? + +- An API defines the way in which computer systems interact. +- We can find APIs in the standard libraries +- But a special type of API that is built to be exposed over a network and used remotely, "web APIs". +- Those building the API have so much control where as the users have relatively little. +- Web APIs allow you to expose *functionality* without exposing the *implementation*. + - Sometimes they allow users to take advantage of massive compute. + +## What are resource-oriented APIs? + +- Many web APIs act like servants. + - You ask them to do something, and they go off and do it. +- This is called *remote procedure call* (**RPC**) + +### So why aren't all APIs RPC-orinented? + +One of the main reasons is the idea of *statefulness*. + +> - **Stateless**: When an API call can be made independently from all other API requests, with no additional context. +> - **Statefulness**: A web API that stores context on a user from previous API requests. +> For example a web API that stores a user's favourite cities and provides weather forecasts for just those has no runtime inputs but requires a state to be set by the user. + +Consider the following API method names: + +1. `ScheduleFlight()` +2. `GetFlightDetails()` +3. `ShowAllFlights()` +4. `CancelReservation()` +5. `RescheduleFlight()` +6. `UpgradeTrip()` + +Each one of these RPCs is pretty descriptive, but we have to memorize these methods, each of which is subtly different. + +- e.g. sometimes we talk about flight, other times we talk about a trip or a reservation. +- We also need to memorise which action is used in the method. + - Was it `ShowFlights()`, `ShowAllFlights()`, `ListFlights()` etc + +We need to standardise, by providing a standard set of building blocks - method-resource + +1. `CreateFlightReservation()` +2. `GetFlightReservation()` +3. `ListFlightReservation()` +4. `DeleteFlightReservation()` +5. `UpdateFlightReservation()` + +Resource-oriented APIs will be much easier for users to learn, understand and remember. + +- Standardisation makes it easy to combine what you already know (set of standard actions) which the resource which is easy to learn. + +## What makes an API "good"? + +What is the purpose of building an API in the first place? + +1. We have some functionality that some users want. +2. Those users want to use this functionality programmatically + +### Operational + +- The system as a whole must be operational. + - It must do the thing users actually want. +- **Non-operational** requirements: It must perform how the user expects. + - e.g. latency + +### Expressive + +- The system needs to allow users to express the thing they want to do *clearly* and *simply*. +- The API should be designed such that there is a clear and simple way to do so. +- Avoid workarounds - if there is some functionality a user wants but there is not an easy way to do this, this is called a *workaround*. + - e.g. If you have a translation API, users can create a detect language feature by constantly pinging translate endpoint. + +### Simple + +- We could think of simplicity as the number of endpoints. + - However an API that relies on a single `ExecuteAction()` method just shifts complexity from one place to another. +- APIs should aim to expose the functionality users want in the most straightforward way possible, making the API as simple as possible, but no simpler. diff --git a/docs/books/structure_and_interpretation_of_computer_programs/index.md b/docs/books/structure_and_interpretation_of_computer_programs/index.md deleted file mode 100644 index 3463b16..0000000 --- a/docs/books/structure_and_interpretation_of_computer_programs/index.md +++ /dev/null @@ -1,3 +0,0 @@ -# Structure and Interpretation of Computer Programs - -We are about to study the idea of a *computational process*. Computational processes are abstract beings that inhabit computers. As they evolve, processes manipulate other abstract things called data. The evolution of a process is directed by a pattern of rules called a *program*. People create programs to direct processes. In effect, we conjure the spirits of the computer with our spells. diff --git a/mkdocs.yml b/mkdocs.yml index 37dc9dd..c82ebe3 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -25,6 +25,8 @@ theme: - search.suggest - search.highlight - search.share + - content.action.edit + - content.action.view markdown_extensions: - admonition @@ -60,9 +62,12 @@ nav: - Home: index.md - Books: - Designing Data-Intensive Applications: - - Preface: books/designing_data_intensive_applications/preface/index.md - - Part 1. Foundations of Data Systems: - - Chapter 1. Reliable, Scalable and Maintainable Applications: books/designing_data_intensive_applications/part1/chapter1.md - - Chapter 2. Data Models and Query Languages: books/designing_data_intensive_applications/part1/chapter2.md - - Structure and Interpretation of Computer Programs: books/structure_and_interpretation_of_computer_programs/index.md + - Preface: books/designing_data_intensive_applications/preface/index.md + - Part 1. Foundations of Data Systems: + - Chapter 1. Reliable, Scalable and Maintainable Applications: books/designing_data_intensive_applications/part1/chapter1.md + - Chapter 2. Data Models and Query Languages: books/designing_data_intensive_applications/part1/chapter2.md + - API Design Patterns: + - Part 1. Introduction: + - Chapter 1. Introduction to APIs: books/api_design_patterns/part1/chapter1.md + From b2a1f705a96d1351ebe739ae7f7e0ff291f1eaf4 Mon Sep 17 00:00:00 2001 From: John Gatward Date: Fri, 6 Mar 2026 12:10:18 +0000 Subject: [PATCH 2/5] Added chapter 2 --- .../api_design_patterns/part1/chapter1.md | 20 ++++++++++++++++ .../api_design_patterns/part1/chapter2.md | 24 +++++++++++++++++++ mkdocs.yml | 1 + 3 files changed, 45 insertions(+) create mode 100644 docs/books/api_design_patterns/part1/chapter2.md diff --git a/docs/books/api_design_patterns/part1/chapter1.md b/docs/books/api_design_patterns/part1/chapter1.md index c25e96a..45ea28f 100644 --- a/docs/books/api_design_patterns/part1/chapter1.md +++ b/docs/books/api_design_patterns/part1/chapter1.md @@ -78,3 +78,23 @@ What is the purpose of building an API in the first place? - We could think of simplicity as the number of endpoints. - However an API that relies on a single `ExecuteAction()` method just shifts complexity from one place to another. - APIs should aim to expose the functionality users want in the most straightforward way possible, making the API as simple as possible, but no simpler. +- **Make the common case fast** + - Whenever you add something that might complicate the API for the benefit of an advanced user, it is best to keep this complexity hidden from a basic user. + - This keeps the more frequent scenarios simple and easy whilst enabling advanced features for those who want them. + - e.g. Image a translation API. `GET /translate?lang=en`, allowing the user to add a specific language model as a mandatory field is complex for the average user and will slow down basic scenarios. + +### Predictable + +APIs that rely on repeated patterns applied to both the API surface definition and the behaviour. + +Users very rarely learn an entire API, they learn the parts they need to and make assumptions when they need to make additions. e.g. if a query parameter is called text in one endpoint, it should not be called string or query in another. + +APIs that rely on **repeated**, **predictable** patterns are easier and faster to learn; and therefore better. + +### Summary + +- Interfaces are contracts that define how two systems should interact with one another. +- APIs are a special type of interface +- Web APIs are again a special type of API that is exposed over a network. +- **Resource-oriented** APIs are a way of designing APIs to reduce complexity by relying on a standard set of actions, called *methods*, across a limited set of resources. +- Good APIs are generally: *operational*, *expressive*, *simple* and *predictable*. diff --git a/docs/books/api_design_patterns/part1/chapter2.md b/docs/books/api_design_patterns/part1/chapter2.md new file mode 100644 index 0000000..81a1599 --- /dev/null +++ b/docs/books/api_design_patterns/part1/chapter2.md @@ -0,0 +1,24 @@ +# Introduction to API Design Patterns + +## What are API Design Patterns? + +A **software design *pattern*** is a particular design that can be applied over and over to lots of similar software problems, with only minor adjustments. It is not a pre-built library but more of a *blueprint* for solving similarly structured problems. + +- Most often, design patterns focus on specific components rather than entire systems. + - e.g. If you want to add a logging system, you can use the **singleton design pattern**. + - This pattern is not complete + - However, it's well-defined and well-tested pattern to follow when you need to solve this small compartmentalised problem of always having a single instance of a class. + +## Why are API Design Patterns Important? + +- While having programmatic access to a system is very valuable, it's also much more fragile and brittle. + - Changes to the interface can easily cause failures for those using the interface. +- We refer to this aspect as *flexibility* + - Interfaces where users can easily accommodate changes are *flexible* + - GUIs are flexible - moving a button + - Interfaces where even small changes cause complete failures are *rigid*. + - Backend APIs: changing a query parameter breaks old client code. +- Rigid interfaces make it much more difficult to iterate toward a great design. + - We are often stuck with all design decisions, both good and bad. + +Page 20: 2.3.3 Overview diff --git a/mkdocs.yml b/mkdocs.yml index c82ebe3..1868e6a 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -69,5 +69,6 @@ nav: - API Design Patterns: - Part 1. Introduction: - Chapter 1. Introduction to APIs: books/api_design_patterns/part1/chapter1.md + - Chapter 2. Introduction to API Design Patterns: books/api_design_patterns/part1/chapter2.md From 3a49c14cfa4dae61f17908aac4534f1fb53929d9 Mon Sep 17 00:00:00 2001 From: John Gatward Date: Tue, 10 Mar 2026 12:22:47 +0000 Subject: [PATCH 3/5] Added part2 & chapter3 --- .../api_design_patterns/part1/chapter2.md | 9 ++++- .../api_design_patterns/part2/chapter3.md | 38 +++++++++++++++++++ mkdocs.yml | 3 +- 3 files changed, 48 insertions(+), 2 deletions(-) create mode 100644 docs/books/api_design_patterns/part2/chapter3.md diff --git a/docs/books/api_design_patterns/part1/chapter2.md b/docs/books/api_design_patterns/part1/chapter2.md index 81a1599..3ec182d 100644 --- a/docs/books/api_design_patterns/part1/chapter2.md +++ b/docs/books/api_design_patterns/part1/chapter2.md @@ -21,4 +21,11 @@ A **software design *pattern*** is a particular design that can be applied over - Rigid interfaces make it much more difficult to iterate toward a great design. - We are often stuck with all design decisions, both good and bad. -Page 20: 2.3.3 Overview +**Pagination Pattern**: The pagination pattern is a way of retrieving a long list of items in smaller, more manageable chunks. The pattern relies on extra fields on both the request and response. + +Moving from a non-paginated to paginated response pattern: + +Q. What happens if we don't start with the pattern? + +1. All previously written clients are expected all the data in one list - it has no way of getting subsequent pages. +2. Clients are left to think they have all the data - which can lead to incorrect conclusions. diff --git a/docs/books/api_design_patterns/part2/chapter3.md b/docs/books/api_design_patterns/part2/chapter3.md new file mode 100644 index 0000000..7d243b6 --- /dev/null +++ b/docs/books/api_design_patterns/part2/chapter3.md @@ -0,0 +1,38 @@ +# Naming + +In every software system we build, and every API we design or use - there are names that will live far longer than we ever intend them to. It is **important to choose great names**. + +## Why do names matter? + +When designing and building an API, the names we use will be seen by & interacted with all users of the API. + +## What makes a name "good"? + +### Expressive + +It is critical that a name clearly convey the thing is it naming. + +- e.g. The term topic is used in both messaging and machine learning. +- If your project includes both using the name *topic* will be confusing. +- A more **expressive** name is required: + - `topic_model` + - `topic_message` + +### Simple + +- While an expressive name is important, it can also become burdensome if the name is excessively long without adding additional clarity. +- Names should be expressive but only to the extent that each additional part of a name adds value to justify its presence. +- On the other hand, names shouldn't be oversimplifed + +| Name | Note | +|------|------| +| `UserSpecifiedPreferences` | Expressive, but not simple enough | +| `UserPreferences` | Both simple & expressive | +| `Preferences` | Too simple | + +### Predictable + +- In general, we should use the same name to represent the same thing, and different names to represent different things. +- The basic goal is to allow users of an API to learn one name and continue building on that knowledge to be able to predict what future names would look like. + +Page 36 3.3 diff --git a/mkdocs.yml b/mkdocs.yml index 1868e6a..6b2bc6f 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -70,5 +70,6 @@ nav: - Part 1. Introduction: - Chapter 1. Introduction to APIs: books/api_design_patterns/part1/chapter1.md - Chapter 2. Introduction to API Design Patterns: books/api_design_patterns/part1/chapter2.md - + - Part 2. Design Principles: + - Chapter 3. Naming: books/api_design_patterns/part2/chapter3.md From c1a1f4f11fffe3fff9ce1b9124136c0ef2951caa Mon Sep 17 00:00:00 2001 From: John Gatward Date: Thu, 12 Mar 2026 13:01:29 +0000 Subject: [PATCH 4/5] finished chapter3 --- .../api_design_patterns/part2/chapter3.md | 54 ++++++++++++++++++- .../api_design_patterns/part2/chapter4.md | 3 ++ mkdocs.yml | 1 + 3 files changed, 56 insertions(+), 2 deletions(-) create mode 100644 docs/books/api_design_patterns/part2/chapter4.md diff --git a/docs/books/api_design_patterns/part2/chapter3.md b/docs/books/api_design_patterns/part2/chapter3.md index 7d243b6..e548537 100644 --- a/docs/books/api_design_patterns/part2/chapter3.md +++ b/docs/books/api_design_patterns/part2/chapter3.md @@ -22,7 +22,7 @@ It is critical that a name clearly convey the thing is it naming. - While an expressive name is important, it can also become burdensome if the name is excessively long without adding additional clarity. - Names should be expressive but only to the extent that each additional part of a name adds value to justify its presence. -- On the other hand, names shouldn't be oversimplifed +- On the other hand, names shouldn't be oversimplified | Name | Note | |------|------| @@ -35,4 +35,54 @@ It is critical that a name clearly convey the thing is it naming. - In general, we should use the same name to represent the same thing, and different names to represent different things. - The basic goal is to allow users of an API to learn one name and continue building on that knowledge to be able to predict what future names would look like. -Page 36 3.3 +## Language, Grammar & Syntax + +Language being inherently flexible and ambiguous can be a good thing and a bad thing. + +- On the one hand, ambiguity allows us to name things to be general enough to support future work. + - Naming `image_url` rather than `jpeg_url` presents us from limiting ourselves to a single image format. +- One the other hand, when there are multiple ways to express the same thing, we often tend to use them interchangeably, which ultimately makes our naming choices unpredictable. + +### Language + +Use American English. + +### Grammar + +#### Imperative Actions + +REST standard verbs should use the imperative mood. They are all commands or orders. + +- `isValid()`: Should it return simple boolean field? Should it return a list of errors? +- `GetValidationErrors()`: Clear that it will return list of errors, empty list if is valid. + +#### Prepositions + +- If a Library API wants to list `Book` resources with the `Author`, it's tempting to name `BooksWithAuthor`. +- This falls apart when we add in all our additional resources + - We will end up with many function names to call. +- The preposition `with` is indicative of a more fundamental problem. +- Prepositions act like *code smell*, hinting at something not being quite right. + +#### Pluralisation + +- Most often, we should use the singular. +- However collection names might be pluralised. + - Use American English to pluralise. + +## Context + +- When we use `book` in the library API, we are referring to the resource, however in a flight booking API - we are referring to an action. + +This means we need to keep the context of our API in mind. + +- Context can impart additional value to a name that might otherwise lack a specific meaning. +- It can also lead us astray when we use words with a specific meaning but don't make sense without the context. + - *record* is very generic, until you consider the context of an audio recording API. + +## Data types and units + +A name can become more clear when using a richer data type. + +- `dimensions: String;` - this is ambiguous +- `dimensions: Dimensions;` (where `Dimensions` is an object) diff --git a/docs/books/api_design_patterns/part2/chapter4.md b/docs/books/api_design_patterns/part2/chapter4.md new file mode 100644 index 0000000..ecd84fe --- /dev/null +++ b/docs/books/api_design_patterns/part2/chapter4.md @@ -0,0 +1,3 @@ +# Resource Scope and Hierarchy + +Page 47 diff --git a/mkdocs.yml b/mkdocs.yml index 6b2bc6f..5280b0e 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -72,4 +72,5 @@ nav: - Chapter 2. Introduction to API Design Patterns: books/api_design_patterns/part1/chapter2.md - Part 2. Design Principles: - Chapter 3. Naming: books/api_design_patterns/part2/chapter3.md + - Chapter 4. Resource Scope and Hierarchy: books/api_design_patterns/part2/chapter4.md From 934df269dd28e6dfe827f70101da8e573d615665 Mon Sep 17 00:00:00 2001 From: John Gatward Date: Fri, 13 Mar 2026 12:28:35 +0000 Subject: [PATCH 5/5] added chapter4 --- .../api_design_patterns/media/chapter4_01.png | Bin 0 -> 9767 bytes .../api_design_patterns/media/chapter4_02.png | Bin 0 -> 9988 bytes .../api_design_patterns/media/chapter4_03.png | Bin 0 -> 13774 bytes .../api_design_patterns/part2/chapter4.md | 81 +++++++++++++++++- 4 files changed, 80 insertions(+), 1 deletion(-) create mode 100644 docs/books/api_design_patterns/media/chapter4_01.png create mode 100644 docs/books/api_design_patterns/media/chapter4_02.png create mode 100644 docs/books/api_design_patterns/media/chapter4_03.png diff --git a/docs/books/api_design_patterns/media/chapter4_01.png b/docs/books/api_design_patterns/media/chapter4_01.png new file mode 100644 index 0000000000000000000000000000000000000000..61d640439e0e11ff3238b9165f2f5911ef957d05 GIT binary patch literal 9767 zcmb_?by(cJ(kSi}cZcGI#frPT%i={ADQ?A~xJz+&_u>wP;_ehFUfkWkrSCc4IrrXw z?>=;p#2iSbtkE6moK;~R{!!?oBW32~S2Vb~nH#-TPvw6oy2(Kc= zwthGmSVhlpL*G*AEv!K@-Rt;M!Q7&O`Kt*6%9trAKrn#w2oR7VmJl%D93(gqf)fM; zbX+h5Jot+VPU1OG|89k}$btTM9>VsmqllWAj12gzX5t6}**aO+IX4CBxr2wAw^Ro@ z0~O?XP3&x#jZE!~LCkJ8_HQ5%{BFG9tPRN7h}_M_+SZBJO@Q)m4_ zl>jABL7804&Jje;$;`scLMezuPEOA6Xlll*DlYjiaBxY0(!$x`fZFcV9&$zTMB>f*r;kp!Fx_6#?-UEoH;6X?g8wf7HAVpR zr`xVqg|6pgJI`Mnjj7Zyw$AxPg@*>Wt#!^<+}2=x^%#Cx*jE7G`;mH!sXXUmzSYvG z1(pjN|JU3Q(zL9*pS00W4gIiiP=4JX5v~eyY#?0iZSFtHp*=iUg!`g5e` zkOwB$0u5>-z;>b|H0dudYTkiqS@5Ik{D(87Frp$&y9VNNf2jw;`zcQzc4HX+ErB5g z;1QQ+wk>49b8;42SId4-f7p`}TC%CT^X^7ixoK=tu=BZ0=WC?Ic9yc(3=#h1h5_vG zaB1BYI8FVs;xMq$5$Zm9(Q&h6<&1MRAb9iLxerIHfLbnTTi1OjQLE^-^R~mX?YL16 z8IL&wzKM&O6@4$VyC~f@jdR($Zk*^Rpi=5niT5O0`hPZxKyM9|+A4aV{N_Qm1pK&xvQ>FHtwpoEP3L0ZXUI)1vL>iX4tdZFv(`YH(EMX?IT zsK9sH?zCi)A2r>!_I%R53QE>bYW(eSc$EV$U;#X}s^0mmI8#x3jZSK*QZ^fT_`bK>+cdejn>+&*Ohje%;CpS%N2SpY?V3<41mXh&or)`mziQb=I=KR!2_ZY z`sKdEtc|4KnNj3pdfox}$`ogLeD1%bKy#Pg^nF=c=uAqylA+B^Xk2j|xhe#B(;wIL zzO&ql;!;HOT8Ey|{e6*iH7F&>CUExyEsJiap?%PUEwmwy!G81{s%+ zh(Btr5%`hrvow>HwD0EHGNMn@oLB90UEbTl>Syo)2I?^8Ys$C;o_+$__9Yxwvk2yG zX}C(w?Q9z`5xjw1WmpVJ9u7=#D(sTDT??k{F(el!d~WKT2l#$FWZtIO)?{tmL>N9% zu3i;!jUCslo%+5$S{JPT;cTK0v7FmgX0(v54V~If3yfJ(pvQG_Ark54jXF7T?ecVq z2fhQ7dM*C7wjia2A7+nU16%7N`}K*ojk<-LUcZ0tn-pm(=bG2$Rhd=?LmORRQdQ@} zf%DP#fj`%gRc`_$6_@cPkWjAWL4PytIPq|FKLogoA1L+_B3ACUElWO5N&pbuWO{SU)MS;Ksx*7 zs+e8m>jm{nim`^|Qd9d5(@5zIeQ`z{A3OklUEtDj7NPxc-c)Q6?Y#w7;E zt_VOUw@uv`CsuI|_7JV$d6@Ow%k!!41QKvGRD$si&=Ps*pT~8eVJO~Mv%eO;+(Wly zaTm!xE}bA?^^5FwZ~}Z<loW@h{I+&2f zPB$%(W2d6uB&Xz8JMDSqLhWmIyyVTxtlM^Cc+8sJ@%8-Qu4~>-dSSYO8eUgZQpLS! zLj3g1;yfcDVE^a)7^u-)%0?0MB z&Q-=;%a)#W-2Ub{yNfjEr)uMG7Eyj+X}qgXX4X%W=EKV1}{3=(8Ii{8H_@Ssj0N)NTg~yg)#=s!6&hGF|r5c zCGai8hFpq0nuR-B0*3e2nk-z9WXP69A0WF-8IWK4`J$!g&{uH1syWyO79wkF zB{>-D-f#qjG&kY#m0#9%V}uh*xnL=1IHoNe zUR0Atzk2{p4R1&SMAOlT9V>Ju>`X=7NuBUAs|qiiFTV&dF)>Mv?KB%pdoq6c!__4d z<9%c@1J-n&GkmL+!`G~74@1{w%kaKZ?Sqm;!?_69xDZOD`#19w=*=52q&wbMxG==a z@CplEdAZ|G3RA0A0>AgrwD|PC-3J*_jULwrdeC|*q{eI;c3xXVEl7liOM|kABgvgt zg*=b)-$~Za*bzT$5B9Cc* zKkK6iwFxYS7pp(dm8rX6Ni-@v43`<9`o6KIK4SKYrj>M7BOx=QE4yQhMy+8gJ$v z(eJb1qqLkS-j*L}nxDX@SPCUQ75+F*@nH@fTvz@U21rUVx z^P!sLf~~}F4C!Kc>Rc6{qZhPtip1D~i*O@2v>gB3c0myx6}7`#Q(?`F0*K!@l@FY7 z-x*GH_Z9o}(L&4&4>B`fQS)P+M!6=9^|RCnm&HyhwIcwYDu61)rAjYX6q3d7Fz3K#8gGqQ-A^hQ zcFQf_kzA2KB$_OSz;08!j30Q6NT{62cB^Guid z0xV-^V&A88?H0R+B*X%@$H(8dolpGyulExZ&axAscVel^vlYYuuMOn7>8jT1=6?RB zEHOW+y3TY>nN?#}q)p;Em4yPhv3#5acKO46Q26qrR_1sa9&m*V^4Ebp?aiek@;089 zI$(fs&c=h8iy^eu>;6K!_lH96r*waR1=>DOvtvz0H5}x$>C9-iGvHwg5vg#45gx!G zqjB}i@;W2lCGI76?AEQ zP25=MnD9j>%V%eMAP}3w6~{GSTkRl|(6DQYbs@nmzME02@bve`0?5-B_ub57KCR^l zWFAt^sOv0Pkk|;y8ZX>;+I$ko&BwLZmtX4#voD-gr<%6T9%-eh{ z#B(O6jSPi_EgMYHlsGOvAU4|QFW*haUYyhI;NY@@D!FaArbpZx3IC8t!Hg^tGyahs zOF~E&-@c`WjX#$3Oce6)i{N}vbj$?jd-M{@ZbE^}QTFn38n4@x5VbHF-4^!9GMPER z7?U>MJf~}1N-tK{S>O{&-6GxxU@Y`ce62t$RpLBSS7VT)>w3$fGJ;l_Wkqw}k?WgY ze4T$&{So&n#}D)^|JdDPsUQQHS&ydzrHUl!9b44v5oW8E_8Es^58L?7e$)MA z{A6yCFfI;Kw@|HMSOHV6n4XXASa)&vno0pl)?0mik4JU1RVV>QLvhr<%qK9>2vA{I zvYU|*xI}3`8_mo)(q5cj9BUTh{Yk7vOa|+tKW!Zmi!St$?^u1#MnI30u+DN0S=@I^ zup-;72+RladhjSe^CeY!{7HM-KBv$@M~?)&RwArrU%Ah#YrxoBlW98RBm(<&MAddg zvFdbwhCvoaLV6fG=nmr1Rrx8}{Om@@-aVNNb9Fj)ALkdt z9D$jeBBuviSvL(>Lqd%kc2!7gb&A4|!=2+n2D^MK_bJ+aff^Ncay*JFd|2su0qeiq7A|zRPq$2+wFSAbv24 zx8-QdV%jrmJ5#X&tmPQ#YrGkv@_Tqu1GC-8Ac~Q3D@=A`Mh=agXf7MPL$LOdSr@Gh zp%^K$ny#u;FgX>xC0n#6yAbZbtF$>fT_{)V8%wcBg?)v-Qs99FE1?_->@DlU!MMt; z2W^zT1LEwkYXfsL%1eG;)KGS#_N)mUU?O=8p45;>Ao*-U4uj?;hUC?0hTw-k%R182 z&-fs}86_JcV14XtrQDh%yR9+s5Ntj#v)+s6jlJ0ti5E?s*OeJ1{=c#Ne1rESZx_`e zJ5>#|zGQilvFRX0Civq&g z}8n?n{;XX*z$nO+)Jwx6&T%uhOOW+Y1h)GA6X?zjETA@SN6C>YA-+zCRP6-A8K2R`T1$tuFzM5ZGNJJLN+kh7i~|NtmZ=V*xA^d% zFKUTFjESusMJ=1Y*CY{;6Y-*2d(u5{LE#3bZInyY7DW);wO$xAdPCxQ(%(t@`};3= z<_OkFH|i1#i%}Ce49R|%mTAA4qIDoqOIgw>f}s<3%c>T9oUdA3(6|=D6n`CVqcDD* z^cKVAbmpiVT!~A+WJKP)8xy#V9+=yqRMCSw9NIr_y!#jpz6sF_S>`1alxcg7uAt$g z94MCzOXQZx38&6Wz>|~I8+#5CytF73(sOuXsXH}iI@h7P(3)A-&x10B7J|+rQe{J z(9FfPCD?D0_+FPMCbFOsar)*CB7p&`+_3Z8OIn57>skwmpyBz`!cKUQB88Khvs{Qq zvw@|=4sMH-td9@R7eKbZPm%O=G!CQYwm&0nrn4%b?T^jDJa1FPcxaa%ylPqGwO98d z%bS#`-u6Qig)Yoo*BaJFC6R-S$Fdt8@`BfLa=|wr33H z$HY;!Of#TarCGF0l>U+ySrF+UF}3|Z4feID{1eV+74D4k;1TLL(K3qxM{;{qsFmEp zs>_d7p1Pu=xFt4y@>83FPHx@dp;V#~4lPd^j4=fc@4r)*}VLU2TI)T~_SRas_ z5)tt?nbLi&r}88~b?UG&Lb_+lgqIzs-lzP@X~wH&+Bp>tBKH-DYpe?hx3X&2oG#y7 zC@UOJ!p_gn+p`PaE%eyHEBL(g__ z9c3NZ9@VkIt*A!g1g4te9?!Q0sPw~H8tb0O#G`!Db8s^LO5%MrbssNMtgzG#-7Sqp zrY3-9u&L2ksYBN_=cMGC>cFKTaMYP#)yFD`F$`~emR&#zn5Fsf?>f+lfLDmLX(aPR>jEN;4lQoufk~5gw!=*<3hgtmeo#sY{|uMCY7uzzWE> z+trxqcaO>&$q3iWym4XTK5rOZ`97v|?`J$kGwH6QFqMtXvf zY0ZeMPx*+}di}Fd)wfdoghw!9-ODF^^?3_})zm*M_ZV!BvpAGb)Q*3r>&1*MwvXUo zt)o+wRnmP@8QrTcSnk|uzE*kM*Ndns1A zCF2%F>gXN)IQ#xGvoYhZ^paoB`|y++tZV^&iomPz6b%X8W@cdP)A$F6 z#-PKv3hhH*JoQXQMA+4@^|PllNjz4YfPy<^uC7R3mPt-2o!2T6__}ylFYpXS|tA=mrq_4*~DBZ3G zflJyF52SdGnF+(#!T{y(^-IZpSZ&(C^Ek0tClcvR;jftNSeV=Tm5fP?RIb6aQ)_^k zo|DIUk-1z&f6qi#F!2i4zllzOlfvR0r-IPEdA88T5NL`Jgt75wFZVuog4;2np*&nm|eui=X3@+!lVe{d`z`lQP=;@2?vMI6@qw}Sb7dOtp+5<#i{lpk$YfOV9+ce@ z%;^Kg=_4q&sGudq6E6x=B&?WlUu__AQZ_AHhq)N8^_`zA#ViQWC79NE>UMJ+N0JHxTs}I9GOv5yl&Ajl|PZ#OCeg()HKVydlyp4P5`` zXjU)=inafQTfZC-tQHvbImLud#Gz~|7jIjTE+`f_0vZ(cOX?AS(!EI>myt={Mz{Tj znOG%hKEeYTv)QXvNK=2*OJhXM6_$hO;3LM+qXlx*%)7MLf4l2hRuJ4`BA8Q07zs-J zt0ZGbB({ud`CAZCmxu(Ej)$U?28ArrbBUI!->~xOLyL%INCV;N2m64CtW{?{bV4ND51+vf3MHVX&Tya( zE}#SvbQnvr`k+G=1gS02j4RtjLk2E|(;lxHr4WR%g-7On?>GqKD9-$%W2Rw=Mui4# z4Gz=|^(Wd8SfpsA08!YeOuG0QRd`Ptequc`Tm+`%2uRLZbV(yG1)#GKO-Gq6@Zt?v ze`QG?*q-6M|C*c7I@w1im~0d31Pj$cPQG78XTHox$&pAT`h${6RuTc0Q6;dZr@Vo! z`Q4Nry&3jA+d%<(Uy`g5^<&U2p7zK+k9jx)b@SVG5i2h;`i!Ve#DFZec5&!ZSp zxnJS*`z$r3+d9oOvf6*%-v%oN9L`?njOE=e^}8pMX`ab6@XzY4xzGi~`L%Gvx%{Z} zHqf(1(~%~hG=rh*7B#GFRIACLw8BJcQV)-po@eT$3_Ynn%h!lEp?)+et@Y>&H>F#W zR17TL1dhRsHL&D`yBOHuxuS68uL~k;k^0|O|Ew5xr%vJ4)URMXk$Y5G`rwXR_o=H( z5vA(kyV;>9aI!AQnwSgSf)xr|4a;OGwk;l^KH{{-lut!fdpk2lZVq4BNcdNyvU%nL z+m6D4c9%Qom@GnX1zsw3L}EY%k2RO3w6XX}abL?saxUSrc1+JF*gs3IeoN0!I0BvJ zC^=Aqj!|&A)T+C`dOzVl+zh-j&bpntKj(jIp>NLr#dVf}+~f$0~ibwc^(efdQ=fB*Lss zZci&#h5i0u_C1o<{&XRaNF?Q!ta7oazFES2BBNGO<$P`7dkdAg6&$Zouho)rYZ0S8-7JvCm$1R7kMv(_(eyB%<^mmYAo>c*lC*0` zB6P^>Jvx?pJv3osh|JHIdX$!|ylIiW@+j(>(LY3M!!#L&yu+31ip>xj*bnMs#p0k- z36FFc%~W}6PkNr;=G@!ipWC{r^>!heuf4q8#4J5osE^#q-4eOovHfwxeKjfOq|sh< zyx^+Og)0S|JdChEB10IZf+>@&p)*gmb1xeH^)k2hAV@N0bR`E|-rCyQ2gjWTnem?N zspa6QpWA9h^hGkb{wnB#6yy-$$k7ag9Y%t^BC>RQB6(!HZ_$N$icjxz`n`zW1Bq># zk*9+H8YG11_$jbVbU6r(&dTj#b!TaD`U0pQSxwPV(*hR1YE>Y?1j9krq0U*QpebzS z=Mwn&(OX~>X$w;p&VedxJF}x-n-~1Ly~KonRI}JG`7UU*XUM`8w;q)98_P6j{v647zkun_G?`h-r%}O7Vt9xsk=Y@h2VD)-S$-INFL3nhV_DPk#T&# zEbqyKG6oKE=&>W;&=M?x|ZisDtGpZxy^x#VI9 literal 0 HcmV?d00001 diff --git a/docs/books/api_design_patterns/media/chapter4_02.png b/docs/books/api_design_patterns/media/chapter4_02.png new file mode 100644 index 0000000000000000000000000000000000000000..bfee34967cd12312f59010518e519629264f2025 GIT binary patch literal 9988 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 AQvd(} literal 0 HcmV?d00001 diff --git a/docs/books/api_design_patterns/media/chapter4_03.png b/docs/books/api_design_patterns/media/chapter4_03.png new file mode 100644 index 0000000000000000000000000000000000000000..120932053f23486b98a4697acd6293ea9baabd00 GIT binary patch literal 13774 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 Qr*C;=BoxJKM2&<053^eEIRF3v literal 0 HcmV?d00001 diff --git a/docs/books/api_design_patterns/part2/chapter4.md b/docs/books/api_design_patterns/part2/chapter4.md index ecd84fe..a723b36 100644 --- a/docs/books/api_design_patterns/part2/chapter4.md +++ b/docs/books/api_design_patterns/part2/chapter4.md @@ -1,3 +1,82 @@ # Resource Scope and Hierarchy -Page 47 +## What is a resource layout? + +The arrangement of resources in our API, the fields that define those resources, and how those resources relate to one another through those fields. + +In other words, resource layout is the entity (resource) relationship model for a particular design of an API. + +### Types of Relationships + +#### Reference Relationships + +The simplest way or two resources to relate to one another is by a simple reference. + +
+ +
A message resource contains a reference to a specific user who authored the message.
+
+ +- This reference relationship is sometimes referred to as a *foreign key* relationship. +- As a result, this can also be considered a *many-to-one* relationship. + - A user might write many messages, but a message always has one user as the author. + +#### Self-Reference Relationships + +
+ +
An employee resource points at other employee resources as managers and assistants.
+
+ +#### Hierarchical Relationships + +- Hierarchical relationships are sort of like one resource having a pointer to another + - But that pointer aims upward and implies more than just one resource pointing at another. +- Hierarchies also tend to reflect *containment* or *ownership* between resources. + +
+ +
ChatRoom resources act as the owner of Message resources through a hierarchical relationship.
+
+ +In this case, there is an implied hierarchy of `ChatRooms` *containing* or *owning* `Messages`. + +## Choosing the Right Relationship + +### Do you need a relationship at all? + +When building an API, after we've chosen the list of things or resources that matter to us, the next step is to decide how these resources relate to one another. + +- Consider a self-reference relationship between `Users`. A single change to one resource can affect millions of other related resources. +- e.g. if someone famous deletes their Instagram account, millions of records might be to be removed/updated. + +Reference relationships should be **purposeful** and **fundamental** to the desired behaviour. Any reference relationship should be something important for the API to accomplish its primary goal. + +### References or in-line data + +- Where data is in-lined, we only need a single API call to retrieve all the relevant information. +- But what if we aren't interested in that information very often? + - Then our response is bloated. + +Optimise for the common case - without compromising the feasibility of the advanced case. + +### Hierarchy + +The biggest differences with this type of relationship are the **cascading** effect of actions and the inheritance of behaviours and properties from parent to child. + +- Deleting a parent resource typically implies deleting a child resource. +- Access to a parent generically implies the same level of access to the children resources. + +## Anti-patterns + +### Resources for Everything + +It can often be tempting to create resources for even the tiniest concept you might want to model. + +**Rule of thumb**: If you don't need to interact with one of your resources independent of a resource it's associated with, then it can probably be a data type. + +### Deep Hierarchies + +Overly deep hierarchies can be confusing and difficult to manage. + +Page 63 4.3.3 in-line everything