From 74b2e1c065f7bf96575b1f8eaaf315e26d38242f Mon Sep 17 00:00:00 2001 From: Phil Sturgeon <67381+philsturgeon@users.noreply.github.com> Date: Thu, 21 Nov 2024 12:54:56 +0000 Subject: [PATCH 1/3] first draft at api design article --- .../api-basics/dev-guide-api-design-first.md | 184 +++++++++--------- 1 file changed, 87 insertions(+), 97 deletions(-) diff --git a/src/_guides/api-basics/dev-guide-api-design-first.md b/src/_guides/api-basics/dev-guide-api-design-first.md index 8a98146b..f4bcbd74 100644 --- a/src/_guides/api-basics/dev-guide-api-design-first.md +++ b/src/_guides/api-basics/dev-guide-api-design-first.md @@ -1,138 +1,128 @@ --- -title: A Developer's Guide to API-First Design -authors: Alex Doukas +title: A Developer's Guide to API Design-First +authors: phil image: images/guides/api-first-design-guide.png canonical_url: https://bump.sh/blog/dev-guide-api-design-first -excerpt: Learn about the principles of API-first design and how it can benefit your organization. -date: 2024-03-25 +excerpt: Learn about the principles of API design-first and how it can benefit your organization. +date: 2024-11-15 --- -API-first design is a software development approach built around the idea that the application programming interfaces (APIs) should be the primary focus of the development process, with other system components, such as the user interface (UI) being developed later. +API Design-First, also called schema-first or contract-first, is all about designing the interface of an API before writing any code. It's about planning the [API contract](https://bump.sh/blog/api-contracts-extended-introduction) first, and defining what the API does and how it works so everyone's on the same page before implementation starts. This approach has been around for a while, and over time, it's evolved to meet the needs of different technologies. These days, OpenAPI has become the defacto standard for designing REST APIs, and it can make life easier for everyone the whole way through the lifecycle of an API. -API-first design is becoming increasingly important as more and more organizations are turning to microservices and other architectural patterns to improve their ability to scale, innovate, and adapt to changing business needs. This approach enables the development of flexible and modular systems that can be easily integrated with diverse systems and services. -In this article, you'll learn about the principles of API-first design and how it can benefit your organization. You'll understand how API-first design works and learn about the different stages of the API design process. By the end of this article, you'll have a comprehensive understanding of the benefits of API-first design, and how [Bump.sh](https://bump.sh/) can serve as the single source of truth for all your APIs. +## A Brief History -## Why Is API-first Design Important? +To understand why design-first is such a big deal, it helps to know where it came from. -As mentioned, API-first design is a specific methodology for building software systems, where the API is designed and developed before any other system components. APIs are emphasized as a core part of the software development process rather than as an afterthought. In short, the API is considered the backbone of the software, and the rest of the system is built around it. +- **The early days: WSDL and SOAP**: In the late 90s and early 2000s, SOAP web services were popular, and people used the XML-based WSDL (Web Services Description Language) to describe them. WSDL files outlined all the operations and payloads in a verbose XML format. It was powerful, but many felt it was overly complex. Developers creating, maintaining, and using the APIs felt the frustration of working with them. -

Code First v.s. API First - A change of software development philosophy.

The diagram below shows the differences between code-first development and API-first development. Why do we want to consider API first design?

1 of 10 pic.twitter.com/HKgSGYLOf9

