Copyright © 2005-2020

Copies of this document may be made for your own use and for distribution to others, provided that you do not charge any fee for such copies and further provided that each copy contains this Copyright Notice, whether distributed in print or electronically.

Overview

This guide describes the RESTful API of the OpenWMS.org WMS Inventory Service module and its usage. Some general terms and definitions are explained and declared in the first part of the document whereas in the second part the usage of the API is shown in a more use-case-driven approach.

Representation Formats

Basically JSON is used as representation format by default if not otherwise requested or mentioned below. XML format is supported for the index pages as well, but must be requested explicitly. Furthermore a vendor specific JSON format is used to represent resource representations. Therefore it is absolutely required that the Accept header denotes the demanded type. Find the type in the examples below.

Dates in JSON

Date or datetime fields are not treated specially in JSON. Within the scope of this API a date or datetime field is always expected and rendered as JSON String in ISO8601 format with timezone information and milliseconds: yyyy-MM-dd’T’HH:mm:ss.SSSTZD.

Embedded Entities

For the sake of convenience some response entities may included embedded entities or even parts of it. A reference to the actual entity is provided as HAL link as well.

Error Responses

Beside the actual representation of resources, the server may result an error response in JSON format that contains basic information about the error occurred. This information is additional to the standard HTTP status code and may help clients to identify the error cause in order to re-phrase and send the request again.

Currently there are two types of errors with their own response formats.

Server Declined Errors

This kind of errors are sent by the server runtime environment even before the request had a chance to be processed.

An example response looks like this:

{
    "timestamp": 1512400854941,
    "status": 500,
    "error": "Internal Server Error",
    "exception": "org.ameba.oauth2.InvalidTokenException",
    "message": "JWT expired at 2017-12-04T15:04:43Z. Current time: 2017-12-04T15:20:54Z, ...",
    "path": "/v1/transport-units?bk=00000000000000004711"
}

The JSON structure contains the following fields.

Property Name Description

timestamp

When the error occurred on server side

status

The http status of the error

error

A short error text

exception

Internal class name of the Java exception type

message

A more descriptive error text describing the error in detail

path

The part of the URI for the REST resource that was queried

API Declined Errors

Those errors are thrown within the REST API validation and processing logic. For example, if a client request does not match the expected format or has produced an error on server side, the API will decline the request and return a response with status client-side error (4xx).

The structure of the response is aligned to the RFC7808. An example response looks like this:

{
    "message": "LocationGroup with name [NOT_EXISTS] not found",
    "messageKey": "COMMON.LOCATION_GROUP_NOT_FOUND",
    "obj" : [ "NOT_EXISTS" ],
    "httpStatus" : "404",
    "class" : "String"
}

The JSON structure contains the following fields.

Property Name Description

message

A short error text

messageKey

An unique identifier across the API that can be used to identify and translate the error message on the client side

obj

An array of possible passed arguments to the message

httpStatus

The http status of the error

class

The arguments type

Following message keys are currently used:

Message Key Description Action

not.found

The requested resource has not been found

The resource does not exist anymore or has never existed. The resource identifier must be verified

COMMON.BARCODE_NOT_FOUND

The TransportUnit does not exist

Verify the identifying attribute passed to the API

COMMON.LOCATION_NOT_FOUND

The requested Location does not exist

Verify the identifying attribute passed to the API

COMMON.LOCATION_GROUP_NOT_FOUND

The requested LocationGroup does not exist

Verify the identifying attribute passed to the API

COMMON.TRANSPORT_UNIT_TYPE_NOT_FOUND

The requested TransportUnitType does not exist

Verify the identifying attribute passed to the API

Resources

A description of all used API resources.

Index

The initial HTTP request to retrieve information about all available resources looks like the following. The Index page is a public available resource and does not need any authentication.

GET /index HTTP/1.1
Host: localhost:8080

The Index resource is returned in the response body with the response status of 200-OK. This main Index lists all primary resource entities to follow next.

HTTP/1.1 200 OK
Content-Type: application/hal+json
Content-Length: 303

