Epicor Rest Helper (Nuget) Updated V3

V3 Release Major Update 12/17/2024

This release V3 3.0.0.0 contains breaking changes from prior versions as outlined below

The biggest change in this version other than a few bug fixes is to pivot the library to be Instance friendly instead of static. The static approach while it simplified some things it made some other things quite difficult. In order to keep backwards compatibility we still have a static wrapper which should function the same as it always has, below is a breakdown of changes and how to Upgrade easily. This request came from @HLalumiere but also several other users and I have myself encountered issues with this limitation.

  1. EpicorRest and EpicorRestV1 are now instance classes and should be instanciated as follows
EpicorRest myEpicorRestInstance= new EpicorRest();
myEpicorRestInstance.AppPoolHost = "subdomain.domain.tld"; //TLD to your Epicor Server
myEpicorRestInstance.AppPoolInstance = "EpicorDemo700"; //Epicor AppServer Insdtance
myEpicorRestInstance.UserName = "epicor"; //Epicor Username
myEpicorRestInstance.Password = "epicor"; //Epicor Password
myEpicorRestInstance.APIKey = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXX"; //API key required with V2
myEpicorRestInstance.Company = "EPIC03"; //Epicor Company (Current company) Required with V2
myEpicorRestInstance.APIVersion = EpicorRestVersion.V2; //Defaults to V2
myEpicorRestInstance.License = EpicorLicenseType.Default; // You can select the type of license you want to use for the call.

The above approach allows you to have multiple instances of EpicorRest without stepping on each other, it also allows you to maintain multiple Sessions.
2. When instantiating a Session you now need to pass in the instance you’d like to associate with the session as shown below

EpicorRest myEpicorRestInstance= new EpicorRest();
//snip....
using (EpicorRestSession ses = new EpicorRestSession(myEpicorRestInstance))
            {
                var smsSend = new
                {
                    ToPhone = "90445555555",
                    ToMsg = "Rest is so Cool!"
                };
                var rsp = EpicorRest.EfxPost("FacilityPaging", "SendSMS", smsSend);
            }

Again this allows you to have multiple instances and multiple sessions going at once.

  1. When instanciating CallContext you’ll also have to pass in the instance because the client contains information like username company etc.
EpicorRest myEpicorRestInstance= new EpicorRest();
//snip....
CallContextHeader callContext = new CallContextHeader(myEpicorRestInstance); 

The above change also hilights a new class that was added to the project called EpicorCommon which is inherited by both EpicorRestV1 and EpicorRestV2 so each of these instances is in fact an instance of EpicorCommon
4. EpicorRestStaticWrapper class was created as a static wedge instance for backwards compaitbility. To easily upgrade any project without making any changes simply replace EpicorRest.XX with EpicorRestStaticWrapper.EpicorRest.XX and it should be seemless.

.NET Framework: NuGet Gallery | EpicorRestAPI 3.0.0
.NET Core 6+ NuGet Gallery | EpicorRESTAPICore 3.0.0
.NET Standard 2.1 NuGet Gallery | EpicorRESTAPIStandard 3.0.0


@jgiese.wci and I with contributions from @A9G-Data-Droid

Updates Version 2.2.0.1

  • Fixes sync freesing issues Thanks @A9G-Data-Droid
  • Added multi mapper object|
  • Added GetEnvironment|
  • Replaced Dictionary<string,string> with MultiMap<string,string> this allows duplicate “keys” which is necessary for some epicor calls.
  • Added GetEnvironment() and GetEnvironmentAsync() calls
using EpicorRestSharedClasses;
MultiMap<string, string> parms = new MultiMap<string, string>();
parms.Add("CompanyList", "C001");
parms.Add("CompanyList", "C002");
var result = EpicorRest.BaqGet("TestQ", parms);

//Added Get Environment
var env = EpicorRest.GetEnvironment();
// or
var env = await EpicorRest.GetEnvironmentAsync();

//Returns an Environment Object defined in EpicorRestClasses
namespace EpicorRestSharedClasses
{
    
    public class Environment
    {
        public Entity[] Companies { get; set; }
    }

    public class Entity
    {
        public string Company { get; set; }
        public string[] Plants { get; set; }
    }

}

Version 2.2.0.2 Minor Bug Fix

  • Fixes repeated event registration in CreateRequest to handle invalid certificates.

EpicorRestAPI .NET 4.8
EpicorRESTAPICore .NET 6
EpicorRESTAPIStandard .NET Standard


2.2.0.1

Version Compatible with >= .NET 4.8 and .NET Core 6+
NuGet Gallery | EpicorRestAPI 2.2.0.1 (For .NET 4.8 >)
NuGet Gallery | EpicorRESTAPICore 2.2.0.1 (For .Net >=6)
NuGet Gallery | EpicorRESTAPIStandard 2.2.0.1 (For .Net Standard)


2.1.0.3