— Alex Xu (@alexxubyte) November 16, 2022
+- **REST APIs take over**: REST, introduced in the early 2000s, focused on simplicity and scalability. Unlike SOAP, REST didn't have a standard way of describing APIs. Many developers relied on manual documentation, example cURL commands, or tools like Postman collections. It worked, but it was messy, inconsistent, and could easily diverge from the implementation of the API. - +- **The OpenAPI era**: Around 2011, Swagger (later renamed OpenAPI) arrived to help describe REST APIs. It introduced a standard machine-readable format for defining operations, parameters, payloads, and validation rules, all using JSON or YAML. There were a few other similar projects (mainly RAML, API Blueprint) but they all fell out of use, and OpenAPI became the champion. -API-first design is commonly applied in API-centric products. For example, companies like Stripe or Twilio offer their APIs as a core offering to customers, so they have to design them to be intuitive and user-friendly. +## What Is API Design-First? -Companies using or moving to a microservice architecture will also often adopt an API-first design approach. Because APIs are so important in microservices, developing standards and a well-thought-out workflow through API-first design is very important. +API Design-First means you define the API's contract before writing any application code. This contract includes things like: -When done well, API-first design offers a number of benefits: +- The endpoints (URLs) and their HTTP methods (GET, POST, etc.) +- The structure and validation rules of resources and collections. +- Authentication rules (like API keys, OAuth 2.x, OpenID). +- Errors that could be expected, and an example of their structure. -### Faster Development Times +At first this all seems like extra work, but much like writing tests for an application, it will eventually speed up the delivery of APIs, saving everyone time and money, and reduce costly rewrites onces not-quite-right APIs make it to beta, or even worse get into production. -By designing the API first, development teams can more easily work in parallel on different parts of an application. Having a well-documented API means that teams can stub out specific endpoints to test and build their own systems without having to have a running instance of every API on their machine. +## Why Design-First? -Similarly, this improves coordination between frontend and backend teams. Frontend developers can build based on the assumption that the backend will adhere to the established documentation, allowing backend developers to work in parallel with them. +Here's why design-first is worth the effort: -Finally, API-first design makes it easier to reuse endpoints and logic throughout the system. For example, if you’re building an e-commerce application, several parts of the application may need to estimate shipping costs (e.g., pricing page, checkout workflow, returns workflow, invoice generation, etc.). If there’s a single, documented endpoint available, you can ensure that each time it is called, the results will be the same. +1. **Clear communication**: Everyone – from frontend developers to testers to external users – knows what the API does. +2. **Parallel work**: Frontend and backend teams can work at the same time. Mock APIs can be set up using the design, so development doesn't have to wait. +3. **Consistency**: It's easier to enforce standards when the contract is agreed upon first. +4. **Automation**: You can auto-generate documentation, code snippets, and even parts of the implementation using tools. +5. **Version control**: It's easier to track and manage changes to the API over time. -### Improved Developer Experience +## OpenAPI and How It Helps -It’s often easy to tell when a system wasn’t built with the API in mind because it uses clunky or non-standard endpoints. For example, I recently ran across an API that used the following endpoint to edit a user object: +Describing an API is the most important part of the API design-first workflow after planning is done, and for anyone building a REST/RESTish API, the API description format of choice is OpenAPI. -``` -POST http://api.example.com/v1/user/edit -``` - -While this approach technically works, it’s not common. Typically, in a REST API, modification of an object [would use a `PUT` or `PATCH` request and include the object’s ID in the URL](https://restfulapi.net/rest-put-vs-post/). So, consumers of this API must now very carefully read through all the documentation to be sure they use your API properly. - -Whether API consumers are internal or external, systems designed with the API in mind first will almost always provide a better experience to developers. They’re more likely to use established standards which make them much easier and less frustrating to use. - -### Better Collaboration and Communication - -Ultimately, all the advantages of API-first design come down to making communication and collaboration better. - -When your API is clearly defined and agreed upon up-front, multiple teams can work in parallel, engineers can move from working with one API to another seamlessly, and errors in the implementation or consumption of APIs are more clear. - -### When is API-First the Wrong Approach? - -Just because there are advantages to API-first design doesn’t mean it’s a panacea. For example, if you’re building a traditional server-rendered application without plans to offer an API, adding extra layers is a waste of time. API-first design can also hamper nascent projects that aren’t sure exactly how the data model will look when they’re finished. - -[Overengineering is a common problem in software development](https://solidstudio.io/blog/origin-of-overengineering), and API-first design approaches are no different. - -## The API-First Design and Development Process - -Now that you've seen some of the advantages an API-first process provides, let's get into the practical aspects—what does API-first design look like? - -As the name implies, API-first design dictates that you plan your API as part of the application development process, but like all software, your API needs to be open to change as the system around it changes. - -Typically, a new API will undergo the following stages: - -### Define +OpenAPI documents are written in JSON or YAML, making them machine-readable, and somewhat human-readable too. They contain all the information needed to describe the interface of an API: requests, responses, reusable components, etc. -This is the initial stage of the API lifecycle, where you’ll define and establish the API's overall goals, requirements, and constraints. This stage is critical for setting the scope of the project and ensuring that the final API will meet the needs of its intended users and stakeholders. - -At this point, you should consider the technical and service-level requirements, the data format users will prefer (JSON, XML, etc.), the [data structure](https://medium.com/back-to-the-napkin/the-next-step-to-build-better-apis-consistent-data-structure-38667444f37e), and the downstream systems that rely on your API. You should also consider the audience for this API. Will it be publicly available? For private or internal use only? Or limited to verified partners? - -Finally, you should define any key roles or processes your team will use while building and maintaining the API. You’ll need to decide on the tools you’re going to use to design and document the API as well as a plan for change management. - -### Design - -Next, you will outline the API's design and structure. Based on the performance, scalability, security, and other requirements outlined in the _Define_ stage, you will need to make decisions like whether to use [REST, GraphQL, or gRPC](https://blog.logrocket.com/graphql-vs-grpc-vs-rest-choosing-right-api/), how to authenticate and authorize consumers, and how to report and track errors. - -During this stage, you can create API contracts that provide clear guidelines for the API's behavior. Assuming an HTTP API, developers will often use a standard specification like [OpenAPI](_guides/openapi/specification/v3.1/introduction/what-is-openapi.md) or [AsyncAPI](https://bump.sh/blog/what-is-asyncapi) to define the [API’s operations (verb and URL)](https://www.ibm.com/docs/en/amoc/3.0.1?topic=operations-defining-rest-api) and response format. Having contracts like this allows developers to properly implement the API, and it lets consumers mock the API so they can build downstream applications. - -### Develop and Document - -In the next stage, you will implement the API, and create the necessary documentation. - -Traditionally, documentation has been a manual process, but API tooling has come a long way, and now you can use tools like [Bump.sh](https://bump.sh/) to automatically generate your API documentation from your contract defined during the design phase. This allows your developers to focus on implementing the API and building internal business logic without having to worry if they’re keeping their documentation up to date. - -As in building any web application, you’ll need to make decisions about the internal architecture of the API (framework, language, database, etc.), the ancillary services needed (message queues, notifications, etc.), and deployment options. If you’re in an established organization, many of these decisions might be mandated externally, but in greenfield projects, there’s often a lot of leeway. - -### Test - -Before deploying an API, it's important to thoroughly test it to ensure that it behaves as expected, meets the outlined spec, and will continue to behave as expected as the API changes. Typically, this includes unit testing, integration testing, and load testing. While [automated testing should comprise the bulk of your API tests](https://www.infoworld.com/article/3286529/test-automation-comes-of-age.html) you’ll likely want to do some manual QA as well to catch any unexpected behaviors before you launch. - -After launch, testing is equally important, so focus on building repeatable testing practices: run them as part of your CI pipeline, keep an eye on code coverage metrics, and don’t let test debt pile up. As you might imagine, these tests will be invaluable once your API starts changing and growing. - -### Secure +```yaml +openapi: 3.0.0 +info: + title: Example API + version: 1.0.0 +paths: + /users: + get: + summary: Get a list of users + responses: + '200': + description: A list of users + content: + application/json: + schema: + type: array + items: + type: object + properties: + id: + type: integer + name: + type: string +``` -While security should have been considered at the design stage, this point is important enough to check again after implementation. You want to prevent any unauthorized use or abuse of your API to ensure that sensitive data is protected. Encryption, access controls, user authentication, and other security measures should all be tested and verified before deployment. All the security checks that can be repeated should also be included in your CI processes so they are conducted continuously. +This snippet describes an API endpoint `/users` that responds with a list of users when a client sends a GET request. It then describes the responses a client could expect to see, with the status codes (e.g.: 200), content types (e.g.: `application/json`), then gets stuck into the `schema` which will outline the shape of the JSON. -Most high-stakes API projects will have penetration tests conducted by internal or external auditors. If you’re new to API security, familiarize yourself with [the OWASP API Security Top 10](https://owasp.org/www-project-api-security/) and make sure you’re covered. +If you're just getting started with OpenAPI, we're here to help you on your journey. We've put together a guide to help you [learn OpenAPI from scratch](https://docs.bump.sh/guides/openapi/specification/v3.1/understanding-structure/basic-structure/), starting from the basic structure and going through every part of the functionality. +## Comparing Design-first and Code-first -### Deploy +For years the API Code-first approach was the way to build an API. You'd sketch out the API you want to build on a whiteboard, then before that was even done somebody would be generating controllers and views in their favourite programming language and firing JSON around. The goal was always to get coding as fast as possible, so that clients could start integrating with it as soon as a prototype was ready. -After testing and securing the API, you can deploy it for use by its intended audience. Obviously, the specifics of this step vary greatly depending on your tech and infrastructure stack, but most companies use multiple environments to ensure their API can be deployed and that changes don’t cause unintended consequences when they’re released. +The rush to get coding often meant the first version clients get to see is not really anything like what they want, so a lot of time gets lost and wasted recoding controllers and doing database migrations. At some point everyone runs out of time and they have to go to production with whatever they have, even if it's a mess for clients to work with, and everyone just agrees to fix it all later in v2.0... -### Observe +When OpenAPI is utilized in this approach, it is usually as annotations or code comments, popped into the application somewhere near the code it's describing, with the hope being that a developer will remember to update both at the same time. These annotations can then be exported to an `openapi.yaml` document which can be displayed as documentation or generate SDKs. -Observability has come a long way in the past few years, and modern tools allow you to easily track your API's usage, performance, access logs, and errors. Instrumentation should let you catch issues and help you understand how consumers are using the API. +```java +class UserController { + @OpenApi( + path = "/users", + method = HttpMethod.POST, + // ... + ) + public static void createUser(Context ctx) { + // ... + } +} +``` -### Evolve +Sadly this approach relies entirely on conflating proximity with accuracy. The annotations and code just a few lines below would often tell two completely different stories. -It is worth noting that this API development lifecycle isn’t a one-time process. Like most software projects, you’ll come back to implement changes frequently, so you’ll need to have a plan for implementing, testing, and announcing those changes. +Anyone who has been building APIs for more than a few years has probably done this and felt the pain, which is why so many API teams are starting to leverage the API design-first workflow. -Tools like [Bump.sh](https://bump.sh/api-change-management) can help with this as it can track structural changes to your API to automatically update a [changelog](https://keepachangelog.com/en/1.0.0/) and trigger a [webhook to notify other services](/help/api-change-management/webhooks/). +Here's a quick look at the two workflows for comparison. -Finally, this lifecycle isn’t necessarily linear: you may need to move backward before you can move forwards. For example, during the development stage, teams may find that certain requirements must be re-evaluated or redesigned. Or, during the testing stage, they may discover issues that require changes to the API's design or implementation. In such cases, teams may need to go back to a previous stage of the API lifecycle to address these issues before moving forward. +![](/images/guides/design-first/code-first-design-first.png) -## Developer API Tools +Whilst there are a few more steps, the time invested on agreeing a contract early on brings massive time benefits through the rest of the API lifecycle. -I’ve hinted at tooling a couple of times in this piece, but because it’s such an important part of building a great API, I’ll dig deeper here. There are a few categories of tools that are important when designing and building APIs, including: +Combining the API-Design-first workflow with OpenAPI specifically allows for amazing benefits: -- [**Documentation tools**](https://bump.sh/blog/the-best-api-documentation-tools-for-dev-teams) range from presentation-only tools to automatic doc generation tools. In any case, you’ll definitely need some way to document your API and manage changes. -- **Mocking tools** allow you to stub all or part of your API so consumers can work without a deployed version. -- **Testing tools** come in many different shapes and sizes but most will allow you to automatically run and call endpoints with various parameters to ensure the results match your expectations. -- An **API browser** can be helpful for browsing and troubleshooting endpoints or testing specific requests. +1. **Readable by humans and machines**: The YAML/JSON format means it's clear for developers and allows for API design reviews / governance with teams that don't have to read multiple programming languages. +2. **Interactive docs**: API Documentation generators like Bump.sh turn OpenAPI documents into interactive documentation, showing off parameters and examples, so clients can quickly and easily work with the API. +3. **Mock servers**: Tools like Microcks and Wiretap can use the OpenAPI document to simulate the API, allowing parallel development of API and client applications, and allowing feedback to come in early and often. +4. **Server-side Validation**: Instead of rewriting all of your validation logic in docs and code, you can use the OPenAPI document to power your application, making absolute certain the the documentation matches the implementation and reducing time spent writing code. +5. **Contract Testing**: Use automated tools to probe your API implementation based off the OpenAPI document, and add assertions to existing test suites saying "does this response match what it says in OpenAPI", further ensuring the two are in agreement and saving time writing complicated contract testing by hand. +6. **Code generation**: Many tools generate client libraries or server stubs directly from an OpenAPI document, saving loads of time. +7. **API Style Guides**: Style guides are hard to enforce against code, developers need to check them manually, but with OpenAPI you can enforce standards on the API from the very first endpoint that is described. -Finding the right mix of tools often comes down to personal preference, cost, and ease of use or implementation. Ultimately, what works for one company might not work for another, so it’s important to evaluate all the options in your unique context. +Anyone who has written API documentation by hand knows that it takes forever and is usually bad and outdated very quickly, so the fact that you have entirely accurate documentation from the start is a huge benefit for most teams. -## Conclusion +These other benefits may not have ever been considered, they were just things that you spent infinite time doing by hand and had never even considered automating, but when you combine them altogether in a single workflow your team becomes unstoppable. -API-first design is a powerful way of building software that prioritizes APIs and their consumers. Development teams can create better products and more efficient workflows by designing APIs first and then building the rest of the application around them. +Speed and accuracy both go through the roof, reducing time, cost and client frustration with your API. -Additionally, by thinking about the API from the beginning of the development process, teams can better anticipate the needs of third-party developers and create a more user-friendly experience for them. Overall, API-first design is a key strategy for creating high-quality, effective APIs that are well-suited to the needs of modern software development. +## Wrapping Up -Getting your API-first design efforts off the ground can be made easier with Bump.sh. Bump.sh is the simplest way to automatically create API documentation portals for internal, partners, and public APIs. Feel free to look at our [solution](https://bump.sh/users/sign_up), and please reach out to us if you have any feedback, comments, or suggestions you'd like to share. We're always listening. +API Design-First is all about getting the API's design nailed down before jumping into coding. It helps teams work faster, stay consistent, and avoid costly mistakes later on. OpenAPI has become the standard for REST APIs, making it easy to design, document, and manage APIs. While other technologies like GraphQL offer alternatives, the simplicity and reliability of REST, combined with OpenAPI's ecosystem, make it a solid choice for most teams. From d8273510df92e394d1c5eb42a979cea645519281 Mon Sep 17 00:00:00 2001 From: Phil Sturgeon <67381+philsturgeon@users.noreply.github.com> Date: Thu, 28 Nov 2024 17:54:41 +0000 Subject: [PATCH 2/3] missing images --- .../design-first/code-first-design-first.png | Bin 0 -> 56967 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 src/images/guides/design-first/code-first-design-first.png diff --git a/src/images/guides/design-first/code-first-design-first.png b/src/images/guides/design-first/code-first-design-first.png new file mode 100644 index 0000000000000000000000000000000000000000..3fe6af58225d52516e425f53e17339e7a8facf87 GIT binary patch literal 56967 zcmd?Rg;!kJ(g%vW2Mq)#xChq&!QI^@K(Gday9NlZ!GpWILvZ)t5FCQLztfqycjkU; zz4s5iUJd8;rfTmxTS|Ua%@;*^2~?!lNDvSZs8W(*$`BAx+Yk_ta|m!i%LM<8A#j0o zRF)8dC?6x*2R=lbX-b*P$wANo_XrShkZ=&tU=j!@;1|~4_mIH-YY5ms?GO;^kc9ue z*N3F}hd#s-0_JZTbKnYoNdi9r_up6OEXaR)%!2w4HPm(%^ndOl=fG^JVn><41<_to z%Mk(s`4#vF65?ALKJYlmma3XgnsTzdCU!PVMy7VgW=yU&_Fyguepg=L*2c`qh}6~Q zldU7Ks{r{Q3SQtI+{{c)`iI2HT7XV5h zVC4t5@+zA-+I?~ccduq^=_JU;|A+YhHvco)Ut9_xOEW-TFq%h4AKD&1cWezl-PS!SIFP#u&$~Sc)<$%7|V=}Ei#i(j32bMrD>H5 zm0eu&%CQUS)t~FJX=)`Mkg#1`{99mu-R-8Da;A>HU7&19O*lE#EstugN#VH}NlAe? zV<=+qV|&M~8%#+h8I;RSTN;bErzK@-CE0m`NC_J})Z1yu6N^Fdic+eNmK^>m0|{~q z9Sf|=hd>sk5al>X3$`Q4yDWO-3 z5iA=Svc5LK)JbU5;!r%KotzXDrCAY4%Pt?9NQ%HI*J>|Zknag|1wN|mIL^Gl7t*jbYOm(n=*_)*2YT|cNz0(e~pK7(i+rcX%&H5 zm4sM{Eg_B@wu=5Nkl>B>eAy>*x%{qX^mMt}Xh@P&17OYVPxN6=g&AVuC}j6Va=VAx zAV73whkO(;spK?QI^XeRIU<$>#)8L1iW7r!qX1+T=G0EApZ zG`yyiwLUnyGrSiF2j+F04n02@Chdc-jri+9fIjY59#+0UZZrhqEiUAvo=H07+7OOo z+!`RlmJ1?_H$lD;sW0T6R|l6tqpTx>sdU11;}^M9JV ziYc*RQm(5)ePW-o-$_+2kHr`W@|!~Pm!Mpyhf#hhzo@Z2!-*e}a0gRdtP>#K!hrkk z9SCOs3JdP_pEs!if+FoW-tUO`e>M8TOaZM5CS4R*q>%r-2k@X&hc00GD5(C`Nb2_v zXr0zP4gH@E&VwKl&ON)vB!S)YuhG5&t?zL8$^WMVPcn=&=Bj(mTv&f(nXkrQDU}#a z@SPnBbi;&pO?XT{|HJPKqbubr?MA%EN$*(4ziJ$>%BXDsRjMwc?e5y_*>tSM7I?CM!~UBpN2UvX=1DE81E~Ggqynl-38SA zkD8VQg&A$l=Mc1bN+0sJ*=b9z^~miKZ+~z%8A%g-i4?NC(bJ~{PK^+h=wSzCPin+K z^x3pV7zvW?!j?_H)D2W-Clmj!R831?GgD z3f;hdat;sD^z}x*S+nHiL@emn5ZS_K_n;%2eXS!jx9p>+`}-L^gF)&Nl8OFwiicsH zH_DoJf_1vYkGphUZBBmDYCQ3gYONGkq3e(~=n`HUc%RD~;PMu=R;2j&y{O8*+o~3~ZHr%2 zYv@F#ChmXYu~lx)*>9UrW0k&BL5zlY<1DFI7zmFu zBExpegc$9ci9w^4l~zkLFSq*pw50XtwMD^Bvuu}SSv1AO)|P2OaJru1^})dJ)xp81 z*o|#9oo3+%s)jkYspFD@a-u3-J6+zLypSg*W4 zdw8V%Of;1k6*`$#&IkuFYi0Q_uU&eDfB(Gq%T~+&lnW7^iH2*YRe^qz3MoF};ae-c z9TQ0!85~WQ)ZiC_avcMNXkn>D%0rpYQE$A)T6N1likdA{6ezf4u8)9$E zPNOh33hueY_1?5O17IqpgRBR`DA=8Onarl*J~9(~?4u~pz5F)a9Q1J>r$V8c4dcYX z*IO5{vRU^#D>B+IF}#dYNY!Sp5krk%fu zzc=7O(4@!^UH2yw`qT7#rXT5ZXCg+P9gfmwOZnZ-iAYtNngnIJTq=p{=a_2SxuAXD zl7V??T0z`4A&yZ|vUb9eRkZpe6;emmfN^xBnlYg)N=N?2|C zx;AH&S}yvEYgsMpclS|2c6ELZRCT%7nQlxama^X6L4QeKnWn4d6P;_O>Pqs$S)dw> z06{b=byA^zxa7WKRYex0j*Dk@yX~{+a#TG&ZDqc2eWpH@vrK(#Sdi78V{VmCy2Q5Y zC8U?_gTZG@KQo4Edz+`lrQwjlY?&6Aj%@jur^~vEIiZTFM#+{z6h&L!XgjWUQ-}RY zyjv3B=xAWxdi6`1UAoE_G^zT9o$D9uE4PTTdkKooUWn7$>9i-Is0)DV!nx*e*1xkl zEWsON|DMQ#0@-c4u$4Jx2VNJ&e2?#cs~^(@|F+m3$|-%NsZ}2UVq*ibe6tTjKC6HG* zyczdvizFd&WHHuznoerCdc{n5g*q1$(~R{R|E-0IJPi~3R>{?P5%DfzZED^ZLYuK9 z%;ALa0qE+7Wp_s{<5$eXiPOWd0wskdlYA`~zqOClt=uHvyrW&A{Xol{U@jLD8+qU1 zlir^zF`KPj6r~V08%!4uxhNuO?&fOT#c|($<&#do!T^0JP{vF}*()PySg0pIcapsM zdul4@fTgKQJT_$>% zbIgY=2FMAi`iv-~NT_~Lldwxfz9$tHJYbV?4*FcDE3P@O{^mPJ`_dBXLxT;Dx2RV#_(sJuGsW+xpH?rfSl#KON_UDhgOuhD%o$hd! z8dVJ+Xt^v$zu@$7%JEYJ){g-SU*qC#vES6`rkB^Ka!*?=CL69tRgO4@u%{Drk2T6kVj9FT(rMCerk+6mCoV)Vyne< zW7Pevd)`*gn>$+*ZTua*-^j%lrE6UrDiYsU*lv(Y(1U?JwPPhaCv)W8SAzSV@JnlV zC}dER{Fiui9DZL<3SE4e(ge`5Xp73A^ ztZfI)Hl-&k z;C5AvsFiQla4^gHDf?8E)=uwPd$A`nrTx<`KJs2kbhlhejDCej?eFK+Rh$!n0SAJvXuudpQhRW`z{NziOC4&{4(%pS2R zyK{{cfudY*gHbdPjq%4uVx&_Ge>Y(p&E0|FAwGYDKN8i|^Ywia^depqi z65m`#R%@x8rE6J|Ok1r|gGUPKmGC|vSSyCUs4%hEm%Q`m#k^u!RMgROWU#3e?4vQl zf}_~e3tAV={jgxG-PC{gnxm6soFM4Y^S9-l;da|M4P)gnkNq~e)fjTC=%TV@eqc?k zn}R^@B|RtFWD1JxRoUq;ZWpO&jvz`#_%XXUM^PvgRpY?wYNgx!bwb>Ad z#d(dLpPAZbm-g7Y&FB@;NNmR=O|sdMxZSK18Aa=YH1cRH(1Hk;^8Ml9&{~6L?HVf4 z!hyy3PI1A_ylngRvhX^mA5%@~*8EZC(4I5xG2^C3fvUYL@iCco6mv9fOZ&w0T%~7b zqo-oawv)W`=+6RkB4MIym;~}>CbH9Bc;tbOg8*1{M@^}3be|{B@GhNIoeGmD6OaeP z3cN|Lgc=78gYldkM2>CayK(#H1mG2l%Oy9Z1K$}aCOGZ;n z6o!;o9qClch1BaBO%T!NuH}|DyW1d$O-`F~Jw$$t0$dwv1bh={wt#z7aRP+J7?5(?%#r46mJC%0Il6w><jmUj2?2uowr7DpG@t0<75~hw~f`&Po zr0|>}Nf0Mz**sof%*esUk%jvHXDD@Vnl&>Dy2Gp}2@>o^H^5^QSZROVfVCXxS0I%V zUr(@WQ0}Aty!rr*cEt^GiHnU8skj|~edg;i=hpd~UYriQ*cQzh{r)i^?y{-J<_olC zQQmUqvzl4ZD$E|-1bivAv~ZyP8!NSA?KfP4KPJYMTSJ8B7L#wbddg@y3|2#H%jJUb zzd!!!yIOs#V#`nW%Kb!9&+kKCrE(wXBqAO|ITPa0n(bQC=sj=g+rC|VJirYtsMzet znS5aE=PuN2%-<$rqCb7#k-gKFXk94TqxJ#H$6?yc^4h2fr*7K_9zFl~e(HQ{o=_h{ zmIC%Y?9VD?1G5bu$%hK(irAewV>hz!fGcWT`e7x1Z>Wn_LO&|gr!PVG*zH?5$OX5b z?fBZ1ndpNfPv0RiK`l7i=6oQV_cK2yd1Q8^i_C@XfRv3xeBW>o?LNM5LUVwj*?U}d zuc!(7SlmAL0tAenArO6t1UZu78M3u$^Hlt)H*qb$Q1qQ_8URQD!70-BRIxuGPRxRqUW};sR1H;Fkal(aWrd zLWXXJ@~!i%hQVg^(m@9)edJgyJtE!}PjmPB349j>x@VDb7C8*GR#vSEDdG>$(H!In z?YnyQR^%Yu>G5wbV>CkC6ztcYc2%BuinvLJ91xdT2gRbE$-_(P>mDDULhL+*YA$Mq zUX~EBm+^4dvfyF5$fwmuInYQzs>Kalo*&-YybSOc-_)<<&T)021bi#iGd7fBV|s6X zTI6Oide(G5ftfLP5n{oSgEG{AOM<43L&PA1Pq|gd9g8~x;~Q3Makb=Jc_mXf`Op!s z1}A`2csa`PhS0Pu`$r*8+opVmZrgE0fBY_V zFv5{Ls_oYxPah?a1OOYl@u+Zix*A8HZLT^$-d9vSDcnUVOj0zkPV^v%$CzYM$MfI1 zzrXXy+K0Dt2vL~f-wgTJInF;fB-ffU3g^pZPk(GhGbYn-HNi}Nd&c_OS*0Pc_}VRpKF}cs1P7Hp_e3>^Q8)Mv6muw>8qN2F4pktMAQV90CiRxg0>aDxB@- zc0T+1W|iv6RkwY}Hs0|b<_%6iy?#{HQXZtB8@>^BDU5L*x`J;*ofCLd5;->L)CYY* zd_yS=m7$O&7nHFG6`7L7B1wd6L9toiN->wHHKGclbg#I^>+5useGAcH-pKY0dMf{P zuzWdm;D@}#a15$M@mV&j&mccN7-~q~bFA%8#y@mm<#AuwF`79-M~`(i4o#hgoVhH4NQPZPJA6v zO+*SW!G7HvRjYLP3#RLun<$m?B$e6U*6f#NBbCs$a{_B~<4eSR-*EA-3?aF~f0Ge4 zI)C@7J+}1oD7eChT)K5VPJ!8Lj|~U$6w@ilntj9;(u~OFFL2Vz^W05SR^Ml}&Ya5j z>DX5rh9HqGyU|&D0@=kiFtYmO=!&clM>JWJDK4LeJgHQC#Vu)Zb3GqZN@R9vjP!I_ zu_Bmss8%01i=fwV3|DFYdb$!YqoM*Q-z3$vcPVwj8WKd&Q5zf8w6MHjePYp*HmpqsC`_Cu9 zqgCp-In`5fzY|L?p7i{fOz5P?O4&#adGZz_i639HS)CwSp6tc(hRZ#%oMu~|&3a8U zT`EHFu5egZFEe$a&HRLNU`mz>0#&w6K zv_CPfAIdXKw2pM@1b&Iao({14wZ3|R2tb%-1V)3-3<@0*TA$_e{IX7Q+PJO4mW2w+ z(xPOP}G_8c{<}cOffRa6Xy;4V)R+3SX9YE)$;6UV$alt%Lk=0nXQA^AL>q|KQ0Caariplt zC!W8h+CpQ!HJ`Y0S1%5F3ZqwUN+p&y-6W=ryMwGFFh`Oik)}uHBM)hA%!=A~cX*Bg zIJGqd;^3nP==|L1szE?h&XHSEP}@0kJ0@zT`Zqo|!aO|19$9*;V{Jwh;XF~1<7i8M z`Gdzvl>1IB&ja;dGd_FCWB!gDS8P@U^^TU~=x_EG+hd)RBLQn2iA4`Mqt4DiEe)1v z5~R|7DPMXxcNT?yqS?0KJ+;o?TH@<)-%>Ph2J-D>aJBSVU%{+lkf5SQMS)Q*Hh=~aGp`+wm!pQP8p2|zj_SQ%3Q(lJk zxefx^MvNrv93012@D{-4Y_-m8UmI?-R5<3IY{P7(<8)Fmj`#fj?HEbWw^G&gZP08d z76Y-A+5pHS0r=i3Do8=t3PoZGnQOGO>&d-w zrPCO%@yj2{pzCDNaC7a0xVxuu&K8lU1j;vr(M2xre?m-QgoP27)|dzzcT=moq~RkszY%zVVBqd zH3>!Zy-WI*$%66cb8r&skr_JQ7bZ;}oOhW5@-EP#SBr3#v>TWJo~3{h%17r+DkGZ#ZKByBtn+IO4fKPwi}!(F(9=!F47ie5r2CtqMr;uPS(lU<2d9`O9p9y zWtbWx&b}58s+;)v^OX!G&#|Yrv8xy`xhpWIH>J?aK;-_~Id($%eCvs*4jEj+IA#gSPKqT7 z&TD~lL!BkSvkho^-j&5ueE8T|fn7w;dPN*}I`N(0)gV1EEg3QpD^dNp19yd%SP9tl zWvbFV>OUOAhw+sAID7DMyzp|M8#LcONcu#&ScxD$twR-agj)c6Srjy=@?oE*b*>yv@vp#-MV z!7wBLTwFQ}1sN@=OA1k$l~x|9q;#ubt!0z)juP<}-H&pFpiD3qok};xfaRl(nZS@w z^>~^)26%2%@nw+^O+|oh@z&5a_k(_B}%llbGIW|JYfy7DYF(MSEH3^(MX5`D~ zZvZb+V%qfTg>xQ110};pRbk=IXnC%8NT1e9-n%Xg7%R6rktxlm!Nowv_)=p@%F8F# zP%{sn6*^X5o-ne8zbwaNV_{voU-tftp=)!|#$Q2=PoGaQ`G8uWFdB z^EWmyvrDu;m#f+A)vS<*B}TBg?PS0_#&+IKPo6JKtC-Z63F7BNV5{mx82B6JOLYnY zOMl&TTAT@-zl~>qbdXQH?H5+nUaaXNyPRL>5qqzQ^)U*tu}w z0`~a^BA&m{!z91^s2Ckf3BNK-?IM9f{E1 z`h=nMpxnp-MWJweTTOxqJji|bHBTNt)7xzOGd3q`mnVe~R#!gA zk@*U|sq^aymM6++ctDzSh^UHt9AKDoW?Mj-DrIUsIM5S1Kr00K!XlgK(HHuK}2^2o4_xIbpgR20x9oW8E9Fln-YP;q|lAbY97LFK}akWJ5H zoV+PtzDP;m2{P!Y6Gz+WX95-|8#L>DMWrQ>6d(Wly40{aPZ=kySwLT0@-L$r1MK(+ zS=XRHIqoL!g`C~$b zKLh*2R3h|7s?!bp)KPi!!84U|IEZM7u__YGKSz6-RFX`)`;kq1s@p(k%Q&>kt-iXm zHGU{w%_T5!utQ-@e5ONOGTRv%<#AG(%v0seR{K^>=ECevcYbL8O>%GCc9LR{x7WvB zoi8Utg6@<{Tixbi_B}NC7FvxvO7&`WzBBhp=G4!c-dYRfX%-=*t7~4p+`1Q)s#_2)Eoo3KQkk>OaEWQf*C!~4wxN#|)8iU9f+)nanzqzwB6_m?45H3nIUSdaI zj*`&Y2qnw7xTGx9V0#%g#VmCLZXlwY8PPR7@3DAhiXi*?r1;37E_>=p#^%f_hg%W? zcdysSc1l6?Y$e-sD0@#t+odAsX6_}O$3f|{9Y6V-hj;NIt8Myg2aX=rO*y0e)jkgn zhZ0v0fS$^!a6Xz>%{X}Y`bp1OQQNu9#tqHE^d@54$XQYNuBqc;Nl&>_F}eNmQf_T% zZWjLP>`TwC>FUX0p4q(i`HTgZb-3pXJl_z#sCPZh&79F$GJuKNA-q%KVa%^rn7M9R zG%q@msoMw_l(NBw2WuS+Y!V7cYK&9dyk*lm!vn~)D4ilkVVliaPH`KZ8S%kjh-HO# zS4;8c0)Kz#?R&mO$@yp6nhMP|25oYYcJ0%`dNB$5;frj60@K;n^m|Mc?7BoIuIx9m zF=4YZ(i_IGTT^%RJF%;L=Mh)PHsxj3N&^mU`WKQ~g`R6ZIxN^5Vpxk^X3~I&y=AW#!bX)C;s?_pZlGpbP_Y2;>ZzVxt(^q zLcUjrF8!8kzN%Y*;1glr_>wLv!iXkiB)`dOf4e5_bbh{W9oognS@`{T8+SIx9w|h> z7eF6y`}r0$5YQ%wYKtp%rGz0nmJ8<8N8qR~Uhqp(b#ev>!D88yK<32ffX=s&4lEMd zjW{(~=rApb3ph20Xwfh_eaECZh+Kx(BHeln(wMHa#fM6SP-2RmhiOXO8kbk^b5N>i zUCy2S-zV4q8ep$KG38c3#e&V&mB7BvXwbl&y?@1*-Di1-rg zN*cao{uI+e%BC{jr{u4}0L2YKDJTLZPYz5HHSF%Wp&=`}G9jJrZTw3a=Y2dqLV4_w z^>?R<27y_%(ND_nNl28CF?#itezG4dmrDn)*q6-7rD&P$8|dVggRK21-%<|#+D|`YdgO&4odu z&1QDcrS)o#Ci6m!$6>Ej_Svc^lE>;sij|4dR#G~c#)_*fm+|)Hu~}YWR5MSW;LdLB z^FqUwX0U}DU>yJ_@{?i{V-9C6K}Ye|6$>PPzCfE`J{op31FCgK>AU%2h)Sh%VTfrQ zUSo2k+H+XDwUTyqr=*de3_nF?gogxsw1+p^3QY4}pEh}3a|(z`n-8)XrL?u}jtJEB zv+w-;J?e2v+rPXgo(V16M;Ju{5)Gw8S^r22UE!SLt z$9bzYzPl*_>txKculL6==k|qukvlDIHe6+2FQufWA4Xg9L`4o>iIxfRAdBKm`u;_5 zBOGTpN{-+~!wKqu7uDBK?4Eg)dhzJ>1WZt=<6YIG_BN2YDMWgN=%P0usJ&PQJgsHp zykK(ueB~-nl>xt3Byc1G=PeQLw%Gm;`noAf6G>yzoSG$aA6+@ zDzV3Fz@}%YlglbZB6i+S7TU}bb@b!?W#Av9fPP=-9qk5Ly@uNIa+Br%?G9v83Fj?a zgeMaG+wPy@LbVsfmlQP~F`gVV!gf2w`nDkKb-e1&FL%+1#YabM1cFDD8+MBbeJMbI z!|>7F`16U=^>7OXLo+i#1qdG!up6EGtlzibAAtBcrr_fNEC&BFhVEJ8q$? zhi#>*q)qK2BFEoBCwMI-paISvHB$m6L{|i`Q_GBCpg#1T{T&c&I05Lx9N^3QUJD$C zBz
  • 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
    hL-c-M6|mF1EtC<>BJhFf- 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 literal 0 HcmV?d00001 From 1de2fd86dd89a1083b095deffc1e9ff97cb27241 Mon Sep 17 00:00:00 2001 From: Phil Sturgeon <67381+philsturgeon@users.noreply.github.com> Date: Sun, 1 Dec 2024 17:55:02 +0000 Subject: [PATCH 3/3] openapi/asyncapi agnostic --- .../api-basics/dev-guide-api-design-first.md | 48 ++++++++++++++----- 1 file changed, 35 insertions(+), 13 deletions(-) diff --git a/src/_guides/api-basics/dev-guide-api-design-first.md b/src/_guides/api-basics/dev-guide-api-design-first.md index f4bcbd74..e5472247 100644 --- a/src/_guides/api-basics/dev-guide-api-design-first.md +++ b/src/_guides/api-basics/dev-guide-api-design-first.md @@ -7,8 +7,7 @@ excerpt: Learn about the principles of API design-first and how it can benefit y date: 2024-11-15 --- -API Design-First, also called schema-first or contract-first, is all about designing the interface of an API before writing any code. It's about planning the [API contract](https://bump.sh/blog/api-contracts-extended-introduction) first, and defining what the API does and how it works so everyone's on the same page before implementation starts. This approach has been around for a while, and over time, it's evolved to meet the needs of different technologies. These days, OpenAPI has become the defacto standard for designing REST APIs, and it can make life easier for everyone the whole way through the lifecycle of an API. - +API Design-First, also known as "schema-first" or "contract-first", is all about designing the interface of an API before writing any code. It's about planning the [API contract](https://bump.sh/blog/api-contracts-extended-introduction) first, and defining what the API does and how it works so everyone's on the same page before implementation starts. This approach has been around for a while, and over time, it's evolved to meet the needs of different technologies. These days, OpenAPI has become the defacto standard for designing REST APIs, and AsyncAPI has become the defacto standard for describing event-driven APIs. This workflow can make life easier for everyone the whole way through the lifecycle of an API. ## A Brief History @@ -20,6 +19,8 @@ To understand why design-first is such a big deal, it helps to know where it cam - **The OpenAPI era**: Around 2011, Swagger (later renamed OpenAPI) arrived to help describe REST APIs. It introduced a standard machine-readable format for defining operations, parameters, payloads, and validation rules, all using JSON or YAML. There were a few other similar projects (mainly RAML, API Blueprint) but they all fell out of use, and OpenAPI became the champion. +- **AsyncAPI**: In 2017, AsyncAPI released a v1.0 of a new specification to help event-driven architectures describe their APIs in a similar way to OpenAPI, in fact it was a fork. It includes support for common message brokers such as Apache Kafka and RabbitMQ amongst many others. + ## What Is API Design-First? API Design-First means you define the API's contract before writing any application code. This contract includes things like: @@ -41,9 +42,9 @@ Here's why design-first is worth the effort: 4. **Automation**: You can auto-generate documentation, code snippets, and even parts of the implementation using tools. 5. **Version control**: It's easier to track and manage changes to the API over time. -## OpenAPI and How It Helps +## API Description Formats and How They Help -Describing an API is the most important part of the API design-first workflow after planning is done, and for anyone building a REST/RESTish API, the API description format of choice is OpenAPI. +Describing an API is the most important part of the API design-first workflow after planning is done, and for anyone building a REST/RESTish API, the API description format of choice is OpenAPI. For anyone working with event-driven architectures the format of choice is AsyncAPI. OpenAPI documents are written in JSON or YAML, making them machine-readable, and somewhat human-readable too. They contain all the information needed to describe the interface of an API: requests, responses, reusable components, etc. @@ -76,13 +77,34 @@ This snippet describes an API endpoint `/users` that responds with a list of use If you're just getting started with OpenAPI, we're here to help you on your journey. We've put together a guide to help you [learn OpenAPI from scratch](https://docs.bump.sh/guides/openapi/specification/v3.1/understanding-structure/basic-structure/), starting from the basic structure and going through every part of the functionality. +AsyncAPI works in a very similar way, but instead of describing endpoints you describe "publishers" and "consumers". + +```yaml +asyncapi: 3.0.0 + +channels: + user/signedup: + address: user/signedup + messages: + publishUserSignedUp.message: + $ref: '#/components/messages/userSignedUp' + +operations: + publishUserSignedUp: + action: send + channel: + $ref: '#/channels/user~1signedup' + messages: + - $ref: '#/channels/user~1signedup/messages/publishUserSignedUp.message' +``` + ## Comparing Design-first and Code-first For years the API Code-first approach was the way to build an API. You'd sketch out the API you want to build on a whiteboard, then before that was even done somebody would be generating controllers and views in their favourite programming language and firing JSON around. The goal was always to get coding as fast as possible, so that clients could start integrating with it as soon as a prototype was ready. The rush to get coding often meant the first version clients get to see is not really anything like what they want, so a lot of time gets lost and wasted recoding controllers and doing database migrations. At some point everyone runs out of time and they have to go to production with whatever they have, even if it's a mess for clients to work with, and everyone just agrees to fix it all later in v2.0... -When OpenAPI is utilized in this approach, it is usually as annotations or code comments, popped into the application somewhere near the code it's describing, with the hope being that a developer will remember to update both at the same time. These annotations can then be exported to an `openapi.yaml` document which can be displayed as documentation or generate SDKs. +For example, when OpenAPI is utilized in this approach, it is usually as annotations or code comments, popped into the application somewhere near the code it's describing, with the hope being that a developer will remember to update both at the same time. These annotations can then be exported to an `openapi.yaml` document which can be displayed as documentation or generate SDKs. ```java class UserController { @@ -107,15 +129,15 @@ Here's a quick look at the two workflows for comparison. Whilst there are a few more steps, the time invested on agreeing a contract early on brings massive time benefits through the rest of the API lifecycle. -Combining the API-Design-first workflow with OpenAPI specifically allows for amazing benefits: +Combining the API-Design-first workflow with OpenAPI/AsyncAPI specifically allows for amazing benefits: 1. **Readable by humans and machines**: The YAML/JSON format means it's clear for developers and allows for API design reviews / governance with teams that don't have to read multiple programming languages. -2. **Interactive docs**: API Documentation generators like Bump.sh turn OpenAPI documents into interactive documentation, showing off parameters and examples, so clients can quickly and easily work with the API. -3. **Mock servers**: Tools like Microcks and Wiretap can use the OpenAPI document to simulate the API, allowing parallel development of API and client applications, and allowing feedback to come in early and often. -4. **Server-side Validation**: Instead of rewriting all of your validation logic in docs and code, you can use the OPenAPI document to power your application, making absolute certain the the documentation matches the implementation and reducing time spent writing code. -5. **Contract Testing**: Use automated tools to probe your API implementation based off the OpenAPI document, and add assertions to existing test suites saying "does this response match what it says in OpenAPI", further ensuring the two are in agreement and saving time writing complicated contract testing by hand. -6. **Code generation**: Many tools generate client libraries or server stubs directly from an OpenAPI document, saving loads of time. -7. **API Style Guides**: Style guides are hard to enforce against code, developers need to check them manually, but with OpenAPI you can enforce standards on the API from the very first endpoint that is described. +2. **Interactive docs**: API Documentation generators like Bump.sh turn OpenAPI/AsyncAPI documents into interactive documentation, showing off parameters and examples, so clients can quickly and easily work with the API. +3. **Mock servers**: Tools like Microcks and Wiretap can use the API descriptions to simulate the API, allowing parallel development of API and client applications, and allowing feedback to come in early and often. +4. **Server-side Validation**: Instead of rewriting all of your validation logic in docs and code, you can use the API descriptions to power your application, making absolute certain the the documentation matches the implementation and reducing time spent writing code. +5. **Contract Testing**: Use automated tools to probe your API implementation based off the API descriptions, and add assertions to existing test suites saying "does this response match what it says in the API description", further ensuring the two are in agreement and saving time writing complicated contract testing by hand. +6. **Code generation**: Many tools generate client libraries or server stubs directly from an OpenAPI/AsyncAPI document, saving loads of time. +7. **API Style Guides**: Style guides are hard to enforce against code, developers need to check them manually, but with OpenAPI/AsyncAPI you can enforce standards on the API from the very first endpoint that is described. Anyone who has written API documentation by hand knows that it takes forever and is usually bad and outdated very quickly, so the fact that you have entirely accurate documentation from the start is a huge benefit for most teams. @@ -125,4 +147,4 @@ Speed and accuracy both go through the roof, reducing time, cost and client frus ## Wrapping Up -API Design-First is all about getting the API's design nailed down before jumping into coding. It helps teams work faster, stay consistent, and avoid costly mistakes later on. OpenAPI has become the standard for REST APIs, making it easy to design, document, and manage APIs. While other technologies like GraphQL offer alternatives, the simplicity and reliability of REST, combined with OpenAPI's ecosystem, make it a solid choice for most teams. +API Design-First is all about getting the API's design nailed down before jumping into coding. It helps teams work faster, stay consistent, and avoid costly mistakes later on. OpenAPI has become the standard for REST APIs, making it easy to design, document, and manage APIs. AsyncAPI brings this same power to the event-driven API world. Tooling has evolved massively in the last few years to support these standards, so you aren't constantly having to convert things into multiple formats or try to duct-tape infinite tools together with no common source of truth.