{
  "_links" : {
    "product-index" : {
      "href" : "http://localhost:8080/v1/products/index"
    },
    "load-unit-index" : {
      "href" : "http://localhost:8080/v1/load-units/index"
    },
    "packaging-unit-index" : {
      "href" : "http://localhost:8080/v1/packaging-units/index"
    }
  }
}

A client application only needs to know about the agreed link names and follow the corresponding href link to navigate to further resources.

LoadUnit

LoadUnit Index

The index with all possible operations on LoadUnits can be retrieved with an GET request:

GET /v1/load-units/index HTTP/1.1
Host: localhost:8080

The response lists all the operations with a name and the corresponding href link:

HTTP/1.1 200 OK
Content-Type: application/hal+json
Content-Length: 302

{
  "_links" : {
    "load-units-divide" : {
      "href" : "http://localhost:8080/v1/transport-unit?transportUnitBK=transportUnitBK&loadUnitType=loadUnitType&parts=4"
    },
    "load-units-load" : {
      "href" : "http://localhost:8080/v1/load-units/b65a7658-c53c-4a81-8abb-75ab67783f47"
    }
  }
}

Divide a TransportUnit into multiple LoadUnits

To retrieve a list of all existing Products a client must send a GET request to the server:

Unresolved directive in 2-load-unit.adoc - include::/home/runner/work/org.openwms.wms.inventory/org.openwms.wms.inventory/target/generated-snippets/lu-divide/http-request.adoc[]

The response contains all existing Products:

Unresolved directive in 2-load-unit.adoc - include::/home/runner/work/org.openwms.wms.inventory/org.openwms.wms.inventory/target/generated-snippets/lu-divide/http-response.adoc[]

PackagingUnit

PackagingUnit Index

The index with all possible operations on PackagingUnits can be retrieved with an GET request:

GET /v1/packaging-units/index HTTP/1.1
Host: localhost:8080

The response lists all the operations with a name and the corresponding href link:

HTTP/1.1 200 OK
Content-Type: application/hal+json
Content-Length: 475

{
  "_links" : {
    "packaging-units-create" : {
      "href" : "http://localhost:8080/v1/transport-units/transportUnitBK/load-units/luPos/packaging-units?loadUnitType=loadUnitType"
    },
    "packaging-units-findontu" : {
      "href" : "http://localhost:8080/v1/transport-units/transportUnitBK/load-units/packaging-units"
    },
    "packaging-units-findforproduct" : {
      "href" : "http://localhost:8080/v1/packaging-units?sku=sku&amount=amount&sort=sort"
    }
  }
}

Create a new PackagingUnit

A PackagingUnit can be created and directly put into a LoadUnit of a TransportUnit. Therefor a client sends a POST request with the identifying information for the LoadUnit and the required PackagingUnit data to the server:

POST /v1/transport-units/4711/load-units/3/packaging-units?loadUnitType=EURO HTTP/1.1
Content-Type: application/json
Content-Length: 262
Host: localhost:8080

{
  "product" : {
    "links" : [ ],
    "sku" : "ZS0002029",
    "units" : [ ]
  },
  "quantity" : {
    "@class" : "org.openwms.core.units.api.Piece",
    "unitType" : [ "org.openwms.core.units.api.PieceUnit", "PC" ],
    "magnitude" : 1
  },
  "links" : [ ]
}

If the server has created and attached the PackagingUnit successfully a 201-CREATED is returned with a LOCATION header to the new resource:

HTTP/1.1 201 Created
Location: http://localhost:8080/v1/transport-units/4711/load-units/3/packaging-units/e871b4bd-f107-4248-bf0d-62f33d7b3a1d/

Find all PackagingUnits on a TransportUnit

To find all PackagingUnits in all LoadUnits that are currently assigned to a particular TransportUnit a client needs to query for the secondary resources of the TransportUnitLoadUnitPackagingUnit.

GET /v1/transport-units/4711/load-units/packaging-units HTTP/1.1
Host: localhost:8080

If the server has created and attached the PackagingUnit successfully a 201-CREATED is returned with a LOCATION header to the new resource:

HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 3

[ ]

Product

Product Index

The index with all possible operations can be retrieved with an GET request:

