FD1 Client Protocol
 
Library Developer Home FD1 Client Protocol Home Concepts Reading Data Writing Data Protocol Defined Servers Connect & Authenticate Proxies & Tunnels
Webhooks Programming Support Logging Minor Facts State Facts Response Format How To Guides eCommerce Sites Custom Point of Sale Customer Access Bulk Downloads Major APIs / Endpoints All Endpoints Products Sales SalesBuilder Session Sale Capture General Purpose Data Capture Devices Barcode Scanners Eftpos IoT Sensors Power Outlets Printing Scales Security Cameras Purchasing / Supply Side Purchase Orders Invoices Invoice Payments Document Capture Rare APIs / Endpoints SSL Certificates API Key Management Diagnositics Server to Client Messages Overview Resources / Objects Purchase Order Invoice Payable Invoice Payment Product Supplier Location Sale Lines Sale Delivery Details Sales Price Maps Employees Carriers Payments Product Kits Department 1 Customers

FD1 Client Protocol

The FD1 client interface protocol is intended for both internal and external web pages and applications. It has the following characteristics

  • Can use either HTTP (GET, POST, etc) or a Websocket
  • Access to some features that are not present on other APIs
  • Distributed. Can be used to talk to most Fieldpine applications
  • Only uses JSON encoding
  • Authorisation (permission to do something) is managed server side with a per function granularity

FD1 is what many would call an opinionated API, things are done a certain way, and thats that. These API decisions do not really impact developers at all, and FD1 is a very easy interface protocol to work with

Your App
Fieldpine Server #1 Client Libraries
Network via HTTP/S FD1 Client Protocol
Fieldpine Server #2
  • FD1 is not strictly a REST API, it is more a request/response API. The difference is largely semantics so doesn't really impact at all.
  • FD1 is driven by "command packets", which are JSON objects sent to the server. These packets have a rigid top level structure, and vary as specific handlers are invoked.
  • Everything is based around passing JSON packets. (Well, some rare exceptions of course)
  • FD1 protocol is the low level interface protocol, there are various abstraction libraries to simplify using FD1, or you can roll your own
  • Fieldpine itself is a distributed system, and while you mainly communicate to a specific server, you can fail over to other servers as needed.
  • While you can use Javascript fetch() directly, we highly recommend wrapping these to a single library function for all calls. eg
    ...  your code ....
    MyFetch("some FD1 resource").then(...)
    
    ... or better yet, use Fieldpine Libraries ...
    FieldpineFd1.fetch("some FD1 resource").then(...)
    
    // rather than
    fetch("/fd1/some FD1 resource").then(...)
    
    This is because FD1 may enforce new security requirements at short notice.
    Note, this only applies if you are directly calling, if you use Fieldpine interface Javascript libraries then this is handled for you.
  • FD1 using HTTP calls do not require a GET method, and GET are processed as POST with a body automatically created from the query arguments.
    You absolutely can use GET verbs, all we are saying is these are converted to POST structure on the server - and this documentation tends to show the POST format
    Few reasons
    1. Logging. Intermediate webservers may log URLs, but not the payload/body. Placing data in the body means no data easily leaks.
    2. WebSockets. Using a "packet" based protocol means packets can easily be sent using websockets without application change.
    3. Caching. HTTP GET can be cached by intermediate services, while POST is typically isn't. However, this data is often client specific and not cachable anyway

    There are some exceptions though where only GET is available or GET is not available. These are where using a POST/PUT is cumbersome. To be clear, GET is not banned, simply not the main method.
  • You may use Content-Type "text/plain" to send JSON data, although this is not encouraged. You should only be doing this for sites that are using CORS to access a retailers Fieldpine as it can eliminate the pre-flight request in some cases.

Talking to FD1

Lets jump straight to an example. Requesting RetailConfig, which is often the first call an application makes

fetch("/fd1/retailconfig").then(....)

Sending using Native JSON. Not recommended, but great for first steps as it shows exactly how it works

let request = {
    a: "retailconfig"
}

fetch("/fd1/retailconfig", {
  method: "POST",
  headers: {
    "content-type": "application/json"
  },
  body: JSON.stringify(request)
}).then(....)

Sending using Fieldpine FD1 library, which is what we recommend

<script src="...fieldpinefd1.js"></script>

FieldpineFd1.fetch("retailconfig").then(...)
Or, if you need/want to control the body
<script src="...fieldpinefd1.js"></script>

let request = {
    a: "retailconfig"
}

FieldpineFD1.send(request).then(...)

Sending using command line tools such as CURL

... To be supplied ...

FD1 URL space

  • FD1 urls are lowercase. They may include uppercase in the future, but if in doubt use lower case
  • The URL path matches the object "a" field: (this is for security. If you route all requests via a single function client side to fetch data, then this is trivial to implement
    1. The leading /fd1/ is dropped
    2. All "/" (slash) are changed to "." (dot)

    For example
    URL:
    /fd1/device/printer/do_something

    matching object
    {
      a: "device.printer.do_something"
      ...
    }
    
  • The URL final path segment is generally meaningful all by itself, even if it repeats earlier path components. For example /fd1/device/printer/listprinters This is done as many developer tools often only show the final path segment by default, so we ensure that segment is helpful. Yes, this may mean you have to type a few more characters, but we consider that tradeoff OK.

Command Packets

Command packets have a common structure. Think of this like an envelope around the actual request. All top level fields are reserved - do not use any top level fields for your own purposes. Full details of the command and response packets: Protocol Defined

{
    "a": "...target handler..."     // Required
    "q": { ... query parameters ... }
    "v": { ... handler specific values ... }    // Typically required for edit/update
    "rq" "... your RequestId ..."
}

"a" defines the address of the target handler. This is required as this is used to locate the handler to respond to this request

"v" provides the handler specific payload. The contents of this object is defined by each individual handler

"q" provides any query specific parameters to be passed to the handler. Q is typically required for reading only

"rq" is any value you wish to associate with this request. This value will be returned in the response packet

HTTP GET and "q"

Earlier we said that GETs are internally converted to POST requests, some examples should show how this works server-side. If you use GET requests, you don't need to know this, or do anything, this is simply background information

GET /fd1/some-area/some-function?id=123&name=Bob&_rq=MY_LOCAL_REFERENCE_ID
This is automatically converted to
POST /fd1/some-area/some-function
{
  "a": "some-area.some-function",
  "q": {
    "id": 123,
    "name": "Bob"
  },
  "rq": "MY_LOCAL_REFERENCE_ID"
}

To Fieldpine, either are acceptable. If you are using a WebSocket though, then you must send only the body JSON object

Response Packets

Response Object also have a fixed structure. There are no fixed fields returned on every packet, fields are only present if required.

{
    "rp": "...your RequestId (from rq)..."
    "r":  "...your Request "a" value ..."
    "data": { ... handler specific values ... }
    "error": { ... error response object ... }
    "debug": { ... extended debug info ... }
}

"rp" is copied from your request id parameter provided in "rq". RP may be repeated for multiple response packets if the original request can generate ongoing responses, such as a subscribing to a "webhook" (only for websocket interface) that can send many responses

"data" is the handler specific response

"error" is a standard error response packet. Note it is possible for a handler to respond with both "data" and "error". A hypothetical example is a request for details of products #7 and #14 in a single request. The handler might send "data" for product #7, and "error" saying product #14 does not exist

If you only receive "error" and no "data", then the error is obviously significant

If you receive "data" and "error", then the error is informational