Obecně o API
Obecný popis ApiComPrem souborů
ApiComPrem.dll
- třída volání HTTP/HTTPS , server
- komunikace s SQL
- jednoduché SQL procedury (select)
- registrovaní CLR SQL procedur přes AutoRegisterAsm
- podpora pro VFP (čtení DBF tabulek, mem souborů, volaní procedur z VFP, ...)
- struktury tříd
- struktury tabulek
- třídy pro JSON
- šifrování hesel
- práce s certifikáty
- čtení Premier licence
- ...
ApiComPremForm.exe
- nastavení komunikace (funguje pouze s SQL verzí programu Premier)
- nastavení účetních jednotek
- testovací server pro vývojáře
- testovací formulář pro vývojáře
ApiComSql.dll
- CLR SQL procedury
AutoRegisterAsm.dll
- automatické registrovaní CLR procedur pro SQL
ApiComPremService.exe
- windows služba pro volaní ApiComPrem.dll
- podpora pro instalování a odinstalování služby
ApiComUpdate.exe
- aktualizace ApiComPrem z FTP
- podpora pro automatické spuštění na pozadí
setup.xml
- uložená konfigurace ApiComPrem
Newtonsoft.Json.dll
- Serializing a Deserializing libovolného objektu .NET s výkonným JSON Serializing Json.NET. (https://www.newtonsoft.com/json)
JSON command
Používají se dva typy příkazů:
- OUT čtení dat z API serveru
- IN zápis dat na API server
OUT příkaz (výstupní formát)
Formát HTTP_OUT
- Result
- CommandIn
- Error
- { row }
- number
- desc
- Warning
- { row }
- desc
- help
- Data
- vrátí JSON data v závislosti od příkazu
- { row }
- { row }
Příklad načítání seznamu všech příkazů s popisem použití
{ "command": {
"inComm": "INFO",
"inParam": {
"parameters": {
"prikaz": "FULL"
} } } }
inComm název příkazu
inParam parametre příkazu které se liší podle požadovaného inComm
Vrácený JSON v případě úspěšného načtení (RESULT – OK)
CommandIn vrácený poslaný příkaz
Data vrátí data podle typu příkazu
{ "Result":"OK",
"CommandIn":"INFO",
"Data":
[ {
"CommList":
[ {
"INFO":
{
"ID": 100,
"nazov": "INFO",
"pouziva_param": true,
"parametre":
[ {
"name": "table_name",
"is_required": false,
"desc": "nazov tabulky pre nacitanie struktury",
"format": "S",
"order": 0
}, {
"name": "prikaz",
"is_required": false,
"desc": "informacie o prikaze (FULL - posle vsetky)",
"format": "S",
"order": 0
} ],
"popis": "nacitanie inform.udajov",
"typ_prikazu": "OUT"
} },
Když nastane chyba ve zpracování (RESULT – ERR)
Error číslo a popis chyby. API nepošle žádné pole "Data"
Warning upozorní na nesprávně naplněné parametry, a v případe že RESULT = OK tak pole Data jsou vytvořené. Warning může mít více řádků
{ "Result":"ERR",
"CommandIn":"INFO",
"Error":
[ {
"number":502,
"desc":"Tabulka sa nenasla."
} ],
"Warning":
[
{
"desc":"chyba spracovanie SQL stru.tabulky [Exception Type: System.Data.SqlClient.SqlException, Message: Invalid object name 'SDFASFA'.]]"
} ] }
K příkazu command se může přidat příkaz „queryFields“ který určuje vrácená pole použitých tabulek povolených v inComm (i nad rámec parametrů daného příkazu):
"queryFields": [ {
"tableName": "FA_OUT",
"tableFields": "INTER,CISLO,ZKKOD,STKOD,K_SYMBOL,OBJEDNAVKA,DOD_LIST,BANKA_DOKL,BANKA_NAZ" },{
"tableName": "POLOZKY",
"tableFields": "FAKTURA,MNOZSTVI,CENA_MJ,CENA_SLV,CENA,CENA_DPH,SAZBA_DPH"
} ]
Upozornění
Když logika inComm povolí, je možnost poslat vlastní podmínky (parametry výběru) „queryCondition“ příkazu:
příklad 1:
"queryCondition": {
"tableName": "FA_OUT",
"conditions": [ {
"fieldName": "INTER",
"relationalOperator": "=",
"value": "15"
} ] }
příklad 2:
{
"command": {
"inComm": "PARTNERI",
"inParam": {
"parameters": {
"part_typ": "OD"
}
},
"queryCondition": {
"tableName": "PARTNERY",
"conditions": [
{
"fieldName": "INTER",
"relationalOperator": ">",
"value": "100"
},
{
"logicalOperator": "AND",
"fieldName": "INTER",
"relationalOperator": "<",
"value": "900"
}
]
}
}
}
IN příkaz (vstupní formát)
Formát HTTP_in
- Command
- inComm
- inParam
- Parameters
- názvy a hodnoty parametrů v závislosti od příkazu
- Parameters
- queryCondition
- { row }
- tableName
- conditions
- logicalOperator
- fieldName
- relationalOperator
- value
- queryFields
- { row }
- tableName
- tableFields
- Select
- Data
- { row }
- { row }
Používá stejnou logiku jako OUT příkaz + doplněné o pole „DATA“, které se posílají na server.
{
"command": {
"inComm": "PARTNERI_ADD",
"inParam": {
"parameters": {
"typCmd": null
}
}
},
"Data": {
"INTER": 0,
"ODBERATEL": true,
"ID": "057fe3f7-3363-49ab-88bc-8c6342ad9a33",
"CISLO": "0123456789",
"NAZEV": "Test ADD",
"ALT_NAZEV": null,
"ULICE": null,
"PSC": null,
"MESTO": null,
"STAT": null,
"ICO": null,
"DIC": null,
"KON_PRIJEM": null,
"MOBIL": null,
"E_MAIL": null
}
}
Obecné specifikace v příkazech
Vstupní formát Timestamp: rrrr-MM-dd HH:mm:ss
(HH = 24 hod. Formát, příklad: 2020-01-31 19:55:00)
Vstupní formát Datumu: rrrr-MM-dd
Chybové hlášky
Vrácené chybové hlášky mají zpravidla tento formát:
{
"Result": "ERR", /* OK/ERR */
"CommandIn": "FA_OUT", /* název příkazu */
"Error": [
{
"number": 900, /* číslo chyby */
"desc": "Exception Type: System.Data.SqlClient.SqlException, Message: Invalid column name 'inter'." /* podrobnosti k chybě */
}
]
}
Přehled chybových hlášek v result
Arithmetic overflow error converting expression to data type - došlo k přetečení hodnoty, kdy je v databázi nižší, než kterou se pokoušíte zapsat
Invalid column name 'nazev' - obvykle se zobrazí při použití queryFields, kde je nutné uvést ve výčtu i povinnou databázovou položku
Musí být vyplněn alespoň jeden z parametrů ['nazev'] nebo [queryConditions] - chybí vyplnění alespoň jedné z uvedených povinných položek
Cannot continue the execution because the session is in the kill state - může nastat v případě volání příkazů za sebou, kdy se nestihne vrátit Result z předchozího příkazu a dochází ke stornu. Maximální čas pro zpracování jednoho příkazu je nastaveno v API na 2 min. Tento maximální čas spojení by si měl současně nastavit a hlídat ve svém programu i programátor.
Chyba: 3521 - Požadovaná měna není v nastavení pro Kurzovní lístek ČNB. Pro tuzemskou fakturu menu neudávejte - je nutné mít v Premieru povolenou požadovanou měnu:
Chyba: 3514 ... - chybný parametr FORMA ve fakturách
Chyba: 3005 ... – všeobecná chyba SQL
Chyba: 3006 ... – název partnera již existuje
Chyba: 3007 ... – požadované ID [xy] pro update partnera jsem nenašel
ApiComPremForm
Pokud není nastaven správně Compatibiliy Level v administraci MS SQL, zobrazí se při Testu připojení tato chyba:
ApiComPremForm: Nastavení HTTP
Slouží k nastavení základních parametrů. Uložené nastavení přebírá HTTP server i služba ApiComPremService, která musí být po provedení změn restartována.
Pokud nejsou nainstalovány SQL procedury v SQL databázi, může ApiComPrem vyhazovat při odesílání příkazů chyby, potom je třeba provést reinstalaci procedur tl. „Reinstall SQL CLR“ a zároveň musí být správně nastavena a programem přístupná cesta „Default cesta k HTML“.
Tlačítko Přidání nového záznamu (=připojení ke konkrétní firmě v SQL verzi programu Premier)
Konfigurace se zapisuje do souboru setup.xml, který můžete v případě potřeby editovat i ručně, data nejsou zašifrována.
ApiComPremForm: HTTP server
Vizuální zobrazení komunikace HTTP serveru. Po spuštění přebírá nastavení z předchozího kroku a funguje pouze s SQL verzí programu Premier.
Při spuštění http serveru se kontroluje verze ApiComSQL.dll a automaticky se nainstalují nebo přeinstalují požadované SQL procedury na SQL serveru. Pokud k přeinstalaci SQL procedur nedojde z nějakého důvodu automaticky, lze použít v Nastavení http tlačítko Reinstal SQL CRL.
ApiComPremService
Služba HTTP server, nahrazuje spuštění vizuálního formuláře HTTP server. Instalaci provádějte jako správce. Veškerá nastavení se přebírají z Nastavení http (soubor setup.xml).
Instalace: ApiComPremService.exe" /install
Odinstalace: ApiComPremService.exe" /uninstall
Pokud si nastavíte spuštění příkazu „ApiComPremUpdate.exe -auto“ v plánovači úloh v požadovanou dobu, dojde k zastavení spuštěné služby a k automatické aktualizaci programu.
Strukturu každé tabulky naleznete vždy u konkrétního příkazu v aplikaci ApiComPrem zde:
ApiComPremUpdate.exe
Spuštěním lze program aktualizovat z FTP. Parametrem -auto se provede aktualizace na pozadí (v případě že se používa služba ApiComPremService).
Popis testovacího webové rozhraní
Naleznete jej na adrese: https://dev.premier.cz
Přihlašovací jméno: test
Heslo: test
Stránka je vytvořená pro to, aby vývojář pro přehled, vyzkoušení všech možností API a otestování zasílání dat, nemusel instalovat Premier a SQL.
Zároveň je v Helpu uveden seznam všech aktuálně podporovaných příkazů a aktuální přehled datových typů databázových položek použitých tabulek. Ten v tomto manuálu není uveden, je generován automaticky a projeví se již v okamžiku aktualizace databáze (např. rozšíření velikosti databázové položky). Zásadnější změny, pokud se nebude jednat jen o pouhé rozšíření velikosti, budou zapsány v tomto manuálu. Současně se přidání nových databázových položek nebo příkazů projeví v daném prostředí obvykle rychleji, než následně dojde k aktualizaci manuálu.
Parametry pro vnější komunikaci naleznete na úvodní stránce:
Zobrazené datové typy
char textový typ
decimal číselný typ
datetime datum + čas
timestamp
bit logický typ (true/false)
uniqueidentifier jednoznačný identifikátor
Pokud kliknete na kterékoliv stránce na tuto značku:
Zobrazí se naposledy odeslaný příkaz společně s vráceným výsledkem:
Obecně pro tvůrce
- s API musí probíhat pouze synchronní komunikace
- nelze poslat souběžné požadavky s jedné IP adresy
- každý příkaz musí projít přes open/close spojení k API
Pro tvůrce v PHP
Tipy na nástroje pro tvorbu
PHP a mySQL – naleznete také pod XAMPP (apachefriends.org)
BRACKETS (brackets.io) – open source textový editor
BOOTSRAP (getbootstrap.com) – komponenty a templates
DataTables (datatables.net) – HTML tabulky
Font Awesome (fontawesome.com) – ikonky
URL kódování
Upozornění
Například po vložení řetězce „Johnson & Johnson“, je pak nutné jej odesílat ve tvaru „Johnson %26 Johnson"
Rezervované znaky a jejich zakódování
(https://cs.wikipedia.org/wiki/URL_kódování)
Vzorový příklad komunikace s Premier API
Výběr prvních deseti záznamů z tabulky partnerů příkazem SELECT
<?php
$DEBUG = false;
$crlf = "\r\n";
$data_in = '';
// hodnoty pro testovací server – doplňte váš požadovaný server
$host = 'ssl://'.'dev.premier.cz';
// ID účetní jednotky
$iduj = '3ce17312-8dbd-49a0-94d3-2e01b65e4173';
// číslo portu
$port = 12375;
// vlastní příkaz
$data = '{"select": "select top 10 * from partnery"}';
$odpoved = sendAndRec($data);
// výpis vrácených hodnot nebo případné chyby
if ($odpoved->status == 200){
echo 'Status: '.$odpoved->content->result.'<br>' ;
echo 'CommandIn: '.$odpoved->content->commandin.'<br>';
if ($odpoved->content->error != null) {
echo 'Chyba: '.json_encode((array)$odpoved->content->error).'<br>';
}
if ($odpoved->content->warning != null ){
echo 'Varování: '.json_encode((array)$odpoved->content->warning).'<br>';
}
if ($odpoved->content->data != null ){
echo 'Data: <br>';
echo json_encode((array)$odpoved->content->data, JSON_PRETTY_PRINT);
}
} else {
echo $odpoved->status ;
}
// funkce pro odeslání požadavku
function sendAndRec($data){
global $DEBUG, $crlf,$host,$port,$iduj ;
$response = "";
// vytvorim objekt pre vysledok
$urlinfo = new stdClass;
$urlinfo->status = 0 ;
$urlinfo->errstr = '';
$errno = 0;
$errstr = '';
try{
$fp = fsockopen($host, $port, $errno, $errstr, 30);
}
catch(\Exception $ex) { //used back-slash for global namespace
array_push($errors, $errstr);
}
if ($fp) {
$msg = 'POST /api/comm HTTP/1.1' . "\r\n";
$msg .= 'Content-Type: application/json; charset=utf-8' . $crlf;
$msg .= 'Content-Length: ' . strlen($data) . $crlf;
$msg .= 'ID-UJ: '. $iduj . $crlf;
$msg .= 'Host: ' . $host . $crlf;
$msg .= 'Connection: close' . $crlf . $crlf;
$msg .= $data;
$_SESSION['data_out'] = $msg;
if (fwrite($fp, $msg) ) {
while ( !feof($fp) ) {
$response .= fgets($fp, 1024);
}
}
fclose($fp);
} else {
$response = false;
}
if ($response===false){
$urlinfo->errstr = 'chyba připojení';
return $urlinfo;
}
$lines = explode(PHP_EOL, $response);
$code = trim(substr($lines[0],9,4));
// if no status code default to 400 = Bad Request
if(empty($code) || !is_numeric($code)){
$code = 400;
}
if ($code!=200){
$urlinfo->status = $code ;
$urlinfo->errstr = 'chybný status stránky';
return $urlinfo;
}
$result = explode("\r\n\r\n", $response, 2);
$header = isset($result[0]) ? $result[0] : '';
// parse headers
$headers = array();
$lines = explode($crlf, $header);
foreach ($lines as $line) {
if (($pos = strpos($line, ':')) !== false) {
$headers[strtolower(trim(substr($line, 0, $pos)))] = trim(substr($line, $pos + 1));
}
}
// načtu info o HTTP
$urlinfo->status = $code ;
$urlinfo->header = $headers;
$urlinfo->content_type = get_content_type($result[0]);
// načtu data
$url_data = new stdClass;
$content = isset($result[1]) ? $result[1] : '';
$jsonobj = json_decode($content);
$url_data->result = isset($jsonobj->Result) ? $jsonobj->Result : '' ;
$url_data->commandin = isset($jsonobj->CommandIn) ? $jsonobj->CommandIn : '';
$url_data->error = isset($jsonobj->Error) ? $jsonobj->Error : '';
$url_data->warning = isset($jsonobj->Warning) ? $jsonobj->Warning : '';
$url_data->data = isset($jsonobj->Data) ? $jsonobj->Data : '';
// zapíšu data
$urlinfo->content = $url_data;
$urlinfo->json_out = $msg ;
$urlinfo->data_in = $response;
return $urlinfo;
}
// zkontroluje záhlaví content-type, pro správné zobrazení obrázků
function get_content_type($headers){
$content_type = "";
if(!empty($headers)){
$headerarray = explode("\r\n", $headers);
foreach($headerarray as $head){
// echo "header item = ".$head;
if(preg_match("/Content-Type: .+$/i",$head)){
$content_type = $head;
break;
}
}
}
return $content_type ;
}
?>
Pro tvůrce v C#
Tipy na nástroje pro tvorbu
Online převod JSON do C# třídy: https://app.quicktype.io/#
Vzorový příklad komunikace s Premier API
Výběr prvních deseti záznamů z přijatých objednávek (tabulka OB_IN) příkazem SELECT
using System;
using System.IO;
using System.Net;
using System.Text;
namespace TestApiConsole {
class Program {
// doplňte správnou adresu
static readonly Uri url = new Uri(@"https://dev.premier.cz:12375/api/comm");
// vlastní příkaz
static readonly string JsonSendData = "{\"select\": \"select top 10 * from ob_in\"}";
static void Main(string[] args) {
string responseFromServer = "";
if (!SendAnRec(url, JsonSendData, ref responseFromServer)) {
Console.WriteLine("Err:"+responseFromServer);
}
else {
// zpracovat odpověď (Result) z Premier API
Console.WriteLine(responseFromServer);
}
Console.ReadKey();
}
private static bool SendAnRec(Uri url, string JsonData, ref string responseFromServer) {
bool odpoved = true;
byte[] byteArray = Encoding.UTF8.GetBytes(JsonData);
responseFromServer = "";
// Nastavení TSL 1.2 pro případ, že to server vyžaduje
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11;
WebRequest request = WebRequest.Create(url);
request.Method = "POST";
// doplňte správné ID účetní jednotky
request.Headers.Add("ID-UJ: 3ce17312-8dbd-49a0-94d3-2e01b65e4173");
request.ContentType = "application/json; charset=utf-8";
request.ContentLength = byteArray.Length;
request.Timeout = 200000;
// pošlu údaje
try {
using (var dataStream = request.GetRequestStream()) {
dataStream.Write(byteArray, 0, byteArray.Length);
}
}
catch (Exception ex) {
responseFromServer = ex.Message;
return false;
}
// čekám na odpověď
try {
Encoding enc = new UTF8Encoding(true, true);
using (var response = request.GetResponse()) {
using (var stream = new StreamReader(response.GetResponseStream(), enc)) {
responseFromServer = stream.ReadToEnd();
}
}
}
// zpracování výjimek
catch (WebException ex) {
if (ex.Status == WebExceptionStatus.ProtocolError) {
using (var stream = new StreamReader(ex.Response.GetResponseStream())) {
responseFromServer = stream.ReadToEnd();
odpoved = false;
}
}
else {
if (ex.Status == WebExceptionStatus.Timeout) {
responseFromServer = "{Request timeout is expired.}";
odpoved = false;
}
else {
responseFromServer = "{" + ex.Message + "}";
odpoved = false;
}
}
}
return odpoved;
}
}
}