GET /v1/products/index HTTP/1.1
Host: localhost:8080

The response lists all the operations with a name and the corresponding href link:

HTTP/1.1 200 OK
Content-Type: application/hal+json
Content-Length: 291

{
  "_links" : {
    "products-create" : {
      "href" : "http://localhost:8080/v1/products"
    },
    "products-findall" : {
      "href" : "http://localhost:8080/v1/products"
    },
    "products-findbysku" : {
      "href" : "http://localhost:8080/v1/products?sku=ZS0002029"
    }
  }
}

Find all Products

To retrieve a list of all existing Products a client must send a GET request to the server:

POST /v1/transport-unit HTTP/1.1
Host: localhost:8080
Content-Type: application/x-www-form-urlencoded

transportUnitBK=4711&loadUnitType=EURO&parts=2

The response contains all existing Products:

HTTP/1.1 201 Created

Find a Product by SKU

To find and return a Product identified by its SKU a client needs to query the resource by sku as query parameter in a GET request:

GET /v1/products?sku=ZS0002029 HTTP/1.1
Host: localhost:8080

The response contains either the Product if it exists:

HTTP/1.1 200 OK
Content-Type: application/hal+json
Content-Length: 100

{
  "pKey" : "1",
  "sku" : "ZS0002029",
  "baseUnit" : "PC",
  "stockZone" : "A",
  "units" : [ ]
}

or returns with a 404-NOT FOUND error response in case no Product with the given SKU exists:

HTTP/1.1 404 Not Found
Content-Type: application/hal+json
Content-Length: 115

{
  "message" : "Product with SKU [UNKNOWN] does not exist",
  "messageKey" : "not.found",
  "httpStatus" : "404"
}

Create one or more Products

New Products can be added to the catalog of existing Products by sending a POST request to the server with the details of each Product. Products are often created by the ERP system, indirectly through the appropriate ERP Hostconnector, and it is not unusual that this happens in a bulk operation with thousands of records at a time.

A request could look like this:

POST /v1/products HTTP/1.1
Content-Type: application/json
Content-Length: 98
Host: localhost:8080

[ {
  "links" : [ ],
  "sku" : "NEW_PRODUCT",
  "baseUnit" : "PC",
  "units" : [ "PC", "DOZ" ]
} ]

If the server has successfully created the demanded Product the response looks like:

HTTP/1.1 201 Created
Location: http://localhost:8080/v1/products/80a3129e-b3a5-4f07-a315-7f5493eb349a/

Notice that the server sends back the LOCATION header to the created Product resource in case only one new Product has been requested. If multiple Products have been created, the LOCATION header is kept empty.

If the request could not been processed because of missing or invalid request data the server responds with:

HTTP/1.1 400 Bad Request
Content-Type: application/hal+json
Content-Length: 135

{
  "message" : "Error on validation [create.products[1].baseUnit]",
  "messageKey" : "core.validation.error",
  "httpStatus" : "400"
}

Put a Product into a LoadUnit

New Products can be added to the catalog of existing Products by sending a POST request to the server with the details of each Product. Products are often created by the ERP system, indirectly through the appropriate ERP Hostconnector, and it is not unusual that this happens in a bulk operation with thousands of records at a time.

A request could look like this: Unresolved directive in 4-product.adoc - include::/home/runner/work/org.openwms.wms.inventory/org.openwms.wms.inventory/target/generated-snippets/lu-put-product/http-request.adoc[]

If the server has successfully created the demanded Product the response looks like: Unresolved directive in 4-product.adoc - include::/home/runner/work/org.openwms.wms.inventory/org.openwms.wms.inventory/target/generated-snippets/lu-put-product/http-response.adoc[]

Notice that the server sends back the LOCATION header to the created Product resource in case only one new Product has been requested. If multiple Products have been created, the LOCATION header is kept empty.

If the request could not been processed because of missing or invalid request data the server responds with: Unresolved directive in 4-product.adoc - include::/home/runner/work/org.openwms.wms.inventory/org.openwms.wms.inventory/target/generated-snippets/lu-put-product/http-response.adoc[]