docs
  1. Storefront Application
  2. Technical Foundation
  3. Rpc Methods

RPC methods

Overview

The SCAYLE Storefront is built upon a foundation of Remote Procedure Call (RPC) methods. These are JavaScript functions that adhere to a defined interface and are registered with the RPC system. This approach allows us to encapsulate business logic into reusable functions, exposed through an automatically generated API. As a result, developers can easily integrate this functionality without the overhead of building and managing REST APIs. TypeScript provides automatic type checking for parameters and return values, enhancing reliability.

Universal Rendering

Nuxt offers several rendering modes, with Universal Rendering being the most common. This mode renders Vue components on both the server and the client. However, RPC methods are executed exclusively on the server.

  • During Server-Side Rendering (SSR): Calling an RPC method directly executes its corresponding function on the server.
  • On the Client-Side: Calling an RPC method triggers an HTTP request to the server. The server then executes the method and returns the result.

This process is handled automatically, providing a consistent API for calling RPC methods regardless of the rendering context. In the Storefront Application, all calls to SCAYLE APIs are made within RPC methods. This server-side execution protects sensitive API tokens from client exposure and keeps certain implementation details private.

Rendering a Page on the Server

Consider the useProduct composable, which can be used during both server-side rendering and on the client. It relies on the getProduct RPC method. Because getProduct executes on the server, it has secure access to the API token and can call the Storefront API. Furthermore, most RPC methods leverage caching to reduce latency and minimize the load on the Storefront API.

Storefront Core API Example

Custom RPC Methods

Storefront applications can define and implement custom RPC methods, which are then callable within the application. These custom RPCs have access to the RPCContext, providing information about the session, shop, and secure tokens.

Creating a custom RPC method is recommended when integrating with external services, such as SCAYLE add-ons or third-party providers. This approach also helps prevent sensitive code and data from being exposed to the client.

To create a custom RPC method, simply add a new file to the rpcMethods directory of your project:

This example demonstrates creating an RPC method called getShopId, which returns the shop identifier from the context. This RPC takes no input arguments and fulfills the RPC contract.

It's crucial to export the getShopId function from its file and from the rpcMethods/index.ts file. To export from rpcMethods/index.ts, add the following line:

Passing Arguments to RPC Methods

RPC methods can accept parameters. Define these parameters as the first argument of your RPC function. The RpcContext remains the second argument. You'll also need to update the satisfies RpcHandler<Input, Output> declaration to reflect the input and output types.

This example defines the subscribeToNewsletter RPC method, which accepts an email address and (currently) returns it after subscribing the user to a newsletter. The RpcHandler type declaration specifies the input type ({ email: string }) and the output type (string).

Registering Custom RPC Methods

In order for a custom RPC method to be usable, it must be registered. Registration will create the necessary API endpoint for the RPC and extend the global types to include the RPC. The process of registering an RPC method changes depending on whether you are creating a custom RPC method within the Storefront Application or as part of a Nuxt module.

Within a Storefront Application

To register an RPC method in a Storefront Application, you must define rpcDir and rpcMethodNames in the module configuration (within your nuxt.config.ts or a relevant module setup). rpcDir defines the directory from where the method functions will be imported, and rpcMethodNames is a list of the identifiers to import and register as RPC methods.

Overriding Core RPC Methods

The Storefront SDKs also include their own set of RPCs. This introduces the possibility of name conflicts, which could result in accidentally overriding an existing RPC method.

  • Warning: In such cases, you will receive a warning in your console indicating which RPC method was overridden, as this can lead to unexpected side effects and cause the application to behave improperly.
  • Caution: Overriding core RPC methods should be done with extreme caution and only when absolutely necessary. If an RPC method is overridden, we cannot guarantee that the Storefront SDKs will work as expected. It becomes your responsibility to test all relevant cases thoroughly.
  • Silencing Warnings: To suppress console warnings for intended overrides, add the overridden RPC method's name to the storefront.rpcMethodOverrides configuration in your nuxt.config.ts.

Within a Nuxt Module

Nuxt modules can also register custom RPC methods. For a module to register a custom RPC method, they should register for the storefront:custom-rpc:extend hook and append their RPC method import definitions. An import definition includes the source file and the export names to register as RPC methods.

