You have generated an SDK and downloaded it with one of the supported package managers.
You can locate endpoints and contracts of the SDK for imports.
Introduction
You now have the SDK at hand and you're wondering how to get started. To utilize your endpoints you can use the generated Platform. You will need to start by initializing a PlatformSession that will work as a base for your actions. Depending on the needs of your specific service, you will then use the session to initialize a dispatcher, create forwarding sessions, accept gateway requests, etc.
Our sessions come bundled with support for client-server usage and request forwarding tools for when you're working with multiple services at once. Interceptors make life easy for you defining exactly what needs to be implemented and what data you have in use. On top of that with pattern interceptors, you can implement a bunch at a time. This allows you to implement your authentication and transport mechanisms in a way that works for you.
You can use the library to test out and prototype your service interfaces ahead of building your service by using the generated sample data. When you have finished your implementation, you move from samples into proper implementations without having to change the interactions.
Initialize session
To get started you will first have to create your PlatformSession. It will allow you to easily write handlers for your endpoints and interact with them as a user of your defined functionality. Platform session is something you initialize once and keep for the lifetime of your application.
Starter for session initialisation. Create from the builder and define interceptors.
usingUniscale.Designtime;var session =awaitPlatform.Builder() // Set up interceptors for the endpoints .WithInterceptors(i => { // Implementation in later samples }) // And build the session .Build();
While you can get started with just interceptors, the session initialization allows you to define more functionality on a general level.
usingUniscale.Designtime;var session =awaitPlatform.Builder() // Set up interceptors for the endpoints .WithInterceptors(i => { // Implementation in later samples }) // Define functionality for logging throughout .OnLogMessage(message =>Console.WriteLine(message)) // Inspect requested and returned objects .InspectRequests((o, ctx) =>Console.WriteLine(o.ToString())) .InspectResponses((result, o, ctx) =>Console.WriteLine(result.Value)) // And build the session .Build();
Starter for session initialisation. Create from the builder and define interceptors.
from uniscale.core.platform.platform import Platformsession = (await Platform.builder()# Set up an interceptors for the endpoints.with_interceptors(lambdai: i# Implementation in later samples ).build())
While you can get started with just interceptors, the session initialization allows you to define more functionality on a general level.
from uniscale.core.platform.platform import Platformsession = (await Platform.builder()# Set up an interceptors for the endpoints.with_interceptors(lambdai: i# Implementation in later samples )# Define functionality for logging throughout.on_log_message(lambdamessage: print(message))# Inspect requested and returned objects.inspect_requests(lambdao, ctx: print(o)).inspect_responses(lambdaresult, o, ctx: print(result.Value))# And build the session.build())
Starter for session initialisation. Create from the builder and define interceptors.
importcom.uniscale.sdk.Platform;var session =Platform.builder()// Set up interceptors for the endpoints.withInterceptors( i -> {// Implementation in later samples })// And build the session.build().join();
While you can get started with just interceptors, the session initialization allows you to define more functionality on general level.
using Uniscale.Designtime;var session =Platform.builder()// Set up interceptors for the endpoints.withInterceptors( i -> {// Implementation in later samples })// Define functionality for logging throughout.onLogMessage(System.out::println)// Inspect requested and returned objects.inspectRequests((o, ctx) ->System.out.println(o.toString())).inspectResponses((result, o, ctx) ->System.out.println(result.getValue()))// And build the session.build().join();
Starter for session initialisation. Create from the builder and define interceptors.
import { Platform } from"@uniscale-sdk/ActorCharacter-Messagethreads"constsession=awaitPlatform.builder()// Set up interceptors for the endpoints.withInterceptors(i => {// Implementation in later samples })// And build the session.build()
While you can get started with just interceptors, the session initialization allows you to define more functionality on a general level.
import { Platform } from"@uniscale-sdk/ActorCharacter-Messagethreads"constsession=awaitPlatform.builder()// Set up interceptors for the endpoints.withInterceptors(i => {// Implementation in later samples })// Define functionality for logging throughout.onLogMessage({ logLevel:2,write: (message) =>console.log(message) })// Inspect requested and returned objects.inspectRequests((input, _ctx) => {console.log(input.toString()) }).inspectResponses((result, _input, _ctx) => {console.log(result.value) })// And build the session.build()
Defining interceptors
Define the functionality of your endpoints inside the interceptors. You can intercept each function separately and have the data typed, or intercept whole namespaces and deal with untyped data.
Your interceptor's handle function has two parameters:
The input model defined for your endpoint
FeatureContext
This context will follow any request you make and contains the information about which solution, characters, language, data tenant, and more this request was made with.
In a typical situation, you can write interceptors for each endpoint
usingUniscale.Designtime;usingUniscaleDemo.Account_1_0.Functionality.ServiceToModule.Account.Registration.ContinueToApplication;usingUniscaleDemo.Account.Account;usingUniscaleDemo.Messages;var session =awaitPlatform.Builder() // Set up interceptors for endpoints .WithInterceptors(i => {i.InterceptRequest(GetOrRegister.AllFeatureUsages,GetOrRegister.Handle((input, ctx) =>Result<UserFull>.Ok(UserFull.Samples().DefaultSample()))); // You can also intercept with patternsi.InterceptMessage(Patterns.Messages.SendMessage.AllMessageUsages,Patterns.Messages.SendMessage.Handle((input, ctx) => { // You can validate and use defined error codes on returnif (string.IsNullOrEmpty(input.Message))returnResult.BadRequest(ErrorCodes.Messages.InvalidMessageLength);Console.WriteLine(ctx.Characters.Performer?.Terminology=="Term.Admin"?$"Admin sent message: {input.Message}":$"{input.By} sent message: {input.Message}");returnResult.Ok(); })); }) .Build();
However, there are some cases where it makes more sense to have one implementation for a group of endpoints, like for example in your frontend when calling a specific backend service for all endpoints under the messages namespace. We stay out of your way and allow you to choose your preferred authentication and transport mechanisms.
usingUniscale.Core;usingUniscale.Designtime;usingUniscaleDemo.Messages;var session =awaitPlatform.Builder() .WithInterceptors(i => { // We can intercept the whole messages namespace with a patterni.InterceptPattern(Patterns.Messages.Pattern,async (input, ctx) => { // By creating a GatewayRequest JSON, the receiving end can simply // handle incoming calls with session.AcceptGatewayRequest()var json =GatewayRequest.From(input, ctx).ToJson();var responseJson =awaitSendToMessageService(json); // Convert JSON return from AcceptGatewayRequestreturnResult<object>.FromJson(responseJson); }); // You can also intercept all (remaining) calls to a general endpointi.InterceptPattern("*",async (input, ctx) => {var request =GatewayRequest.From(input, ctx);var responseJson =awaitCallGeneralServiceEndpoint(request);returnResult<object>.FromJson(responseJson); }); }) .Build();
In typical situation you can write interceptors for each endpoint
from uniscale.core.platform.platform import Platformfrom uniscale.core import Resultfrom uniscale.core.utilisation.utilisation_session_base import FeatureContextfrom uniscale.uniscaledemo.account_1_0.functionality.servicetomodule.account.registration.continuetoapplication.get_or_register import GetOrRegister
from uniscale.uniscaledemo.account.account.user_full import UserFullfrom uniscale.uniscaledemo.messages.messages.send_message_input import SendMessageInputfrom uniscale.uniscaledemo.messages.patterns import Patternsfrom uniscale.uniscaledemo.messages_1_0.error_codes import ErrorCodes# Example for under message intercept lambdadefhandle_send_message(cinput: SendMessageInput,ctx: FeatureContext) -> Result:# You can validate and use defined error codes on returnifnot cinput.message:return Result.bad_request(ErrorCodes.messages.invalid_message_length)if ctx.characters.performer.terminology =="Term.Admin":print("Admin sent message: "+ cinput.message)else:print(cinput.by +" sent message: "+ cinput.message)return Result.ok(None)session = (await Platform.builder()# Set up an interceptors for the endpoints.with_interceptors(lambdai: i.intercept_request( GetOrRegister.all_feature_usages, GetOrRegister.handle(lambdacinput, ctx: Result.ok( UserFull.samples().default_sample() ) ),# You can also intercept with patterns ).intercept_message( Patterns.messages.send_message.all_message_usages, Patterns.messages.send_message.handle(lambdacinput, ctx: handle_send_message ), ) ).build())
However there are some cases where it makes more sense to have one implementation for group of endpoints, like for example in your frontend when calling specific backend service for all endpoints under the messages namespace. We stay out of your way and allow you to choose your preferred authentication and transport mechanisms.
from uniscale.core.platform.platform import Platformfrom uniscale.core import Result, GatewayRequestfrom uniscale.uniscaledemo.messages.patterns import Patterns# Example for under message intercept lambdaasyncdefgateway_message_interceptor(cinput,ctx) -> Result:# By creating GatewayRequest JSON, receiving end can simply# handle incoming call with session.accept_gateway_request() json = GatewayRequest.from_(cinput, ctx).to_json() response_json =awaitsend_to_message_service(json)# Convert JSON return from accept_gateway_request result = Result.from_json(response_json)return result# Example for under general intercept lambdaasyncdefgateway_general_interceptor(cinput,ctx) -> Result: request = GatewayRequest.from_(cinput, ctx) response_json =awaitcall_general_service_endpoint(request) result = Result.from_json(response_json)return resultsession = (await Platform.builder().with_interceptors(# We can intercept whole messages namespace with patternlambdai: i.intercept_pattern( Patterns.messages.pattern, gateway_message_interceptor,# You can intercept all (remaining) calls to general endpoint ).intercept_pattern("*", gateway_general_interceptor) ).build())
In typical situation you can write interceptors for each endpoint
importcom.uniscale.sdk.Platform;importcom.uniscale.sdk.core.Result;importjava.util.Objects;importuniscaledemo.account.account.UserFull;importuniscaledemo.account_1_0.functionality.servicetomodule.account.registration.continuetoapplication.GetOrRegister;importuniscaledemo.messages.Patterns;importuniscaledemo.messages_1_0.ErrorCodes;var session =Platform.builder()// Set up an interceptors for features.withInterceptors( i -> {i.interceptRequest(GetOrRegister.allFeatureUsages,GetOrRegister.handle( (input, ctx) ->Result.ok(UserFull.samples().defaultSample())));// You can also intercept with patternsi.interceptMessage(Patterns.messages.sendMessage.allMessageUsages,Patterns.messages.sendMessage.handle( (input, ctx) -> {// You can validate and use defined error codes on returnif (input.getMessage() ==null||input.getMessage().isEmpty())returnResult.badRequest(ErrorCodes.messages.invalidMessageLength);System.out.println(Objects.equals(ctx.getCharacters().getPerformer().getTerminology(),"Term.Admin")?String.format("Admin sent message: %s",input.getMessage()):String.format("%s sent message: %s",input.getBy(),input.getMessage()));returnResult.ok(); })); }).build().join();
However there are some cases where it makes more sense to have one implementation for group of endpoints, like for example in your frontend when calling specific backend service for all endpoints under the messages namespace. We stay out of your way and allow you to choose your preferred authentication and transport mechanisms.
importcom.uniscale.sdk.Platform;importcom.uniscale.sdk.core.GatewayRequest;importcom.uniscale.sdk.core.Result;importjava.util.concurrent.CompletableFuture;importuniscaledemo.messages.Patterns;var session =Platform.builder().withInterceptors( i -> {// We can intercept whole messages namespace with patterni.interceptPattern(Patterns.messages.getPattern(), (input, ctx) -> {// By creating GatewayRequest JSON, receiving end can simply// handle incoming call with session.acceptGatewayRequest()var json =GatewayRequest.from(input, ctx).toJson();var responseJson =sendToMessageService(json);// Convert JSON return from acceptGatewayRequestreturnCompletableFuture.completedFuture(Result.fromJson(responseJson)); });// You can also intercept all (remaining) calls to general endpointi.interceptPattern("*", (input, ctx) -> {var request =GatewayRequest.from(input, ctx);var responseJson =callGeneralServiceEndpoint(request);returnCompletableFuture.completedFuture(Result.fromJson(responseJson)); }); }).build().join();
In typical situation you can write interceptors for each endpoint
import { Platform, Result } from"@uniscale-sdk/ActorCharacter-Messagethreads"import { Patterns as MessagePatterns } from"@uniscale-sdk/ActorCharacter-Messagethreads/sdk/UniscaleDemo/Messages"import { GetOrRegister } from "@uniscale-sdk/ActorCharacter-Messagethreads/sdk/UniscaleDemo/Account_1_0/Functionality/ServiceToModule/Account/Registration/ContinueToApplication"
import { UserFull } from"@uniscale-sdk/ActorCharacter-Messagethreads/sdk/UniscaleDemo/Account/Account/UserFull"import { ErrorCodes } from"@uniscale-sdk/ActorCharacter-Messagethreads/sdk/UniscaleDemo/Messages_1_0"constsession=awaitPlatform.builder()// Set up interceptors for the endpoints.withInterceptors((i) => {i.interceptRequest(GetOrRegister.allFeatureUsages,GetOrRegister.handle((_input, _ctx) => {returnResult.ok(UserFull.samples().defaultSample()) }), )// You can also intercept with patternsi.interceptMessage(MessagePatterns.messages.sendMessage.allMessageUsages,MessagePatterns.messages.sendMessage.handle((input, ctx) => {// You can validate and use defined error codes on returnif (!input.message) {returnResult.badRequest(ErrorCodes.messages.invalidMessageLength) }console.log(ctx.characters.performer?.terminology ==="Term.Admin"?`Admin sent a message: ${input.message}`:`${input.by} sent a message: ${input.message}`, );returnResult.ok(undefined) }), ); }).build()
However there are some cases where it makes more sense to have one implementation for group of endpoints, like for example in your frontend when calling specific backend service for all endpoints under the messages namespace. We stay out of your way and allow you to choose your preferred authentication and transport mechanisms.
import { GatewayRequest, Platform, Result } from"@uniscale-sdk/ActorCharacter-Messagethreads"import { Patterns as MessagePatterns } from"@uniscale-sdk/ActorCharacter-Messagethreads/sdk/UniscaleDemo/Messages"constsession=awaitPlatform.builder().withInterceptors((i) => {i.interceptPattern(MessagePatterns.messages.pattern,async (input, ctx) => {// By creating GatewayRequest JSON, the receiving end can simply// handle incoming call with session.acceptGatewayRequest()constjson=GatewayRequest.from(input, ctx).toJson()constresponseJson=awaitsendToMessageService(json)// The response needs to be serialized into the Result classreturnResult.fromJson(responseJson) })// You can also intercept all (remaining) calls to a general endpointi.interceptPattern("*",async (input, ctx) => {constrequest=GatewayRequest.from(input, ctx)constresponseJson=awaitcallGeneralServiceEndpoint(request)returnResult.fromJson(responseJson) }) }).build()
Handle endpoints and make requests
With the platform session, you have a setup that knows how to handle your endpoints. To utilize that and call your endpoints you need to get a DispatcherSession through which you can interact with your endpoints. Dispatchers are designed to be set up in a way where one dispatcher can handle all your solution/service's endpoints.
Making a request: PlatformSession -> DispatcherSession -> Request()
Platform sessions can also be used to receive requests. If in your endpoint you can turn your data into a GatewayRequest (or you sent the data with our helpers), you use AcceptGatewayRequest in your session and let the platform handle the request based on your interceptor implementations.
Receiving a request: PlatformSession -> AcceptGatewayRequest()
The typical case for making a request and creating a GatewayRequest from it.
usingUniscale.Core;usingUniscale.Designtime;usingUniscaleDemo.Account_1_0.Functionality.ServiceToModule.Account.Registration.ContinueToApplication;var session =awaitPlatform.Builder() // Set up your PlatformSession as in above samples // For example sending all to GeneralServiceEndpoint .WithInterceptors(i => {i.InterceptPattern("*",async (input, ctx) => {var request =GatewayRequest.From(input, ctx);var responseJson =awaitCallGeneralServiceEndpoint(request);returnResult<object>.FromJson(responseJson); }); }) .Build();// Initialize a DispatcherSession with a solution id of your choicevar dispatcher = session .AsSolution(Guid.Parse("a18b2b3e-4010-4c0f-a01f-565fda8c466e"));// Create a new user and check if we got a successful responsevar result =await dispatcher .Request(GetOrRegister.With("myAwesomeUserHandle"));if (result.Success)Console.WriteLine("User: id="+result.Value.UserIdentifier+" Handle="+result.Value.Handle);elseConsole.WriteLine("Failed with: "+result.Error.ToLongString());
And a quick sample of how one would receive such a request.
usingUniscale.Core;usingUniscaleDemo.Account_1_0.Functionality.ServiceToModule.Account.Registration.ContinueToApplication;usingUniscaleDemo.Account.Account;var session =awaitPlatform.Builder() // Implement what happens on endpoints when GatewayRequests come in. .WithInterceptors(i => i .InterceptRequest(GetOrRegister.AllFeatureUsages,GetOrRegister.Handle((input, ctx) =>Result<UserFull>.Ok(UserFull.Samples().DefaultSample())))) .Build();// In your endpoint handler (Http endpoint or similar)var result =awaitsession.AcceptGatewayRequest(requestJson);returnresult.ToJson();
The typical case for creating a request and creating a GatewayRequest from it.
from uuid import UUIDfrom uniscale.core.platform.platform import Platformfrom uniscale.core import Result, GatewayRequestfrom uniscale.uniscaledemo.account_1_0.functionality.servicetomodule.account.registration.continuetoapplication.get_or_register import GetOrRegister
# Example for under general intercept lambdaasyncdefgateway_general_interceptor(cinput,ctx) -> Result: request = GatewayRequest.from_(cinput, ctx) response_json =awaitcall_general_service_endpoint(request) result = Result.from_json(response_json)return resultsession = (await Platform.builder()# Set up your PlatformSession as in above samples# For example sending all to GeneralServiceEndpoint.with_interceptors(lambdai: i.intercept_pattern("*", gateway_general_interceptor) ).build())# Initialize a DispatcherSession with a solution id of your choicedispatcher = session.as_solution(UUID("a18b2b3e-4010-4c0f-a01f-565fda8c466e"))# Create a new user and check if we got a successful responseresult =await dispatcher.request(GetOrRegister.with_("myAwesomeUserHandle"))if result.is_success():print("User: id="+str(result.value.user_identifier)+" Handle="+ result.value.handle )else:print("Failed with: "+ result.error.to_long_string())
And a quick sample on how one would receive such request.
from uniscale.core.platform.platform import Platformfrom uniscale.core import Result, GatewayRequestfrom uniscale.uniscaledemo.account_1_0.functionality.servicetomodule.account.registration.continuetoapplication.get_or_register import GetOrRegister
from uniscale.uniscaledemo.account.account.user_full import UserFullsession = (await Platform.builder()# Implement what happens on endpoints when GatewayRequests come in..with_interceptors(lambdai: i.intercept_request( GetOrRegister.all_feature_usages, GetOrRegister.handle(lambdacinput, ctx: Result.ok( UserFull.samples().default_sample() ) ) ) ).build())# In your endpoint handler (Http endpoint or similar)result =await session.accept_gateway_request(request_json)return result.to_json()
The typical case for creating a request and creating a GatewayRequest from it.
importcom.uniscale.sdk.Platform;importcom.uniscale.sdk.core.GatewayRequest;importcom.uniscale.sdk.core.Result;importjava.util.UUID;importjava.util.concurrent.CompletableFuture;importuniscaledemo.account_1_0.functionality.servicetomodule. account.registration.continuetoapplication.GetOrRegister;var session =Platform.builder()// Set up your PlatformSession as in above samples// For example sending all to GeneralServiceEndpoint.withInterceptors( i -> {i.interceptPattern("*", (input, ctx) -> {var request =GatewayRequest.from(input, ctx);var responseJson =callGeneralServiceEndpoint(request);returnCompletableFuture.completedFuture(Result.fromJson(responseJson)); }); }).build().join();// Initialize a DispatcherSession with a solution id of your choicevar dispatcher =session.asSolution(UUID.fromString("a18b2b3e-4010-4c0f-a01f-565fda8c466e"));// Create a new user and check if we got a successful responsevar result =dispatcher.request(GetOrRegister.with("myAwesomeUserHandle")).join();if (result.isSuccess())System.out.printf("User: id= %s Handle= %s%n",result.getValue().getUserIdentifier(),result.getValue().getHandle());elseSystem.out.printf("Failed with: %s%n",result.getError().toLongString());
And a quick sample on how one would receive such request.
importcom.uniscale.sdk.Platform;importcom.uniscale.sdk.core.Result;importuniscaledemo.account.account.UserFull;importuniscaledemo.account_1_0.functionality.servicetomodule. account.registration.continuetoapplication.GetOrRegister;var session =Platform.builder()// Implement what happens on endpoints when GatewayRequests come in..withInterceptors( i ->i.interceptRequest(GetOrRegister.allFeatureUsages,GetOrRegister.handle( (input, ctx) ->Result.ok(UserFull.samples().defaultSample())))).build().join();// In your endpoint handler (Http endpoint or similar)var result =session.acceptGatewayRequest(requestJson).join();returnresult.toJson();
The typical case for creating a request and creating a GatewayRequest from it.
import { GatewayRequest, Platform, Result } from"@uniscale-sdk/ActorCharacter-Messagethreads"import { GetOrRegister } from "@uniscale-sdk/ActorCharacter-Messagethreads/sdk/UniscaleDemo/Account_1_0/Functionality/ServiceToModule/Account/Registration/ContinueToApplication"
constsession=awaitPlatform.builder().withInterceptors((i) => {// Set up your PlatformSession as in above samples// For example sending all to GeneralServiceEndpointi.interceptPattern("*",async (input, ctx) => {constrequest=GatewayRequest.from(input, ctx)constresponseJson=callGeneralServiceEndpoint(request)returnResult.fromJson(responseJson) }) }).build()// Initialize a DispatcherSession with a solution id of your choiceconstdispatcher=session.asSolution('fb344616-794e-4bd7-b81a-fb1e3361701f')// Create a new user and check if we got a successful responseconstresult=awaitdispatcher.request(GetOrRegister.with('myAwesomeUserHandle'))if (result.success) {console.log(`User: id=${result.value?.identifier}`)return}console.log(`Failed with: ${result.error?.toLongString()}`)
And a quick sample on how one would receive such request.
import { Platform, Result, BackendAction } from"@uniscale-sdk/ActorCharacter-Messagethreads"import { GetOrRegister } from "@uniscale-sdk/ActorCharacter-Messagethreads/sdk/UniscaleDemo/Account_1_0/Functionality/ServiceToModule/Account/Registration/ContinueToApplication"
import { UserFull } from"@uniscale-sdk/ActorCharacter-Messagethreads/sdk/UniscaleDemo/Account/Account/UserFull"constsession=awaitPlatform.builder()// Implement what happens on endpoints when GatewayRequests come in.withInterceptors((i) => {i.interceptRequest(GetOrRegister.allFeatureUsages,GetOrRegister.handle((_input, _ctx) => {returnResult.ok(UserFull.samples().defaultSample()) }), ) }).build()// In your endpoint handler (Http endpoint or similar)constresult=awaitsession.acceptGatewayRequest(requestJson)returnresult.toJson()
You can use the created dispatcher to make multiple requests and fetch Terminologies that you have defined into your model. You can find a more complex sample of how forwarding works in Forwarding session basics.
Conclusion
This tutorial has information on everything you need to consider when getting started with your minimalistic implementation. If you want to see all of it come together, you can find samples based on our Demo solution at: https://github.com/uniscale?q=demo-. You can test it out, and mix and match frontend and backend demos as you want.