Conventions
The Jiwa REST API is based on the Data Transfer Object (DTO) pattern.
Every request accepts a DTO and almost every response is a DTO. You can, in some cases encode the request DTO as URL parameters instead, such as authentication and query requests.
The DTO classes can be obtained from the following routes:
Language | Route |
---|
C# | /types/csharp |
VB.NET | /types/vbnet |
F# | /types/fsharp |
Typescript | /types/typescript |
Java | /types/java |
Kotlin | /types/kotlin |
Swift | /types/swift |
Additionally, you can use your tool of choice to generate the DTO's from the Open API specification document located at /openapi
Content Negotiation
By default the Jiwa REST API is configured to accept json DTO's and return json DTO's. This default content type can be changed in the configuration, or the client can override the content type. If using the ServiceStack client, then there is no concern of the content type as it is automatically negotiated.
In addition to using the standard Accept
HTTP Header to retrieve the response a different format, you can also request an alternative Content-Type by appending ?format=ext to the query string, e.g:
- /Debtors/{DebtorID}?format=json
- /Debtors/{DebtorID}?format=xml
- /Debtors/{DebtorID}?format=csv
Or by appending the format .ext to the end of the route, e.g:
- /Debtors/{DebtorID}.json
- /Debtors/{DebtorID}.xml
- /Debtors/{DebtorID}.csv
Verbs
- GET operations are used to retrieve data
- POST operations are used to create data
- PATCH operations are used to update existing data
- DELETE operations are used to delete existing data
HTTP Response Codes
The response code returned will vary based on the type of operation and the result of the request.
200 OK
Will be returned for most GET operations - unless there was nothing to return, then a 204 No Content will be returned
201 Created
Will be returned for successful POST operations
204 No Content
Will be returned for successful DELETE operations
401 Not Authenticated
Will be returned if the operation requires the user to be authenticated, and they are not - or if they are authenticating and it failed due to bad credentials.
403 Forbidden
Will be returned if the user is authenticated, but do not have permission to perform the operation. See Setting Route Permissions for information on setting route permissions.
404 Not Found
Will be returned if the route is invalid, or the resource requested does not exist.
409 Conflict
Will be returned if the Jiwa business logic determines you can't perform the operation. This may occur with DELETE operations if the record cannot be deleted because it is referenced elsewhere (e.g: You can't delete a product because it is used on a sales order).
You may also get a 409 response due to a concurrency conflict. Jiwa uses optimistic concurrency control, and if the record changes because of another users or processes actions between a read and save, then this error will be returned.
Routing
Info |
---|
title | ServiceStack clients don't care about routes |
---|
|
Note that if using a ServiceStack client you do not need to be concerned with routes. The route is worked out by the client based on the type of the DTO being sent. |
The convention used for route structure is to use a plural noun of the resource followed by the primary key (usually an ID) of the resource identifier:
No Format |
---|
/SalesOrders/{InvoiceID} |
The above URL route when used as a GET operation will retrieve the sales order with the InvoiceID provided:
No Format |
---|
/SalesOrders/5244dd5e199749f4b6fe |
will retrieve sales order with InvoiceID of 5244dd5e199749f4b6fe
The same applies to PATCH and DELETE operations
For POST operations, you don't know and cannot supply the InvoiceID, as it is generated for you - so it is simply a POST to:
with the content body being the DTO.
Where there is relational data, such as sales orders have many possible related notes the URL appends to the sales order route URL the plural of the relational data (Notes) and when appropriate the primary key of the note (NoteID). A GET of the following route:
No Format |
---|
/SalesOrders/5244dd5e199749f4b6fe/Notes |
will retrieve all notes for InvoiceID 5244dd5e199749f4b6fe
A POST to the same route will add a new note:
No Format |
---|
/SalesOrders/5244dd5e199749f4b6fe/Notes |
A PATCH to the following route updates the note with NoteID 66581f3f-3efb-4cb5-878c-37f6a55405cf which is attached to sales order with InvoiceID 5244dd5e199749f4b6fe
No Format |
---|
/SalesOrders/5244dd5e199749f4b6fe/Notes/66581f3f-3efb-4cb5-878c-37f6a55405cf |
A DELETE to the same route will remove the note from the sales order
No Format |
---|
/SalesOrders/5244dd5e199749f4b6fe/Notes/66581f3f-3efb-4cb5-878c-37f6a55405cf |
An alternative method of POST or PATCH operations for relational data is not to use the explicit route, but provide the relational data in a POST or PATCH of the parent route.
An example below shows the addition of a new note, the addition of a new line, and the edit of an existing line to an existing sales order using a single PATCH operation to the sales order:
Panel |
---|
borderStyle | solid |
---|
title | Updates an existing order - adds a new line, adjusts an existing line and adds a note |
---|
|
Deck |
---|
|
Card |
---|
id | SalesOrderPATCHRequest_csharp_servicestack |
---|
label | ServiceStack Client C# |
---|
title | ServiceStack Client C# |
---|
|
Code Block |
---|
| var client = new ServiceStack.JsonServiceClient(" |
|
|
|
httphttps://api.jiwa.com.au");
var authResponse = client. |
|
|
|
Send<ServiceStack.AuthenticateResponse>Get(new ServiceStack.Authenticate() { |
|
|
|
providercredentials UserNameapi",
Passwordpassword" });
var salesOrderPATCHRequest = new JiwaFinancials.Jiwa.JiwaServiceModel.SalesOrderPATCHRequest()
{
InvoiceID = " |
|
|
|
passwordRememberMetrue
});
// Read a debtor
var serviceStackDebtorResponse = client.Get(new DebtorGetRequest { DebtorID = "0000000061000000001V" });Using the .NET WebClient
Add References to System.Runtime.Serialization and System.NetAdd the nuget package Newtonsoft.JsonAdd a new class file to the project and paste the code from the code generator of the API - you can get this by clicking on the "Generate C#" link on the metadata page:
Image RemovedCreate a cookie aware WebClient using this code - this is needed to send the session Id with every request:
Code Block |
---|
language | c# |
---|
title | Cookie Aware WebClient |
---|
|
public class CookieAwareWebClient : WebClient
{
public CookieAwareWebClient()
{
CookieContainer = new CookieContainer();
}
public CookieContainer CookieContainer { get; private set; }
protected override WebRequest GetWebRequest(Uri address)
{
var request = (HttpWebRequest)base.GetWebRequest(address);
request.CookieContainer = CookieContainer;
return request;
}
} |
Add the following code:
Code Block |
---|
language | c# |
---|
title | Using WebClient |
---|
|
using (var webclient = new CookieAwareWebClientDateTime.Now.AddDays(5)
};
salesOrderPATCHRequest.Lines.Add(new JiwaFinancials.Jiwa.JiwaServiceModel.SalesOrders.SalesOrderLine { PartNo = "1172", QuantityOrdered = 5 });
salesOrderPATCHRequest.Lines.Add(new JiwaFinancials.Jiwa.JiwaServiceModel.SalesOrders.SalesOrderLine { InvoiceLineID = "88a358a2822e4319b9b9", QuantityOrdered = 10, CustomFieldValues = new List<JiwaFinancials.Jiwa.JiwaServiceModel.CustomFields.CustomFieldValue> { new JiwaFinancials.Jiwa.JiwaServiceModel.CustomFields.CustomFieldValue { SettingID = "1ae102b94dc54dfc8a45 ", Contents = "Adjustment requested by phone" } } });
salesOrderATCHRequest.Notes.Add(new JiwaFinancials.Jiwa.JiwaServiceModel.Notes.Note { NoteText = "Customer telephoned and asked for another few hours of labour" });
var salesOrderATCHResponse = client.Patch(salesOrderPATCHRequest);
|
|
Card |
---|
id | SalesOrderPATCHRequest_csharp |
---|
label | C# |
---|
title | C# |
---|
|
Code Block |
---|
| using (var webClient = new System.Net.WebClient())
{
// Authenticate |
|
|
|
var reqparm = new System.Collections.Specialized.NameValueCollection();
reqparm
webClient.QueryString.Add("username", " |
|
|
|
api reqparm webClient.QueryString.Add("password", "password");
|
|
|
|
byte[] responsebyteswebclientUploadValueshttphttps://api.jiwa.com.au/auth |
|
|
|
", "POST", reqparm);
string responsebody = Encoding.UTF8.GetString(responsebytes);
ServiceStack.AuthenticateResponse webClientAuthResponse");
// Above returns something like this: {"SessionId":"0hKBFAnutUk8Mw6YY6DN","UserName":"api","DisplayName":"","ResponseStatus":{}}
// Deserialise response into a dynamic - below requires the Newtonsoft.Json nuget package
var authResponse = Newtonsoft.Json.JsonConvert.DeserializeObject<dynamic>(responsebody);
var sessionId = authResponse.SessionId;
webClient.Headers.Add(System.Net.HttpRequestHeader.Cookie, string.Format("ss-id={0}", sessionId));
webClient.Headers[System.Net.HttpRequestHeader.ContentType] = "application/json";
string json = Newtonsoft.Json.JsonConvert |
|
|
|
.DeserializeObject<ServiceStack.AuthenticateResponse>(responsebody);
// Read a debtor.SerializeObject(new
{
ExpectedDeliveryDate = DateTime.Now.AddDays(5),
Lines = new List<object>
{
new { PartNo = "1172", QuantityOrdered = 5 },
new { InvoiceLineID = "88a358a2822e4319b9b9", QuantityOrdered = 10, CustomFieldValues = new List<object> { new { SettingID = "1ae102b94dc54dfc8a45 ", Contents = "Adjustment requested by phone" } } }
},
Notes = new List<object>
{
new { NoteText = "Customer telephoned and asked for another few hours of labour" }
}
});
responsebody = |
|
|
|
webclientDownloadStringhttp:80debtor/0000000061000000001V");
JiwaFinancials.Jiwa.JiwaServiceModel.DebtorGetResponse webClientDebtorGetResponse = Newtonsoft.Json.JsonConvert.DeserializeObject<JiwaFinancials.Jiwa.JiwaServiceModel.DebtorGetResponse>(responsebody);
}If you prefer to not use the CookieAwareWebClient, you can set the cookie yourself: Code Block |
---|
|
language | c# |
---|
title | Using WebClient ManuallySalesOrders/babce67cdbf64f778536", "PATCH", json);
} |
|
Card |
---|
id | SalesOrderPATCHRequest_curl |
---|
label | Curl |
---|
title | Curl |
---|
|
Code Block |
---|
| curl -H 'Accept: application/json' -H 'Content-Type: application/json' -X GET https://api.jiwa.com.au/auth -d '{"username":"Admin","password":"password"}' |
Returns the following authentication response, containing the SessionId which subsequent requests will need to include in the cookie "ss-id" No Format |
---|
{"SessionId":"6w1nLX8r0sIrJHClX9Vj","UserName":"Admin","DisplayName":"","ResponseStatus":{}} |
Then, with the SessionId now known, the route can be called: Code Block |
---|
| curl -H 'Accept: application/json' -H 'Content-Type: application/json' --cookie 'ss-id=6w1nLX8r0sIrJHClX9Vj' -X PATCH https://api.jiwa.com.au/SalesOrders/babce67cdbf64f778536 -d '{"ExpectedDeliveryDate":"2017-09-20","Lines":[{"PartNo":"1172","QuantityOrdered":5},{"InvoiceLineID":"88a358a2822e4319b9b9","QuantityOrdered":10,"CustomFieldValues":[{"SettingID":"1ae102b94dc54dfc8a45 ", "Contents":"Adjustment requested by phone"}]}],"Notes":[{"NoteText":"Customer telephoned and asked for another few hours of labour"}]}' |
|
|
The response returned from the above request will be a json document representing the full sales order DTO model from the business logic - see the meta data page for the SalesOrderPATCHRequest for more detail. Note(1): The DebtorID or DebtorAccountNo can be provided. If both are provided, then the DebtorID will be used to resolve the debtor. Note(2): A sales order line can update an existing line by providing the InvoiceLineID property. New lines are appended by omitting InvoiceLineID. Note(3): A new sales order line added can provide either the InventoryID, or the PartNo. If both are provided, then the InventoryID will be used to resolve the inventory item. Note(4): When sales order lines are added, omitting the price will cause Jiwa to determine the price per normal pricing scheme logic. Note(5): The last line added in the above example sets a custom line field value for a setting with ID "1ae102b94dc54dfc8a45" Note(6): When adding notes if the NoteType is omitted, then the default note type configured in Jiwa is used. |