Friday, February 23, 2018

Sitecore Experience Commerce - Calling services in code

Calling the Experience Commerce APIs is simple enough, especially when exporting the Postman examples into C# code. However when doing this, I did notice that the request body was not present in the Postman export. Here is an example of calling the GetToken method which returns a bearer token and is required for any subsequent API calls.
This code requires nuget packages for RestSharp and NewtonSoft.Json. Note that in my case, I am testing this using a console application.
using CommerceImport.Model;
using Newtonsoft.Json;
using RestSharp;
using System;

namespace CommerceImport
{
    class Program
    {
        private static string BearerToken;

        static void Main(string[] args)
        {
            var authenticate = Authenticate(new ConnectRequest
            {
                client_id = "postman-api",
                grant_type = "password",
                password = "b",
                scope = "openid EngineAPI postman_api",
                username = "sitecore\\admin"
            });

            if (!string.IsNullOrEmpty(authenticate.access_token))
            {
                BearerToken = authenticate.access_token;
                Console.WriteLine("Authentication Successful");
            }

            Console.ReadLine();
        }

        /// <summary>
        /// Authenticate and get a bearer token
        /// </summary>
        /// <returns>Response object</returns>
        private static ConnectResponse Authenticate(ConnectRequest requestObject)
        {
            var client = new RestClient("https://localhost:5050/connect/token");
            var request = new RestRequest(Method.POST);
            request.AddHeader("Postman-Token", "67a56502-c7c6-4030-322a-ff31cda1f3a7");
            request.AddHeader("Cache-Control", "no-cache");
            request.AddHeader("Accept", "application/json");
            request.AddHeader("Content-Type", "application/x-www-form-urlencoded");
            request.AddParameter("application/x-www-form-urlencoded", Helpers.GetQueryString(requestObject), ParameterType.RequestBody);
            IRestResponse response = client.Execute(request);

            if (response.IsSuccessful)
            {
                return JsonConvert.DeserializeObject<ConnectResponse>(response.Content);
            }
            else
            {
                Console.WriteLine("Authentication Failed");
                return new ConnectResponse();
            }
        }
    }
}
The models used:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CommerceImport.Model
{
    public class ConnectRequest
    {
        public string username { get; set; }
        public string password { get; set; }
        public string grant_type { get; set; }
        public string client_id { get; set; }
        public string scope { get; set; }
    }

    public class ConnectResponse
    {
        public string access_token { get; set; }
        public int expires_in { get; set; }
        public string token_type { get; set; }
    }
}
The helper class:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web;

namespace CommerceImport
{
    public static class Helpers
    {
        public static string GetQueryString(this object obj)
        {
            var properties = from p in obj.GetType().GetProperties()
                             where p.GetValue(obj, null) != null
                             select p.Name + "=" + HttpUtility.UrlEncode(p.GetValue(obj, null).ToString());

            return String.Join("&", properties.ToArray());
        }
    }
}
The helper class for parsing an object into querystring is required as the service expects the data in the following format:
password=b&grant_type=password&username=sitecore%5Cadmin&client_id=postman-api&scope=openid+EngineAPI+postman_api
 In this example you should successfully authenticate and get a valid bearer token. It's worth noting that this is only a simple example, and service URLs and other configurations should not be hard coded (or statically bound as is my usual excuse).

No comments:

Post a Comment