The registration of RPC methods via this hook is slightly more restrictive:

  • If a hook-registered RPC method uses the same name as an application-registered RPC method, the application-registered one will take precedence.
  • RPC methods registered via this hook are not allowed to override core RPC methods from the Storefront SDKs.
SourcePriorityCan Override Core RPCs?Location
Core RPC MethodMediumn/astorefront-corepackage
storefront:custom-rpc:extendLowNoNuxt module (or application)
`rpcDir`/`rpcMethodNames`HighestYesApplication

Calling Custom RPC Methods

After defining and registering your custom RPC methods, you need a way to call them from your components or composables. Two options are available, depending on your needs:

  1. useRpc: This composable provides a declarative approach for calling RPCs within pages, components, or other composables. It's suitable for calls that should occur during initial setup or data fetching. useRpc behaves similarly to useAsyncData.
  2. useRpcCall: Use this composable when triggering an RPC in response to an event or user interaction (e.g., clicking a button, submitting a form). useRpcCall is more akin to $fetch.

Both useRpc and useRpcCall are composables and must follow composable usage rules. For further guidance, refer to Nuxt's data fetching guide.

useRpc

useRpc offers a declarative approach to data fetching. It handles the fetch state, automatically executes the RPC method, and returns the result or any errors. Many Storefront Core composables utilize useRpc as lightweight wrappers around provided RPCs.

Here's how to call the getShopId RPC from the previous example:

The first argument to useRpc is the RPC method name (the name under which the RPC is exported). The second argument is a unique key, which Nuxt uses to avoid redundant fetches and repopulate server-side rendered data. For more details, consult the Nuxt documentation or check out the "Nuxt 3.8 - Client-side caching with getCachedData" YoutTube video by Alexander Lichter, a Core Nuxt Maintainer.

We recommend using location-specific unique keys and explicitly passing data rather than assuming key usage and fetch behavior elsewhere.

The third (optional) argument provides parameters to the RPC method. In this example, getShopId doesn't require parameters. If parameters are needed, you can pass a reactive function or a computed value. useRpc will automatically re-fetch the data if any of the reactive parameters change.

Managing Shared State with useRpc

By default, useRpc utilizes a shared cache, causing all instances called with the same key to share the same data. You can disable this behavior globally by setting the disableDefaultGetCachedDataOverride option in the public runtime config.

You can also disable this behavior for individual useRpc calls:

If disabled globally, you can re-enable shared caching for specific useRpc calls:

useRpcCall

useRpcCall is designed for calling RPCs in response to events or user interactions, such as clicking a button or submitting a form. Consider the subscribeToNewsletter example, triggered by a form submission:

useRpcCall accepts the RPC method name and returns a callback function. When invoked, this callback receives the RPC parameters, makes the request, and returns a promise that resolves with the RPC's response.

RPC Context

The RPC context object provides information about the current application, including application secrets and helper functions for RPCs. Key properties and methods include:

Property NameDescription
sapiClientA reference to the Storefront API client initialized to the shop of the request.
campaignKeyThe key for the currently active campaign. By default, we will choose any active campaign at the time of the request.
cachedA utility function for caching functions.
userThe current user.
wishlistKeyThe wishlist identifier for the current session.
basketKeyThe basket identifier for the current session.
sessionIdThe unique session id of the current user.
shopIdThe shop id of the current request.
logA reference to the logger.
runtimeConfigurationAn object containing the private properties set at runtime through the environment.

Extending the RPC Context

You can add custom information to the RPC context to make it available to all your RPC methods. This is achieved by hooking into the storefront:context:created Nitro runtime hook.

Create a server plugin and register a hook using nitroApp.hooks.hook('storefront:context:created', handler). The handler is a synchronous or asynchronous function that receives the base RPCContext as its argument. You can modify the context passed to RPC methods by adding or changing properties on this object.

Caution: Overwriting existing RPCContext properties is strongly discouraged, as it can break application functionality. Proceed with extreme care if you choose to do so.

Adding a New Property

To add a new property to the PRC Context, use the following snippet:

Overwriting Existing Values

While possible, overwriting or changing existing values within the RPC context is generally not recommended and should be done with extreme caution. If absolutely necessary, use the following approach: