Nav

APIkit Anatomy Reference

A REST or SOAP project that uses APIkit has the following parts:

  • A RAML or WSDL interface, respectively

  • A main flow

  • Backend flows

apikit-basic-anatomy-f5e73

You use the APIkit Console or a SOAP testing tool, such as SoapUI, to simulate calls to the API. Currently an APIkit Console equivalent is not available for WSDL-based APIs.

Main Flow

The main flow for a RAML-based API manages these functions:

  • Exposes the API using HTTP or Jetty.

  • Routes requests between the interface and the backend flows based on the HTTP request.

  • References exception strategies that produce HTTP-status-code responses.

apikitmainflow

APIkit Router tasks include routing messages, serializing responses, and validating payloads, headers, query-params, and uri-params. Message routing consists of routing incoming API requests to existing Mule flows and returning outgoing HTTP response codes to exceptions.

The main flow for a WSDL-based API manages the first two tasks. The logic in the main flow accepts requests, sends responses, and facilitates communication between the interface and API processes. The main flow typically consists of HTTP Listener and SOAP Router components.

apikit-basic-anatomy-c4249

Backend Flows

APIkit generates a backend flow for each resource-action pairing in a RAML. APIkit for SOAP generates a backend flow for each operation in a WSDL. For example, the RAML interface receives the GET request for sales of T-shirts. The backend flow accesses a database to look up sales data and responds to the request.

backend

APIkit and APIkit for SOAP support the following flow naming conventions, respectively:

  • RAML: <action>:<resource path configuration name>

    Example: post:/sales:application/json:api-config

  • SOAP: <operation>:<service configuration name>

    Example: OrderTshirt:/TshirtService/TshirtServicePort/api-config

The name of each backend flow corresponds to the resource-action pairing or to some operation-service mapping. For example, the XML code for the backend flow named get:/machines:apiConfig maps to the RAML resource /machines and its nested get: action.

After generating backend flows, you integrate the functional processes to take the expected input and produce output. From RAML, Studio infers information about the metadata for the input of a flow and exposes this information through DataSense. In a REST API, this input might arrive in the following forms:

  • request body

  • query parameters

  • uri parameters

  • headers

Backend flows mock responses of the REST API for simulating calls to the API. Each RAML-based backend flow has one or more message processors for API Console simulations.

The message processors in each backend flow accept requests and mock the expected action on a resource based using the RAML examples. In the get:/machines:apiConfig backend flow of the APIkit tutorial the message processors set a property on the message and set the payload of a message to display vending machine names listed in the RAML example.


         
      
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/machines:
  type: base
  is: [filterable]
  get:
    responses:
      201:
        body:
          example: |
            {
                "count" : 3,
                "machines" : [
                  {
                    "id" : "ZX4102",
                    "location" : "Starbucks, 442 Geary Street, San Francisco, CA 94102"
                  },
                  {
                    "id" : "ZX5322",
                    "location" : "Starbucks, 462 Powell Street, San Francisco, CA 94102"
                  },
                  {
                    "id" : "ZX6792",
                    "location" : "Cafe La Taza, 470 Post Street, San Francisco, CA 94102"
                  }
                ]
            }

Using DataWeave with APIkit for SOAP, you can provide XML responses to the SOAP requests in backend flows.

Interface

The interface defines the API, designating resources that contain or access data and specify actions, such as GET and PUT, on the example data.

REST Interface

This relationship between REST resources and actions is called resource-action pairing. The interface exposes internal data assets requested by the REST service.

You can write a RAML interface using the built-in Studio editor or API Designer in Anypoint Platform. Alternatively, when you create the APIkit project, you can import a RAML from a file system into Studio or reference the URL of an externally located RAML.

SOAP Interface

The interface defined by a WSDL file exposes a number of services. Each service has a set of operations. The underlying type of data is XML defined by schemas within the WSDL file or by an imported XSD file.

Error Handling

APIkit and APIkit for SOAP facilitates handling errors for RAML- and WSDL-based APIs, respectively.

RAML-Based Exception Strategy Mappings

APIkit facilitates RAML-based error handling by generating global exception strategies for the most frequently to handle the most widely-used HTTP status code responses.  

Status Code Exception Message

