‫Hey, welcome back.
‫In this lecture,
‫we're going to talk about designing the application
‫programming interface for our system.
‫As always, we will start with some introduction
‫and motivation for why we need to design an API
‫for our system.
‫And later we will talk about a few categories of APIs
‫as well as the best practices and patterns
‫for designing a good API for our clients.
‫So let's start with defining what an API is
‫and why we need it.
‫After we capture all the functional requirements,
‫we can start thinking about our system as a black box
‫that has behavior as well as a well defined interface.
‫That interface is essentially a contract
‫between us the engineers who implement the system,
‫and the client applications who use our system.
‫Since this interface is going to be called
‫by other applications,
‫we'll refer to this interface
‫as an application programming interface or API in short.
‫To clarify, since we are building a large scale system,
‫and not a class or a library,
‫this API is going to be called by other applications
‫remotely through the network.
‫The applications that are going to be calling our API
‫may be front-end clients like mobile applications
‫or web browsers.
‫They can be other backend systems
‫that belong into other companies,
‫or they can be internal systems within our organization.
‫Additionally,
‫once we finish the internal design of our system
‫and decide on its different components,
‫each such component will have its own API
‫which will be called by other applications
‫within our system.
‫Now let's talk about the different in categories of APIs
‫depending on the system we're designing
‫and the type of clients that are using it.
‫Generally we can classify APIs into three groups.
‫public APIs, private or internal APIs and partner APIs.
‫Public APIs are exposed to the general public
‫and any developer can use them and call them
‫from their application.
‫A good general practice for public APIs
‫is requiring the users to register with us
‫before we allow them to send us requests and use our system.
‫This allows us to have better control
‫over who uses our system externally
‫and how they're using it.
‫This in turn provides us with better security
‫and also allows us to blacklist users
‫that don't play by our rules.
‫Private APIs are exposed only internally within our company.
‫Private APIs allow other teams or part of our organization
‫to take advantage of our system and for provide bigger value
‫for our company without exposing our system directly
‫outside the organization.
‫Partner APIs are very similar to public APIs,
‫but instead of being exposed
‫and available to anyone who wants to use them,
‫they're exposed only to companies or users
‫that have a business relationship with us
‫in a form of a customer agreement
‫after buying our product or subscribing to our service.
‫Having an explicit contract
‫in the form of an API with our clients has a few benefits.
‫The main benefit of a well defined API
‫is that the client who uses it can immediately
‫and easily enhance their business
‫by using our system without knowing anything
‫about our system's internal design or implementation.
‫However, there are a few other benefits
‫that should be considered.
‫As we're going through the design process of our system,
‫once we define our API and expose it to anyone
‫who wants to use it in the future,
‫those clients don't have to wait
‫until we finish implementing our system.
‫And once they know our API,
‫they can already start making progress
‫towards their integration with us.
‫Another benefit is once we define our API,
‫it's a lot easier for us to design
‫and architect the internal structure of our system
‫because this interface essentially defines the endpoints
‫to the different routes
‫that the user can take to use our system.
‫Now, let's talk about the important considerations,
‫patterns and best practices
‫for designing a good and easy to use API.
‫The first rule that would make a good API for any system
‫not only a large scale system
‫is complete encapsulation of the internal design
‫and implementation and abstracting it away
‫from the developer that wants to use our system.
‫In other words, if a client who wants to use our API
‫finds himself requiring information
‫about how this API is implemented internally,
‫or needs to know too much about our business logic
‫for them to use it,
‫the whole purpose of the API is defeated.
‫In addition, we want our API to be completely decoupled
‫from our internal design and implementation
‫so that we can change that design anytime in the future
‫without breaking our contract with existing clients.
‫Another thing to consider when designing an API
‫is that it needs to be easy to use, easy to understand
‫and impossible to misuse accidentally or on purpose.
‫A few things that can help make an API simple
‫are having only one way to get certain data
‫or perform a task and not many.
‫Having descriptive names for our actions
‫and resources and exposing only the information
‫and the actions that the user need, and not more than that.
‫Also keeping things consistent all across our API
‫will make using it a lot easier.
‫The next best practice for a good API
‫is keeping the operations idempotent as much as possible.
‫An idempotent operation
‫is an operation that doesn't have any additional effect
‫on the result if it's performed more than once.
‫For example, updating the user's address to a new address
‫is an idempotent operation because result is the same
‫regardless whether we perform this operation one time,
‫five times or 10 times.
‫On the other hand,
‫incrementing a user's balance by $100
‫is not an idempotent operation
‫because the result will be different
‫depending on the number of times we perform this operation.
‫The reason we prefer idempotent operations for our API
‫is that our API is going to be used through the network.
‫So if the client application sends us a message,
‫that message can be either lost.
‫The response to that message may be lost
‫or a critical component inside our system may go down
‫and the message wasn't even received.
‫Because of this network decoupling
‫the client application has no idea
‫which one of those scenarios actually happened.
‫So if that operation is idempotent,
‫then the client application can simply resend
‫the same message again without risking adverse consequences.
‫The next best practice is called API pagination.
‫Pagination is an important API feature
‫for scenario when the response from our system
‫to the client request
‫contains a very large payload or dataset.
‫Without pagination, most client applications
‫would either not be able to handle such big responses
‫or result in a poor user experience.
‫Imagine what would happen
‫if you opened your email account on your web browser,
‫and instead of seeing only the last 10 or 20 emails,
‫you would be presented with all the thousands of emails
‫that you ever received since you opened your email account
‫all on one page.
‫Similarly, you can imagine what would happen
‫if you opened your favorite online store or search engine
‫on your mobile phone or web browser.
‫And anytime you searched for a particular item,
‫you would get all the thousands or maybe millions of items
‫that somehow matched your search query.
‫Obviously, if your application or web browser
‫was even able to handle so much data without crushing,
‫which in most cases is highly unlikely,
‫it would take an unreasonable time
‫to show all those results.
‫So pagination allows the client
‫to request only a small segment of the response
‫by specifying the maximum size of each response
‫from our our system,
‫and an offset within the overall dataset.
‫And if they want to receive the next segment,
‫they simply increment the offset.
‫The next best practice and pattern refers to the operations
‫that take a long time for our system to complete.
‫Unlike the previous examples
‫where partial results were meaningful,
‫so we could solve them using pagination,
‫some operations just need one big result at the end
‫and there is nothing meaningful that we can provide
‫before the entire operation finishes.
‫A few examples of such operations
‫can be running a big report
‫that requires our system to talk to a lot of databases,
‫big data analysis that scans a lot of records or log files
‫for aggregation purposes
‫or compression of large video files.
‫In all those use cases, if the operation takes a long time,
‫the client application is forced to wait for the result
‫without the ability to make any progress.
‫The pattern that is used for this type of situation
‫is called an asynchronous API.
‫With an asynchronous API,
‫a client application receives a response immediately
‫without having to wait for the final result.
‫That response usually includes some kind of identifier
‫that allows the client application to track the progress
‫and status of the operation,
‫and eventually receive the final result.
‫The final important best practice
‫for designing a good API is a explicitly versioning it
‫and allowing the client
‫to know which version of the API they're currently using.
‫The motivation behind versioning our API is as follows.
‫As we mentioned earlier, the best API we can design
‫is the one that allows us to make changes
‫to the internal design and implementation
‫without needing to make any changes to the API.
‫However, in practice, we can't always predict the future
‫and we may be forced
‫to potentially make non-backward compatible API changes
‫at one point or another.
‫So if we explicitly version the APIs,
‫we can essentially maintain two versions of the API
‫at the same time and deprecate the older one gradually
‫with proper communication with the clients
‫who are still using it.
‫Now, theoretically we're free to define our API
‫in any way we want.
‫As long as we adhere to those best practices
‫we just mentioned.
‫But over time, a few APIs became more standard
‫in the industry.
‫So we're going to cover those types of APIs
‫in the next lectures.
‫But before we go there,
‫let's quickly summarize what we learn in this lecture.
‫In this lecture, we defined an API
‫as a contract that we define for other applications
‫so they can use our system without knowing anything
‫about its internal design and implementation.
‫Later, we talked about the three categories of APIs
‫which are the public API, private API and partner APIs.
‫And finally,
‫we talked about a few best practices and patterns
‫for designing a good API, which are encapsulation,
‫ease of use, making our operations idempotent,
‫pagination, asynchronous operations and API versioning.
‫I will see you soon in the next lecture.