Version Compatible with >= .NET 4.8 and .NET Core 5+
NuGet Gallery | EpicorRestAPI 2.1.0.3 (For .NET 4.8 >)
NuGet Gallery | EpicorRESTAPICore 2.1.0.3 (For .Net >=5)
NuGet Gallery | EpicorRESTAPIStandard 2.1.0.3 (For .Net Standard)


Old Version Compatible with .NET 4.5 and .NET Core 3.1
NuGet Gallery | EpicorRestAPI 2.0.4 (For .NET 4.5.1 >)
NuGet Gallery | EpicorRESTAPICore 2.0.4 (For .Net Core >=3.1)
NuGet Gallery | EpicorRESTAPIStandard 2.0.4 (For .Net Standard)

Just overhauled the Epicor Rest Nuget to support Epicor REST V2 and bring up V1 to a better standard.
We have kept the old V1 Version Available we just renamed the class to EpicorRestV1 and everything works the same as before.

However we recommend you update to the new version which supports both V1 and V2 of Epicor Rest. It supports Methods, BAQs and Functions! (AT LONG LAST!)

Initial Setup:
This will be the setup required for any use of the API, the API version defaults to V2 so you don’t need to set that unless you want to change to V1.
V1 doesn’t support Functions

EpicorRest.AppPoolHost = "subdomain.domain.tld"; //TLD to your Epicor Server
EpicorRest.AppPoolInstance = "EpicorDemo700"; //Epicor AppServer Insdtance
EpicorRest.UserName = "epicor"; //Epicor Username
EpicorRest.Password = "epicor"; //Epicor Password
EpicorRest.APIKey = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXX"; //API key required with V2
EpicorRest.Company = "EPIC03"; //Epicor Company (Current company) Required with V2
EpicorRest.APIVersion = EpicorRestVersion.V2; //Defaults to V2
EpicorRest.License = EpicorLicenseType.Default; // You can select the type of license you want to use for the call.

Bypass Certificate Errors (Optional)

EpicorRest.IgnoreCertErrors = true; // If you are too cheap to get a free Certificate from Let's Encrypt this will bypass the errors. (Not Recommended)

Change Plant / Company, Language, and Culture (Optional)

EpicorRest.CallSettings = new CallSettings("CompanyID", "PlantID", "", ""); //This allows you to change the company and plant for a request. For V2 the company is passed in the URL via the .Company property (above) but the plant still needs to be changed either in the session, or in the callSetting.

Getting a Token:
We have always supported token authentication but we didn’t provide a way to generate a token within the API. This has now been corrected, after the initial setup above you can (if you chose to) generate a token if you want to.
Note that to generate a token you do need the username and password to be provided (as shown above)

if (EpicorRest.CreateBearerToken()) //Generates a Token and Assigns it to the API calls
{
        //Do Work Here!
}

Calling an Epicor BO:
We have made all the calls use dynamic objects this means that you don’t have to (up front) generate a class for the responses you are getting. Though you also have access to the original (serialized response if you chose to)

All calls made now generate what we are calling an EpicorResponseObject. This object contains the entire reponse send back from Epicor in several formats as well as any Error Information

[BoGET]
The example below makes a [GET] Request to the oData endpoint for AbcCode.

//This dictionary can be used to pass in filters to odata or any URL parameter required by the business object. It is optional
Dictionary<string, string> dic = new Dictionary<string, string>(); 
dic.Add("$top", "50");

//This will allow you pass in a CallContextHeader and more importantly receive a CallContextResponse (if you want it) it is optional
CallContextHeader callContext = new CallContextHeader(); 

var response = EpicorRest.BoGet("Erp.BO.ABCCodeSvc", "ABCCodes", dic,callContext);

//The code above returns an EpicorResponseObject (response) below are some ways to use it

// Allows you get an individual property from your response using the dynamic object
response.ResponseData.value[0].Company 

//Returns the Raw Response Body (usually JSON)
response.ResponseBody 

// Returns a boolean indicating whether there was or wasn't an error.
if(response.IsErrorResponse) 
{

      response.ResponseError; //Returns the Error Message
}

//Returns the Status Code (404) (200) etc of the Request
response.ResponseStatus 

// Contains the exception that is thrown by the server
response.BLException 

//Contains a response that was thrown specifically because of a bad client request. Something YOU did  not the server
response.BadRequest 

// Contains the exception that was thrown by RestSharp something specific like a connection issue..
response.RestCallException 

// *Note that all these 3 above are "summarized" in response.ResponseError

//Is the entire IRestSharp response object if ya want it.
response.Response 

[BoPost]
Example below makes a [POST] Request to create a new AbcCode all of the above still applies

var postData = new {
                Company = EpicorRest.Company,
                ABCCode1 = "Z",
                CountFreq = 1
            };

//Note I am passing the callcontexthere but it is OPTIONAL
var response =EpicorRest.BoPost("Erp.BO.ABCCodeSvc", "ABCCodes", postData ,callContext);

//The Response Object above has the same options as the one for [GET]

[BoPatch]
Example below makes a [PATCH] Request to update an AbcCode all of the above still applies

var patchData = new {
                Company = EpicorRest.Company,
                ABCCode1 = "Z",
                CountFreq = 1
            };

