API

ReFIS Flow - softvér pre elektronizáciu a schvaľovanie dokumentov

Application programming interface alebo skratkou API je rozhranie pre prácu s ReFISom z iného programu. Momentálne je podporovaná verzia API 1.0.

Overovanie

V ReFISe si opíšte „API key ID“ a tajný kľúč „SecretKeyID“. ReFIS API využíva autentifikáciu cez HMAC, ktorá vyzerá nasledovne:

  • Je nutné v každom requeste poslať HTTP hlavičku:
    • "Authorization"
    • "Date"
  • Príklad:
    • Authorization: ReFIS db000:4:Dr5v5iqDg1bsp0NJDdmCiqmXhyA=.
    • Date: Mon, 15 Jan 2018 14:20:08 GMT
  • Date obsahuje RFC2616 sformátovaný dátum
  • Hodnoty hlavičky Authorization pozostávajú z:
    • Service label ReFIS
    • Meno spoločnosti
    • API key ID
    • Hash, ktorý sa vypočíta takto:
     base64(sha1(upperstring(httpmethod) + "\n" +
                request_uripath + "\n" +
                httpheader_date_unixtime + "\n" +
                SecretKeyID))

Na otestovanie overovania môžete použiť end-point /api/1.0/authorization/. V prípade úspechu príde JSON odpoveď s textom: „You are authorized! Welcome!“

Operácie

Je možné vykonávať všetky operácie, ktoré môže robiť používateľ. „API key ID“ sa viaže ku kontu používateľa a operácie sa vykonávajú pod týmto používateľom. To znamená, že ak má používateľ napríklad prístup k operácii „Odoslať doklad“, môže API odoslať doklad.

Všetky operácie sú zdokumentované vo formáte SWAGGER na adrese: https://app.swaggerhub.com/api/ReFIS/re-fis_api/1.0

Vzorové implementácie

Java/Groovy

import grails.plugins.rest.client.RestBuilder
import grails.util.Holders
import org.apache.http.client.methods.HttpUriRequest
import org.grails.web.json.JSONObject
import org.springframework.http.HttpMethod
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory
import org.springframework.web.client.RestTemplate
import java.security.MessageDigest
import java.time.ZonedDateTime
import java.time.format.DateTimeFormatter

class ReFISUtilService {

    private sendGetRequestToReFIS(RefisEndpoint endpoint, String company, LinkedHashMap payload = null, String param = null) {
        def headerDate = getDate()
        def response = this.restBuilder.get(getServerAddress() + getEndpoint(endpoint, param)) {
            header 'Authorization', getAccessTokenSHA1(headerDate, endpoint, "GET", company, param)
            header 'Date', headerDate.formatedTime
            header 'User-Agent', "yourservice/useragent"
            accept JSONObject, 'application/json'
            contentType('application/json')
            if(payload)
                json(payload)
        }
        def details = [body: response.body, response: response]
        def json = response.json
        if(response.responseEntity.statusCode.value in [200,201,202]) {
            return [response: json]
        } else if(response.responseEntity.statusCode.value == 400) {
            return [response: json, withError: true]
        } else {
            throw new IllegalStateException("[ReFIS API] Endpoint responded with status ${response?.responseEntity?.statusCode?.value}. Payload: $payload, response: $json, details: $details.")
        }
    }

    protected String getServerAddress() {
        return "https://dev.refis.sk"    
    }

    private getEndpoint(RefisEndpoint endpoint, String param = null) {
        switch(endpoint) {
            case RefisEndpoint.AUTHORIZATION :
                return "/api/1.0/authorization"
        }
    }

    private getDate() {
        def date = ZonedDateTime.now()
        return [
                unixTime: date.toEpochSecond().toString(),
                formatedTime: date.format(DateTimeFormatter.RFC_1123_DATE_TIME) //RFC2616 - rfc1123 give same result     //  Mon, 15 Jan 2018 14:20:08 GMT
        ]
    }

    private getInputString(headerDate, RefisEndpoint endpoint, String httpMethod, String param) {
        return httpMethod.toUpperCase()+"\n"+getEndpoint(endpoint, param)+"/\n"+headerDate+"\n"+config.refis.secretKey
    }

    private getAccessTokenSHA1(headerDate, RefisEndpoint endpoint, String httpMethod, String company, String param) {
        company = company ?: "testDB"
        MessageDigest sha1 = MessageDigest.getInstance("SHA1")
        return "ReFIS "+ company + ":" + config.refis.apiKeyID + ":" + Base64.encoder.encodeToString(sha1.digest(getInputString(headerDate.unixTime, endpoint, httpMethod, param).getBytes()))
    }

    def testAuthorization(String company) {
        def result = sendGetRequestToReFIS(RefisEndpoint.AUTHORIZATION, company,null)
        return result && !result.withError
    }
}

enum RefisEndpoint {
    AUTHORIZATION
}

PHP

Kód je pre úpravu dátumu dodania v objednávke, iné end-pointy fungujú podobne.

<?php
$serviceLabel = 'ReFIS';
$AccDocumentID = 999999; // ID dokladu
$endpoint = "/api/1.0/accdocument/order/" . $AccDocumentID . '/';
$path = "https://dev.refis.sk" . $endpoint;
$method = 'put';
$date = mktime(date("H"), 0, 0);

$company = 'db004'; // nazov spolocnosti

// API kluc
$apikey = [
    'ID' => 1, // Identifikator
    'Key' => 'cg1KmVAXDPBMGa86FAWy9123' // Kluc
];