400

org.mule.module.apikit.exception.BadRequestException

Bad request

404

org.mule.module.apikit.exception.NotFoundException

Resource not found

405

org.mule.module.apikit.exception.MethodNotAllowedException

Method not allowed

406

org.mule.module.apikit.exception.NotAcceptableException

Not acceptable

415

org.mule.module.apikit.exception.UnsupportedMediaTypeException

Unsupported media type

The following example of the HTTP 400 response shows the construction of the exception strategies:


          
       
1
2
3
4
5
<apikit:mapping statusCode="400">
   <apikit:exception value="org.mule.module.apikit.exception.BadRequestException" />
   <set-property propertyName="Content-Type" value="application/json" doc:name="Property"/>
   <set-payload value="{ &quot;message&quot;: &quot;Bad request&quot; }" doc:name="Set Payload"/>
</apikit:mapping>

Every time a message throws an exception, APIkit checks to see if the exception matches the value of any of the apikit:exceptions defined in the project. The main flow in an APIkit project references these mappings to send HTTP error responses: an HTTP status code and corresponding plain-language message.

  • In the event of a match, APIkit returns a friendly, HTTP-status-code response using the property and payload defined in the exception mapping. For example, if an exception matches the following package name, APIkit returns a 400 error which indicates that the content of the request was bad:

    org.mule.module.apikit.exception.BadRequestException

  • In the event of a mismatch, APIkit returns a 500 Internal Server Error response. No payload is sent with this response.

You can adjust or add to the default exception strategy mappings, but if you do, you need to reference the mappings in the main flow. The following example shows the addition of an exception strategy mapping to handle a "500 Internal Server Error" response:


          
       
1
2
3
4
5
        <apikit:mapping statusCode="500">
            <apikit:exception value="java.lang.Exception" />
            <set-property propertyName="Content-Type" value="application/json"/>
            <set-payload value="#['{ &quot;message&quot;: &quot;Internal Server Error: ' + exception.message + '&quot; }']"/>
        </apikit:mapping>

If you remove all exception mappings, errors thrown in the project elicit a 500 Internal Server Error response.

SOAP Faults

APIkit for SOAP maps any faults defined by the WSDL to operations defined by the WSDL. For example, the TshirtFault is mapped to OrderTshirt, ListInventory, and TrackOrder, as described in the APIkit for SOAP tutorial. You use DataWeave to specify the message presented to the user.

How APIkit Works with RAML

The following diagram shows how a RAML-based API built by APIkit processes end user requests.

how_it_works

  1. The end user sends an HTTP request to the API.

  2. The HTTP or Jetty endpoint in the main flow receives the request and passes the message to the APIkit Router.

  3. The router checks with the interface to confirm that the resource-action pair exists in the interface.

  4. The router checks to see if a body is defined as part of the request. Generally, a request sends a body only with PUT, POST, and PATCH requests.

  5. If the request includes a body, the router determines the media type associated with the body, then matches the request content type with the one defined in the interface.

  6. If a schema is defined for the content type, the router checks that the schema on the incoming request matches the schema defined in the interface. If the schema is not valid, the application rejects the request.

  7. The router uses the information contained in the interface to determine which backend flow should receive the request. For example, based on the request and the resource-action pairing, the router determines that it should send the request to flow2.

  8. The router sends the request to flow2.

  9. Flow2 processes the request, accessing a resource and acting upon data as required.

  10. Flow2 returns a response to the router.

  11. The router pushes the response to the HTTP or Jetty endpoint.

  12. The HTTP or Jetty endpoint sends the response to the end user.

  13. From the console, you can simulate API calls by submitting requests through the Web user interface.

Routing Logic

If two sibling resources match a request, and one of them is static and the other parameterized, the static one is used.

For example:

        /users:
            /me:
                get:
            /{id}:
                put:

Results are:

  • get /users/me → 200 OK

  • put /users/me → 405 Method not allowed

  • put /users/it → 200 OK

  • get /users/it → 405 Method not allowed

If there’s more than one parameterized resource at the same level (siblings) the behavior is nondeterministic. The routing algorithm takes into account all resources even if they don’t have methods defined.

For example:

get /users → 405 Method not allowed