//Note I am passing the callcontexthere but it is OPTIONAL
var response =EpicorRest.BoPatch("Erp.BO.ABCCodeSvc", "ABCCodes", patchData ,callContext);

//The Response Object above has the same options as the one for [GET]

[BoDelete]
Example below deletes an ABC Code. (Using oData)

string company ="EPIC02";
string abcCode ="Z";
 response = EpicorRest.BoDelete("Erp.BO.ABCCodeSvc", $"ABCCodes('{company}', '{abcCode}')");

[BaqGet]
Example below calls a BAQ and gets the results

// Same options as standard Get apply including filtering and parameters
response = EpicorRest.BaqGet("zCustomer01");

[BaqGetDataTable]
This is a little special helper that returns a C# DataTable object with labels on columns for a given BAQ.

var  baqDt = EpicorRest.BaqGetDataTable("zCustomer01");


baqDt.Rows[0]["Customer_CustID"]

[BaqPatch]
Eample below patches a BAQ Result

var baqData = new
            {
                Customer_CustNum = 33,
                Customer_CustID = "Larry",
                SysRowID = new Guid("473e5374-fac8-47ab-abb8-fe3acd9ec77c"),
                RowMod = "U"
            };
            response = EpicorRest.BaqPatch("updatableBAQ01", baqData);

[FunctionPost]
Example below calls an Epicor function

 var smsSend = new
            {
                ToPhone = "90445555555",
                ToMsg = "Rest is so Cool!"
            };
var rsp = EpicorRest.EfxPost("FacilityPaging", "SendSMS", smsSend);

You can also wrap any of the above calls into a single Epicor Session by using the EpicorRestSession object and wrapping your call around it.

using (EpicorRestSession ses = new EpicorRestSession())
            {
                var smsSend = new
                {
                    ToPhone = "90445555555",
                    ToMsg = "Rest is so Cool!"
                };
                var rsp = EpicorRest.EfxPost("FacilityPaging", "SendSMS", smsSend);
            }

If there are any questions issues or concerns let us know!

if there is anything from the Legacy implementation that is critically missing from the overhaul let us know and we’ll take it into consideration. If you are starting out new I would highly recommend using the latest methods but set the API version to V1 if you are constrained to that for some reason.

Updates Version 2.1.0.3

Added Timeout property in MS (if specified)

EpicorRest.Timeout = 10000;
28 Likes

Remember you can also disable API key requirements in config if that’s a roadblock to using V2

You guys are legends! :+1:

2 Likes

5 Likes

All right this is live now! Testers needed :stuck_out_tongue:

1 Like

I’m fairly convinced that if this site did not exist, or the people running didn’t do awesome stuff like this, that Epicor would go under or not be anywhere near as successful as it is.

I mean, I would bail and find another line of work if it weren’t for all of you.

13 Likes

I will do so tomorrow. I’ve got some projects I started that would be easily convertable.

1 Like

Love to help, but no Epicor environments to test in at the moment. :frowning:

I am testing out the library and I had some issues.

I am trying to call the BaqGetDataTable method but it is returning null under certain error situations. If I set VS to catch all exceptions there is a JsonReader exception thrown within the BaqGetDataTable call.

The setup

            EpicorRest.AppPoolHost = "server address eg domain.com"; 
            EpicorRest.AppPoolInstance = "Test";
            EpicorRest.APIKey = "the api key GUID"; 
            EpicorRest.UserName = "user"; 
            EpicorRest.Password = "password"; 
            EpicorRest.Company = "company"; 
            EpicorRest.IgnoreCertErrors = true;

then I call the method with

var response = EpicorRest.BaqGetDataTable("RestTest");

Turns out the “RestTest” BAQ was not shared so I was not able to access it. The method returned null so there was nothing to help me there. The give away was some events created on the server.

I also noted that if I had the wrong host the method would also return null but the time with no events on the server to guide me it was harder to track down.

Brett

Let me take a look it should have shown you an error in the response

Is there a sample resource that uses this? @josecgomez

There are a ton of examples above what are you looking for?

I’m trying to make my first application to create a receipt entry. I’m only seeing snippets. I was wondering if there was a full application that shows start to finish using Epicor Rest API. I’m venturing away from Service Connect and want to get acquainted to using REST

You may find calling Epicor Functions via REST a more satisfying experience. You encapsulate the Epicor logic away from your REST client making it less brittle to changes. Performance will be better as you’ll send less traffic across the wire too. Just food for thought.

1 Like

If you are new to REST perhaps doing a generic non Epicor example might be better. There are tons of examples online. This way you can see how to use REST, before you add the Epicor layer.

1 Like
4 Likes

I’ve used REST and API’s before. Just not with Epicor.

@BlakeW did you attend Insights? I presented on how to use this.

I did not unfortunately

Crap… I can’t send you my slides then, but I imagine if you search the forum for something like “EpicorRest.AppPoolHost” or “.BaqGet(” you might find references from other peoples posts. Sorry about that.

1 Like