question

Francois Boucher-Genesse avatar image
Francois Boucher-Genesse asked

Calling client API from Azure Functions

Hello,

Upon players registering to our service through AddUsernamePassword, we need the ability to set their contact email (only available from the client API) and to remove tags. We're trying to put these critical steps on the server rather than on our unity client, as we want to remove risks of connection issues between the client / server in between these steps. AddUsernamePassword doesn't seem to generate any PlayStream event, so we can't hook a cloudscript on that event which would then trigger some logic server side.

I've been setting up Azure Functions to do all the steps mentioned above, as a moderator mentioned that it has access to the client API. The unity client calls this azure function, which makes calls to the client API (AddUsernamePasswordAsync, then AddOrUpdateContactEmailAsync). I can also use rules to trigger some further actions when that Azure Function is called.

Everything seems to be working, but I just stumbled upon this thread, in which it is suggested that we should never use the client API from Azure Functions, since we would hit the rate limit. So...

Question A: are we supposed to use the Client API at all in Azure Functions, or is it not a recommended practice?

If there exists a proper way to use the client API from Azure Functions, I'd like to confirm we're using it properly.

This sample code readme says there are "authentication objects that you can use to create PlayFab instance API clients in an Azure Function". In my case I seem forced to always create a new client instance from the Azure Function, and login with it in order to call other API methods:

var playerSettings = new PlayFab.PlayFabApiSettings()
            {
                TitleId = titleID,
            };
            var clientInstanceAPI = new PlayFabClientInstanceAPI(playerSettings);
            /// LOGIN CLIENT
            var clientLoginRequest = new LoginWithCustomIDRequest
            {
                CreateAccount = false,
                TitleId = titleID,
                CustomId = customID
            };

I've tried creating the client instance API with context.AuthenticationContext instead.

var context = await FunctionContext<RegisterAccountRequest>.Create(req);

var clientInstanceAPI = new PlayFabClientInstanceAPI(context.AuthenticationContext);

When trying to call client API methods with that instance, I get an error message saying the client "Must be logged in to call this method". Upon further investigation, context.AuthenticationContext.ClientSessionTicket is null and context.AuthenticationContext.IsClientLoggedIn() is false. From the unity client, I've tried passing different arguments in ExecuteFunctionRequest.Entity.ID and .Type that I received when the unity client logged in, but that didn't seem to change the context.AuthenticationContext in the Azure Function.

Question B: are we supposed to reuse the unity client authentication context to initialize the client API in azure functions, and if we are, could you provide code samples on how to do this?

Finally, this section mentions we should not use static API for very good reasons, but I'm not 100% certain what this means in the context of azure functions.

Question C: Could you clarify if the first code sample above uses a static API?

Thanks a lot for your help.

CloudScript
10 |1200

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

Sarah Zhang avatar image
Sarah Zhang answered

>> Question A: are we supposed to use the Client API at all in Azure Functions, or is it not a recommended practice?

The second thread’s answer is more accurate. I will revise the answer to correct the possible misleading. Apologies for the confusion.

Client API has a low rate limit. It is unrecommended to call Client API on servers. If one IP address calls the Client API too frequently, it may receive this error -- "The client has exceeded the maximum API request rate and is being throttled".

>> Question B: are we supposed to reuse the unity client authentication context to initialize the client API in azure functions, and if we are, could you provide code samples on how to do this Finally, this section mentions we should not use static API for very good reasons, but I'm not 100% certain what this means in the context of azure functions.

The static API in this context means the pre-defined public static “PlayFabAPI” class. Due to each call to Azure Function will generate a new Function instance, static data in different function instances will affect each other. As this section -- Instance APIs said, "if you use static APIs, there is a very high chance that the settings you set on the APIs are overridden at run-time by different instances of the functions running in parallel, causing unexpected race-conditioned behavior".

>> Question C: Could you clarify if the first code sample above uses a static API?

The first code sample is using the instance API. The variable “clientInstanceAPI” is an instance of "PlayFabClientInstanceAPI". Generally, title developers use the static API on clients. For example, the sample code in this quick start is using static API.

If you want to use the instance Client API on C# Clients, the code could be something like this.

PlayFabAuthenticationContext playerContext= new PlayFabAuthenticationContext();
            
//Use the real client Session ticket here.
playerContext.ClientSessionTicket = "YourClientSessionTicket";
          
var request = new PlayFab.ClientModels.AddOrUpdateContactEmailRequest();

//Replace the [ContactEmail] and [YourTitleId] to the real info.
request.EmailAddress="[ContactEmail]";
var adminApiSettings = new PlayFab.PlayFabApiSettings(){TitleId = "[YourTitleId]"};

var clientAPI = new PlayFabClientInstanceAPI(adminApiSettings,playerContext);
         
var result = await clientAPI.AddOrUpdateContactEmailAsync(request);
10 |1200

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

Francois Boucher-Genesse avatar image
Francois Boucher-Genesse answered

Hi Sarah,

Understood, thanks. I'm assuming the same constraint for the client API applies to regular cloudscript, if we were to make calls to the client API through http requests.

This is a serious limitation, and I have spent several days trying to find solutions that involved servers making calls on clients' behalf. To prevent others going through the same thing, it would probably a good idea to add this type of information in the documentation.

The inability to call any client API methods from any server is quite limiting, as it forces us to chain multiple operations on the unity client. Every time we add a new step on the client, we need to handle the case when that step failed due to connection issues halfway through for example.

One way to fix that could be to add _all_ client methods to the server API. So far the two that would have been useful for me were AddUsernamePassword and AddOrUpdateContactEmail, but I'm sure there's several other calls that will be useful for developers.

Another solution could also be to whitelist certain IP addresses from PlayFab's cloudscript or Azure Functions servers on your end, and make sure calls to the client API from these addresses are not rate limited (or at least, have a similar rate limit to calls to the server API). I understand the logic of protecting your servers from bad client actors spamming client API calls. That being said I don't understand why you would need to protect from client API calls coming from your servers. It sounds like whatever restrictions are in place for server API calls could also be applied to client API calls.

Does that make sense? Do you think this is a change that could eventually happen?

Thanks!

1 comment
10 |1200

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

Sarah Zhang avatar image Sarah Zhang commented ·

This thread discussed this question, but there is no ETA of such updates. Please feel free to post your ideas to Feature Requests.

0 Likes 0 ·

Write an Answer

Hint: Notify or tag a user in this post by typing @username.

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.