// Vypocet hash-u
$hash = base64_encode(sha1(
    strtoupper($method) . "\n" .
    $endpoint . "\n" .
    $date . "\n" .
    $apikey['Key'], TRUE));

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $path);
curl_setopt($ch, CURLOPT_HEADER, FALSE);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, strtoupper($method));
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
    'DeliveryDate' => '01.10.2018' // datum dodania
]));
curl_setopt_array($ch, [
    CURLOPT_HTTPHEADER  => [
        sprintf("authorization: %s %s:%d:%s", $serviceLabel, $company, $apikey['ID'], $hash),
        'date: ' . date('r', $date),
    ],
    CURLOPT_RETURNTRANSFER => TRUE,
    CURLOPT_VERBOSE => 1,
    CURLOPT_FOLLOWLOCATION => 1
]);

$server_output = curl_exec($ch);
print_r(json_decode($server_output));
curl_close($ch);

C#

using System.Net;
using System.Text;

public class ReFISAPI
{
    //... your code here

    public async Task Authorization()
    {
        // Execute Authorization

        CreateHeader(HttpMethod.Get, RefisApiUrlEndpoints.AuthorizationUrl);

        var response = await SendAsync(HttpMethod.Get, _refisApiProxySetting.Endpoint + RefisApiUrlEndpoints.AuthorizationUrl, null);

        // Response Authorization with StatusCode: response.StatusCode

        var json = await response.Content.ReadAsStringAsync();

        if (response.StatusCode != HttpStatusCode.OK)
        {
            _logger.LogError(json);
            throw new Exception("Authorization Error");
        }
    }
	
    private string GetAuthorizationHash(HttpMethod httpMethod, string methodUrl, string dateUnix)
    {
        var key = httpMethod.ToString().ToUpperInvariant() + "\n" + methodUrl + "\n" + dateUnix + "\n" + _refisApiProxySetting.SecretKey;
        var sha = System.Security.Cryptography.SHA1.Create();
        byte[] bytes = Encoding.UTF8.GetBytes(key);
        var hash = sha.ComputeHash(bytes);

        return Convert.ToBase64String(hash);
    }
	
    private string CreateAuthotizationHeader(HttpMethod httpMethod, string methodUrl, string dateUnix)
    {
        var hash = GetAuthorizationHash(httpMethod, methodUrl, dateUnix);
        return $ "ReFIS {_refisApiProxySetting.CompanyName}:{_refisApiProxySetting.ApiKeyId}:{hash}";
    }
	
    private void CreateHeader(HttpMethod httpMethod, string methodUrl)
    {
        _httpClient.DefaultRequestHeaders.Clear();

        var currentTime = DateTime.UtcNow;
        var dateHeader = currentTime.ToString("r");
        var dateUnix = ((DateTimeOffset) currentTime).ToUnixTimeSeconds();

        var authorization = CreateAuthotizationHeader(httpMethod, methodUrl, dateUnix.ToString());

        _httpClient.DefaultRequestHeaders.Add("Authorization", authorization);
        _httpClient.DefaultRequestHeaders.Add("Date", dateHeader);
    }
}

VB.NET

Tento kód slúži iba na vygenerovanie informácie do Header v HTTP requeste (Authorization: authorizationHeader, Date: dateHeader)

Dim authStaticVal As String = "ReFIS COMPANY_NAME_PLACEHOLDER:API_KEY_ID_PLACEHOLDER:"
Dim secretKey As String = "SECRET_KEY_ID_PLACEHOLDER"
Dim httpMethod As String = "GET"
Dim methodUrl As String = "/api/1.0/authorization/"
Dim currentUtcTime As DateTime = DateTime.UtcNow 

unixTimestamp = CLng((currentUtcTime - New DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc)).TotalSeconds).ToString() 

Dim key As String = httpMethod.ToString().ToUpperInvariant() & vbLf & methodUrl & vbLf & unixTimestamp & vbLf & secretKey
Dim sha As System.Security.Cryptography.SHA1 = System.Security.Cryptography.SHA1.Create()
Dim bytes() As Byte = System.Text.Encoding.UTF8.GetBytes(key)
Dim hash() As Byte = sha.ComputeHash(bytes) 

authorizationHeader = authStaticVal & Convert.ToBase64String(hash)
dateHeader = currentUtcTime.ToString("ddd, dd MMM yyyy HH:mm:ss 'GMT'")

Python

import time
from datetime import datetime
import hashlib
import base64
import requests

def generate_auth_header(http_method, request_uri, api_key_id, secret_key_id, company_name):
    date_header = datetime.utcnow().strftime('%a, %d %b %Y %H:%M:%S GMT')
    unix_timestamp = str(int(time.time()))
    string_to_hash = http_method.upper() + "\n" + request_uri + "\n" + unix_timestamp + "\n" + secret_key_id
    hashed = hashlib.sha1(string_to_hash.encode('UTF-8'))
    base64_encoded_hash = base64.b64encode(hashed.digest()).decode('utf-8')
    authorization_value = "ReFIS" + " " + company_name + ":" + api_key_id + ":" + base64_encoded_hash

    print("string_to_hash", string_to_hash)
    print(f"Authorization: {authorization_value} \n Date: {date_header}")
    return {"Authorization": authorization_value, "Date": date_header}

headers = generate_auth_header("GET", "/api/1.0/authorization/", "API_KEY_ID_PLACEHOLDER", "SECRET_KEY_ID_PLACEHOLDER", "COMPANY_NAME_PLACEHOLDER")

URL = "https://app1.refis.sk"
response = requests.get(URL, headers=headers)

print(f"HTTP response: {response.status_code} {response.content.decode('utf-8')}")