{"id":115976,"date":"2026-09-05T14:31:23","date_gmt":"2026-09-05T09:01:23","guid":{"rendered":"https:\/\/jhansimediaclub.com\/?p=115976"},"modified":"2026-09-05T14:31:24","modified_gmt":"2026-09-05T09:01:24","slug":"a-closer-look-at-viper-and-what-makes-it-different","status":"publish","type":"post","link":"https:\/\/jhansimediaclub.com\/?p=115976","title":{"rendered":"A closer look at VIPER and what makes it different"},"content":{"rendered":"<div lang=UK>\n<h2>A closer look at VIPER and what makes it different<\/h2>\n<p>In the ever-evolving landscape of iOS development, architectural patterns come and go, but few have sparked as much debate and dedication as VIPER. Unlike the more familiar Model-View-Controller (MVC) approach that Apple champions by default, VIPER presents a radically different philosophy\u2014one that prioritises testability, modularity, and clear separation of concerns above all else. This article takes a comprehensive look at what makes VIPER genuinely distinctive, dissecting its components, weighing its trade-offs, and examining its place in the modern development ecosystem.<\/p>\n<h2>Understanding the Core Principles Behind the VIPER Architecture<\/h2>\n<p>At its heart, VIPER is not merely a collection of design patterns but a fundamental rethinking of how an application&#8217;s responsibilities should be distributed. The acronym stands for View, Interactor, Presenter, Entity, and Router\u2014five distinct layers that each have a single, well-defined job. This granularity ensures that no single component becomes a &#8220;god object&#8221; that silently accumulates too many responsibilities, a common pitfall in many MVC-based projects.<\/p>\n<p>The philosophy draws heavily from Robert C. Martin&#8217;s Clean Architecture, which posits that software should be divided into layers that depend only on inner, more abstract layers. In VIPER, the flow of dependencies is unidirectional: the View knows about the Presenter, the Presenter knows about the Interactor and Router, and the Interactor knows about Entities. This strict dependency rule creates a system where each layer can be developed, tested, and modified in isolation without causing ripple effects throughout the codebase.<\/p>\n<p>Another core <a href=\"https:\/\/viper-casino.co.uk\/\">https:\/\/viper-casino.co.uk\/<\/a> principle is the separation of navigation from presentation logic. In traditional MVC, pushing a new view controller onto a navigation stack is often done directly from within the controller itself, coupling business decisions with UI flow. VIPER&#8217;s Router component abstracts this entirely, meaning that the decision to navigate and the execution of that navigation are handled in separate, testable units. This separation is not just a theoretical nicety; it has profound practical implications for how teams structure their work and how they approach complex user journeys.<\/p>\n<h2>VIPER vs MVC: Why the Shift in iOS Development Matters<\/h2>\n<p>For years, Apple&#8217;s MVC has been the default starting point for iOS apps, largely because it is baked into the SDK&#8217;s class libraries. However, as apps have grown in complexity, MVC&#8217;s limitations have become increasingly apparent. The &#8220;Massive View Controller&#8221; problem\u2014where controllers balloon to thousands of lines of code handling everything from data fetching to UI updates\u2014is a direct consequence of MVC&#8217;s loose structure. Table view data sources, delegate methods, network calls, and model mutations all end up jumbled together, making the codebase fragile and difficult to reason about.<\/p>\n<p>VIPER offers a decisive break from this pattern. By forcing developers to split these responsibilities across five distinct layers, it eliminates the temptation to throw everything into the view controller. To illustrate the difference, consider how a simple &#8220;user login&#8221; flow would be handled in both architectures. In MVC, the controller would validate the input, call the network service, parse the response, update the UI, and handle navigation\u2014all in one sprawling class. In VIPER, the View merely collects input and passes it to the Presenter. The Presenter orchestrates the flow, asking the Interactor to perform the login. The Interactor calls the network, receives a response, and returns the result. The Router then decides whether to navigate to the home screen or display an error. Each step is isolated, testable, and replaceable.<\/p>\n<p>The shift matters because it fundamentally changes how teams approach bug fixing and feature development. With MVC, a change to the login logic might require wading through hundreds of lines of unrelated UI code. With VIPER, a developer can open the Interactor, modify the business logic, and be confident that the change will not break the UI\u2014provided the interfaces remain stable. This level of confidence is invaluable in a fast-paced development environment where regressions are costly and time-consuming to diagnose.<\/p>\n<h2>The Five Components of VIPER Explained Simply<\/h2>\n<p>To truly grasp VIPER, you need to understand each of its five pillars and how they interlock. While the names might sound intimidating at first, their roles are surprisingly straightforward once you strip away the jargon. Here is a quick breakdown of each component and its primary responsibility:<\/p>\n<ul>\n<li><strong>View:<\/strong> This is the most passive layer. It displays what the Presenter tells it to display and forwards user actions (button taps, gestures) to the Presenter. It contains zero business logic and typically holds no state beyond what is needed for UI rendering.<\/li>\n<li><strong>Interactor:<\/strong> This is the workhorse of the architecture. It contains the application&#8217;s business logic and performs all data operations. It fetches data from APIs or local databases, manipulates Entities, and returns results to the Presenter.<\/li>\n<li><strong>Presenter:<\/strong> This acts as the middleman. It receives user inputs from the View, formats data for display, and instructs the View on what to render. It also receives outputs from the Interactor and translates them into presentable formats, such as view models.<\/li>\n<li><strong>Entity:<\/strong> These are plain data objects that represent the core model of your application. They are passive and contain no logic. In most cases, they are simple structs or classes that conform to Codable for easy serialisation.<\/li>\n<li><strong>Router:<\/strong> This handles all navigation logic. It knows how to move from one screen to another and passes data between modules. It is the only component that directly references other modules&#8217; Routers or View controllers.<\/li>\n<\/ul>\n<p>What makes this architecture so compelling is the way these components communicate. The View and the Presenter communicate through a protocol, as do the Presenter and the Interactor. This protocol-based communication is the key to VIPER&#8217;s testability\u2014you can easily mock any layer to test the others in isolation. The dependency injection is also explicit: each component is given its dependencies through initialisers, making the flow of control transparent and easy to follow.<\/p>\n<h2>How the View Interacts with the Presenter in VIPER<\/h2>\n<p>The View-Presenter relationship is arguably the most critical interaction in the entire architecture, as it defines the boundary between the UI and the app&#8217;s logic. In VIPER, the View is deliberately &#8220;dumb.&#8221; It does not decide what to display or when to update; it simply waits for instructions. When a user taps a button, the View calls a method on the Presenter, passing along any relevant data. The Presenter then processes this request, potentially consulting the Interactor, and eventually sends back a formatted response.<\/p>\n<p>This interaction is defined by a protocol, usually named something like <code>ViewToPresenterProtocol<\/code>. The View conforms to a separate protocol that the Presenter uses to update the UI. For example, the Presenter might call <code>view.showLoadingIndicator()<\/code> or <code>view.displayUserData(user)<\/code>. This inversion of control means that the View&#8217;s implementation can be swapped out without affecting the Presenter&#8217;s logic\u2014crucial for supporting multiple UI variations or for unit testing the Presenter with a mock View.<\/p>\n<p>One of the benefits of this design is that it makes UI changes remarkably safe. If a designer decides to move a button from the top of the screen to the bottom, the developer only needs to update the View&#8217;s layout. The Presenter&#8217;s method that handles the button tap remains unchanged, as does the Interactor&#8217;s business logic. This separation also makes it easier to implement complex UI states, such as loading, error, and empty states, because the Presenter can explicitly instruct the View to render each state without the View having to infer it from the data.<\/p>\n<h2>The Role of the Interactor in Handling Business Logic<\/h2>\n<p>The Interactor is where the &#8220;real work&#8221; happens. It is responsible for executing the business rules that define your application&#8217;s behaviour. Whether it is calculating a total price, validating a user&#8217;s input, or fetching data from a remote server, the Interactor does it. The Interactor does not know anything about the UI; it only knows how to manipulate Entities and return results.<\/p>\n<p>This separation is crucial for testing. Because the Interactor is a pure Swift class with no UIKit dependencies, you can write unit tests for it with minimal setup. You can mock the networking layer or the database and verify that the Interactor calls the right methods, handles errors correctly, and returns the expected output. This is a significant advantage over MVC, where testing business logic often requires instantiating a full view controller and mocking its view, which is cumbersome and brittle.<\/p>\n<p>The Interactor also enforces a strict boundary around data access. It is the only component that is allowed to interact with Entities directly. The Presenter and View treat Entities as opaque objects\u2014they receive them from the Interactor and format them for display, but they never modify them. This ensures that the data model remains consistent and that changes to the data layer do not inadvertently corrupt the UI state. In practice, the Interactor often wraps multiple services (like a network manager and a local cache) into a single cohesive unit, providing a clean API for the Presenter to consume.<\/p>\n<h2>Why the Entity Layer Keeps Your Data Models Clean<\/h2>\n<p>In many architectures, the model layer becomes a dumping ground for all sorts of logic\u2014formatting, validation, and even network calls. VIPER prevents this by making Entities nothing more than plain data containers. They represent the fundamental objects of your app, such as a <code>User<\/code>, a <code>Product<\/code>, or an <code>Order<\/code>. They are typically simple structs with properties and initialisers, possibly conforming to <code>Codable<\/code> for JSON parsing.<\/p>\n<p>Keeping Entities clean has a profound impact on code maintainability. Because they contain no behaviour, they are trivial to test and cannot break. They are also easy to reason about\u2014you can look at an Entity and immediately understand what data it holds. This clarity becomes invaluable when multiple teams are working on different features, as the data models serve as a shared vocabulary. When a new developer joins the team, they can quickly understand the app&#8217;s domain by examining the Entity definitions.<\/p>\n<p>Furthermore, this clean separation allows the Interactor to perform business logic without worrying about how the data will be displayed. For instance, the Interactor might return a list of <code>Product<\/code> entities to the Presenter. The Presenter then formats them into a <code>ProductViewModel<\/code> that includes display-specific fields like a formatted price string or a truncated description. This two-tiered approach\u2014raw Entities for logic, formatted view models for UI\u2014prevents the model layer from becoming polluted with presentation concerns and keeps the UI flexible.<\/p>\n<h2>The Router\u2019s Job in Managing Navigation and Flow<\/h2>\n<p>Navigation is often an afterthought in architectural discussions, but VIPER treats it as a first-class citizen. The Router is responsible for every transition between screens. It knows how to instantiate a new module (View, Presenter, Interactor, and Router) and how to present it, whether by pushing onto a navigation stack, presenting modally, or switching tabs. It also handles passing data from one module to another.<\/p>\n<p>This centralisation of navigation has a significant benefit: the rest of the app does not need to know how navigation is implemented. A Presenter can simply call <code>router.navigateToDetailScreen(productID:)<\/code> without caring whether the destination is a SwiftUI view, a storyboard-based controller, or a fully programmatic view. This abstraction makes the app much easier to refactor, as navigation changes are isolated to the Router layer.<\/p>\n<p>Routers also promote reusability. If you need to navigate to a &#8220;Profile&#8221; screen from three different places, you can reuse the same Router method. This reduces duplication and ensures a consistent navigation experience. In more complex VIPER setups, Routers can also handle complex flow logic, such as deciding whether to show an onboarding sequence or skip straight to a dashboard, based on the app&#8217;s state. This keeps decision-making out of the View and Presenter, further simplifying their roles.<\/p>\n<h2>Key Differences Between VIPER and Other Clean Architecture Patterns<\/h2>\n<p>VIPER is often compared to other architecture patterns like MVP (Model-View-Presenter) and MVVM (Model-View-ViewModel), especially since they all aim to solve similar problems. However, there are crucial distinctions that set VIPER apart. The most obvious difference is the addition of the Router, which explicitly handles navigation\u2014something that is largely ignored in MVP and MVVM. In those patterns, navigation is typically handled by the View or a Coordinator, which can lead to the same kind of coupling that VIPER seeks to avoid.<\/p>\n<p>Another key difference lies in the level of granularity. Both MVP and MVVM have three main components, whereas VIPER has five. This extra granularity means that VIPER enforces a stricter separation of concerns. In MVP, the Presenter often takes on some of the navigation responsibilities. In MVVM, the ViewModel handles the presentation logic but the View still manages navigation. VIPER&#8217;s approach is more rigid, requiring more upfront planning but offering clearer boundaries and better testability in the long run.<\/p>\n<p>To better illustrate the differences, consider the following table comparing the key architectural patterns:<\/p>\n<table>\n<thead>\n<tr>\n<th>Aspect<\/th>\n<th>MVC<\/th>\n<th>MVP<\/th>\n<th>MVVM<\/th>\n<th>VIPER<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>Number of Core Components<\/td>\n<td>3<\/td>\n<td>3<\/td>\n<td>3<\/td>\n<td>5<\/td>\n<\/tr>\n<tr>\n<td>Navigation Handling<\/td>\n<td>View Controller<\/td>\n<td>Presenter\/View<\/td>\n<td>Coordinator\/View<\/td>\n<td>Router (dedicated)<\/td>\n<\/tr>\n<tr>\n<td>Business Logic Location<\/td>\n<td>Model\/Controller<\/td>\n<td>Presenter<\/td>\n<td>Model\/ViewModel<\/td>\n<td>Interactor (dedicated)<\/td>\n<\/tr>\n<tr>\n<td>Testing Ease<\/td>\n<td>Difficult<\/td>\n<td>Moderate<\/td>\n<td>Moderate<\/td>\n<td>Very High<\/td>\n<\/tr>\n<tr>\n<td>Dependency Direction<\/td>\n<td>Unclear<\/td>\n<td>View -> Presenter<\/td>\n<td>View -> ViewModel<\/td>\n<td>Strictly Inward<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>As the table demonstrates, VIPER is the most explicit about where each responsibility lies. While this can be seen as over-engineering for small apps, it becomes a powerful tool for large, long-lived projects where clarity and testability are paramount.<\/p>\n<h2>Testing Benefits That Make VIPER Stand Out for Developers<\/h2>\n<p>Testability is the single most compelling reason teams choose VIPER, and it is not hard to see why. Because every component is protocol-driven and has a single responsibility, mocking dependencies becomes trivial. You can write a unit test for the Presenter by creating a mock View and a mock Interactor, then verify that the Presenter correctly handles a user action. You do not need to instantiate a real View controller or wait for a network response.<\/p>\n<p>The Interactor is equally testable. By injecting a mock data service, you can test business rules without ever hitting a real API. This allows for fast, reliable unit tests that run in milliseconds, making it feasible to have a robust test suite that catches regressions early. In contrast, testing an MVC view controller often requires setting up a full UI test environment, which is slow and flaky.<\/p>\n<p>Moreover, VIPER naturally supports test-driven development (TDD). Because the contracts between components are defined by protocols from the outset, you can write tests before the implementation exists. This &#8220;test-first&#8221; approach leads to better-designed interfaces and more reliable code. Many teams report that adopting VIPER improved their code coverage from around 20% to over 80% within a few months, primarily because the architecture makes testing so straightforward. The ability to test the entire app&#8217;s logic without launching the UI is a game-changer for maintaining quality in large codebases.<\/p>\n<h2>Common Pitfalls When First Adopting VIPER in a Project<\/h2>\n<p>Despite its benefits, VIPER has a steep learning curve, and many teams stumble when they first adopt it. The most common pitfall is over-abstraction. Developers new to VIPER often create protocols and classes for every conceivable scenario, even when a simple closure would suffice. This leads to a proliferation of files and boilerplate code that can overwhelm the project. The key is to start simple\u2014use VIPER for a single feature or module, and only abstract what is truly needed.<\/p>\n<p>Another frequent mistake is misusing the Router. Some developers treat the Router as a central navigation manager that knows about every screen in the app, creating a god object. Instead, each module should have its own Router, and the Router should only know how to navigate to its immediate children or neighbours. This keeps the dependency graph acyclic and manageable.<\/p>\n<p>There is also the challenge of communication between modules. When one module needs to send a result back to a previous module, it can be tempting to use hard-coded references or notifications. However, the recommended way is to use protocol delegates or closure-based callbacks. Failing to do this can create hidden coupling between modules, undermining the entire point of the architecture. Finally, many teams underestimate the importance of injecting dependencies correctly. If the Presenter or Interactor instantiate their own dependencies internally, they become hard to test and tightly coupled, defeating the purpose. A disciplined approach to dependency injection is essential for reaping VIPER&#8217;s full benefits.<\/p>\n<h2>Practical Tips for Structuring a VIPER Module From Scratch<\/h2>\n<p>Starting a new VIPER module from scratch can be daunting, but following a clear, repeatable process can make it painless. First, define the Entity or Entities that the module will work with. These should be pure data models. Next, build the Interactor around those entities, implementing the necessary business logic. The Interactor should expose a protocol (e.g., <code>InteractorInput<\/code>) that the Presenter will use, and it should have a corresponding output protocol (<code>InteractorOutput<\/code>) to send results back.<\/p>\n<p>Once the Interactor is ready, create the Presenter. The Presenter conforms to two protocols: one for receiving events from the View (<code>ViewOutput<\/code>) and one for providing data to the View (<code>PresenterInput<\/code>). It also holds a reference to the Interactor&#8217;s input protocol and the Router. After the Presenter, build the Router, which will have a method to create the module (often called <code>createModule()<\/code>) and a method for each navigation action the module needs to perform. Finally, implement the View, which is typically a <code>UIViewController<\/code> that conforms to the Presenter&#8217;s input protocol and owns the Presenter.<\/p>\n<p>To keep the module organised, use a clear folder structure. A common convention is to create a subfolder for each VIPER module under <code>Modules\/<\/code>, with subfolders for <code>View<\/code>, <code>Presenter<\/code>, <code>Interactor<\/code>, <code>Entity<\/code>, and <code>Router<\/code>. This makes it easy for developers to find relevant files and understand the module&#8217;s boundaries at a glance. It is also helpful to use a code generator or a Swift template to automate the creation of the boilerplate, ensuring consistency across the team and reducing the initial friction of writing dozens of protocol declarations by hand.<\/p>\n<h2>When VIPER Is the Right Choice and When It Might Be Overkill<\/h2>\n<p>VIPER is not a silver bullet, and choosing it for every project would be a mistake. It shines in large, complex applications with extensive business logic, multiple user roles, and a need for thorough unit testing. Apps like banking portals, e-commerce platforms, and corporate dashboards are ideal candidates. In these contexts, the upfront investment in creating five layers per module pays off handsomely in reduced bugs, easier maintenance, and faster feature iteration.<\/p>\n<p>However, for small apps or prototypes, VIPER can feel like wielding a sledgehammer to crack a nut. The boilerplate code required for even a simple screen\u2014five classes, several protocols, and dependency wiring\u2014is disproportionate to the complexity of the task. A developer can create a simple MVC or MVVM-based screen in a fraction of the time. For a hackathon project or a minimal viable product (MVP), the cognitive overhead of VIPER can slow down development considerably.<\/p>\n<p>The decision also depends on your team&#8217;s expertise. If your team is new to VIPER, there will be a learning curve that temporarily reduces velocity. If you are under a tight deadline, it might be wise to defer VIPER adoption until a calmer period. Ultimately, the right choice depends on the project&#8217;s expected lifespan and complexity. If you anticipate the app growing significantly and being maintained for years, the benefits of VIPER will likely outweigh the initial costs. If the app is a simple utility that you plan to ship quickly and rarely touch, a lighter architecture is more pragmatic.<\/p>\n<h2>Real-World Examples of Apps Built With VIPER<\/h2>\n<p>VIPER has been adopted by several high-profile companies, particularly those with massive, data-heavy applications. One of the most famous examples is the Uber app, which has used VIPER in various iterations to handle its complex ride-hailing flows. The app&#8217;s need to manage multiple concurrent states (driver location, rider request, payment processing) and its rigorous testing standards made VIPER an attractive choice. The architecture allowed Uber&#8217;s teams to work on different parts of the app independently without stepping on each other&#8217;s toes.<\/p>\n<p>Another notable example is the American Express mobile app. The company&#8217;s engineering team has publicly discussed their use of VIPER to improve code quality and testability across their iOS application. They highlighted that the architecture helped them reduce the number of crashes and regressions, largely due to the ease of writing comprehensive unit tests. Similarly, many fintech startups, such as Revolut and Monzo, have experimented with VIPER or similar Clean Architecture patterns to ensure stability in their financial services apps, where a bug in the transaction logic could have severe consequences.<\/p>\n<p>Beyond the well-known names, VIPER is popular in the travel and hospitality sector. Companies like Booking.com and Airbnb have large teams working on feature-rich apps, and they use VIPER (or a variant) to manage the complexity of search, booking, and payment flows. The common thread across these examples is scale and complexity. Each of these apps has a vast feature set, and the strict modularity of VIPER allows them to scale their development efforts effectively. While VIPER is less common in indie development, its presence in enterprise environments is a testament to its ability to handle serious engineering challenges.<\/p>\n<h2>How VIPER Improves Team Collaboration and Code Ownership<\/h2>\n<p>One of the less-discussed but highly valuable benefits of VIPER is its positive impact on team dynamics. The clear separation of responsibilities creates natural code ownership boundaries. A senior developer can take ownership of the Interactor, which contains the most critical business logic, while a junior developer can work on the View or the Router, which are more straightforward. This division allows team members to specialise and become experts in their respective layers, improving overall code quality.<\/p>\n<p>The protocol-based interfaces also make merging code easier. When two developers are working on the same module, they can work on different components simultaneously. For example, one developer can implement the View while another works on the Presenter, as long as they agree on the protocol interface. This reduces merge conflicts and accelerates development. Furthermore, code reviews become more focused and manageable. Instead of reviewing a massive pull request with hundreds of lines of mixed UI and logic, reviewers can examine each component&#8217;s changes in isolation, making it easier to spot bugs and suggest improvements.<\/p>\n<p>Additionally, VIPER encourages better documentation practises. Since each module has a well-defined structure, it becomes natural to document the responsibilities of each layer, the protocols, and the flow of data. This documentation serves as a valuable onboarding tool for new team members, who can quickly understand how a feature is implemented by reading the protocols and the Router. The architecture promotes a culture of ownership, where developers are proud of their well-tested and cleanly separated code, leading to higher morale and lower turnover.<\/p>\n<h2>Future Outlook for VIPER in Modern iOS and Cross-Platform Development<\/h2>\n<p>As the iOS ecosystem evolves, with SwiftUI gaining prominence and Swift Concurrency changing how we write asynchronous code, the future of VIPER is a topic of discussion. Some argue that SwiftUI&#8217;s declarative nature and built-in state management make architectures like MVVM more natural, potentially reducing the need for VIPER&#8217;s rigid structure. However, VIPER is far from obsolete. Its principles of clean separation and testability remain as relevant as ever, and many teams continue to use it successfully with SwiftUI, albeit with some adaptations.<\/p>\n<p>In the cross-platform world, VIPER has also found a niche. Frameworks like Kotlin Multiplatform and Flutter have their own architectural patterns, but the core ideas of VIPER\u2014single responsibility, protocol-driven design, and strict dependency rules\u2014translate well across platforms. Some teams use VIPER as a shared architectural blueprint for both their iOS and Android apps, ensuring consistency in how business logic is structured and tested, even if the UI implementations differ drastically.<\/p>\n<p>The rise of modularisation and microservices in backend development has also influenced mobile architectures. VIPER&#8217;s emphasis on modularity aligns perfectly with this trend. As apps become collections of independent feature modules, the clarity that VIPER provides becomes even more critical. While the specific implementation details may evolve\u2014perhaps the Router becomes a more centralised navigation coordinator, or the Interactor leverages more async\/await patterns\u2014the underlying philosophy of VIPER is likely to endure. It offers a disciplined, professional approach to app development that many teams will find indispensable for years to come.<\/p>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>A closer look at VIPER and what makes it different In the ever-evolving landscape of iOS development, architectural patterns come and go, but few have sparked as much debate and dedication as VIPER. Unlike the more familiar Model-View-Controller (MVC) approach that Apple champions by default, VIPER presents a radically different philosophy\u2014one that prioritises testability, modularity, [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-115976","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/jhansimediaclub.com\/index.php?rest_route=\/wp\/v2\/posts\/115976","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/jhansimediaclub.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/jhansimediaclub.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/jhansimediaclub.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/jhansimediaclub.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=115976"}],"version-history":[{"count":1,"href":"https:\/\/jhansimediaclub.com\/index.php?rest_route=\/wp\/v2\/posts\/115976\/revisions"}],"predecessor-version":[{"id":115977,"href":"https:\/\/jhansimediaclub.com\/index.php?rest_route=\/wp\/v2\/posts\/115976\/revisions\/115977"}],"wp:attachment":[{"href":"https:\/\/jhansimediaclub.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=115976"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/jhansimediaclub.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=115976"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/jhansimediaclub.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=115976"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}