Skip to content

Configuration

APIchamp configuration

You are able to configure your APIchamp instance by using a yaml configuration file. Full configuration file examples can be found in the samples repository.

Filename

The configuration file must be named config.yaml and mounted under /app/config.yaml within your APIchamp docker image. How to launch APIchamp

Config Specification Versioning

The APIchamp configuration files are versioned using a numeric value to indicate the syntax version. The version information is defined at the very top of the configuration file under the field specification.

specification: "1.0"

Changelog

Version Description
1.0 Initial release of APIchamp configuration

Please note that as APIchamp evolves, future versions may introduce additional features or syntax changes. Always ensure you are using the must up to date specifiation of the configuration file in order to benefit from the latest features.

Content

The APIchamp configuration file contains the following sections.

Section Description
operations Each endpoint from your openAPI yaml configuration can be configured by creating an operation. In each operation you are able to define how your endpoint will process, map and return data.
datasources APIchamp works with many datasources such as your database´s or a 3rd party API. Each datasource specified is usable in your fulfillment´s.
settings Specify global settings like for example debug mode or your licence.

Operations

Within the operations sections you should create an operation for each endpoint. The name of the operation must match the name of the openapi specification, additionally containing the HTTP-method directly in the name. Leading to the following structure:

'HTTP-Method /ENDPOINT_PATH'
HTTP-METHOD Endpoint Name Pattern
GET /news 'GET /news'
POST /news/{id} 'POST /news/{id}'
DELETE /news/comment/{id} 'DELETE /news/comment/{id}'
operations:

  'get /news':
    fulfillments:
      ....

    mappings:
      ....

Fulfillments

A fulfillment is the mechanism used to retrieve and process data for each operation in APIchamp. Everytime an endpoint from APIchamp is called it will run all fulfillments specified for this operation synchron after each other. A potential fulfillment reading data from a database could look like that:

- name: ff2
  if: param.test != null
  type: read
  datasource: db
  queries:
    - if: param.language == 'en'
      query: Select * from news WHERE lang = :[param.news]
    - query: Select * from news
  exceptions:
    - if: ff2.size() == 0
      statuscode: 404
      message: "No news available"
  join: ff1.id == ff2.news_id
Field Description Mandatory
name Set a fulfillment name. You may use the name later to use you´re fulfillments result in conditions and field mapping. x
type Define the type of your fulfillment. READ or UPDATE x
datasource The datasource this fulfillment should use to retrieve data. Use the datasource name from the datasources section. x
if Specifies if the fulfillment should only be processed under certain conditions. More Information
queries Define your SQL queries. More Information x
exceptions You can use exceptions to return HTTP error responses. More Information
join If one operation needs data from multiple fulfillments you are able to join two results. More Information

IF

Sometimes you want to process a fulfillment only on a certain conditions. For example if the input Header parameter ' Content-Language' is available.

# Only run fulfillment if Content-Language header is not empty or null
if: param.Content-Language != ''

# Only run the fulfillment if a fulfillment already executed before called 'ff1' does at least have one item.
if: ff1.size() > 0

Queries

If your datasource is a database you are able to define one or multiple queries. The queries will be processed from top to bottom starting with the first query. As soon as one query matches it will be executed and the other´s skipped.

Field Description Mandatory
if Define a condition under which you want to use this query
query The SQL query x
queries:
  # The first query should be used if language is set. We want to filter by language in that case.  
  - if: param.Content-Language != ''
    query: SELECT id FROM news WHERE lang = :[param.Content-Language]
  # If the first queries condition was not met, use this query
  - query: SELECT id FROM news

Exceptions

In order to handle error cases you are able to specify exception for each fulfillment. Whenever a exception is triggered the processing of the fulfillments & mappings is aborted and the exception´s response is returned directly. It´s possible to define multiple exception.

Field Description Mandatory
if Define a condition under which you want to trigger this exception x
statuscode The http status code you want to return for the error case. e.g.: 404 x
message The response message you want to return x

A classical case is to return HTTP-code 404 when an item is not available in the database. Your exception for this case could look like this:

# we have a fulfillment getting a news entry from a database and want to return 404 if the news id does not exist.
name: ffnewsdetail
type: read
datasource: db
queries:
  - query: Select * from news WHERE id = :[param.id]
exceptions:
  - if: ffnewsdetail == null
    statuscode: 404
    message: "Item is not available"

Join

If you retrieve data from multiple fulfillments and need to combine two data from two datasources you are able to use the join condition.

# We have a news fulfillment and a news_image fulfillment. The second fulfillment will load all images and afterwards join the image by news_id to the correct news item.
join: news.id == ff2.news_id

In a full example:

operations:

  'get /news':
    fulfillments:
      - name: news
        type: READ
        datasource: db
        queries:
          - query: Select * from news

      - name: news_image
        type: READ
        datasource: db
        queries:
          - query: Select * from news_images
        # Join all images from this fulfillment to each entry in the news fulfillment using the id to note_id field.
        join: news.id == news_image.note_id        

Mappings

The concept of mapping is used by APIchamp to map data fields from your fulfillment´s response to the REST-API model of your openapi specification. Therefore you are able to define the mapping for each model from your REST API.

The mapping contains of two parts: The source field and the target field. The source field is the API model´s field name from your openapi specification and the target is the name from your datasource. For example if you have defined a ProductModel in your openAPI with the fields (id, name, description) but the columns in your database are called ( itemid, title, details) you should define the following mappping:

# The fulfillment is called productff and your openapi model ProductModel 
mappings:
  'ProductModel':
    id: productff.itemid
    name: productff.title
    description: productff.details

If you have a nested opeAPI model, like for example an NewsModel which includes an ImageModel, you only need to map both separately. By using the join condition APIchamp will automatically create the correct response for you.

A full example could look like this:

fulfillments:
  - name: news
    type: READ
    datasource: db
    queries:
      - query: Select * from news
  - name: news_image
    type: READ
    datasource: db
    queries:
      - query: Select * from news_images
    join: news.id == news_image.note_id

  mappings:
    # Firstly lets map the base NewsModel
    'NewsModel':
      id: news.id
      title: news.name

    # And secondly each productmodel has an ImageModel. We only need to add the ImageModel to mapper
    'ImageModel':
      imageurl: news_image.imageurl
      thumburl: news_image.thumburl

Datasources

APIchamp is designed to work with multiple datasources, including databases and 3rd party APIs. This means that you can configure your software to interact with a wide range of data sources and services.

In order to identify multiple datasources, you will need to specify a name for each one. This name will allow you to easily reference the datasource throughout your configuration files.

The following databases are supported:

  • mariadb
  • postgres

An example datasource for a mariadb database called 'demodb':

datasources:
  demodb:
    type: db
    url: jdbc:mariadb://host.docker.internal:3306/sample-products
    user: testuser
    password: samplepwd
Field Description
type Specifies the type of datasource. Use the value "db" for database. Mandatory
url The URL or endpoint for the datasource. In this case, the URL is "jdbc:mariadb://host.docker.internal:3306/sample-products". Mandatory for "db"
user The username for the datasource. Optional, user can also be part of the url
password The password for the datasource. Optional, password can also be part of the url
driver Specifies the jdbc driver to use. Optional, only for "db"

Authentication

APIchamp allows you to enhance the security of your APIs by adding authentication to the instance. At present, basic authentication (basicauth) is already available for use.

With APIchamp, you have the flexibility to define multiple authentications for your instance, allowing you to tailor access controls based on your specific needs. This ensures that your APIs are well-protected and accessible only to authorized users or applications. As the platform evolves, more authentication options will be made available to provide comprehensive security solutions for your API management needs.

All authentication providers in APICHAMP is stateless, meaning now Session Based Authentication is available.

Example:

authentications:
  basictest:
    type: basicauth
    user: default
    password: generatedpwd

Add two authentications:

authentications:
  basictest:
    type: basicauth
    user: default
    password: generatedpwd

  adminuser:
    type: basicauth
    user: admin
    password: admin

Warning

The Swagger UI Page is excluded from authentication: If you want to disable your Swagger UI Page to be public disable debug mode. All Swagger-UI specific URLs like /swagger-ui and /v3/api-docs/** are not authenticated.

Settings

The settings section contains global configuration for your APIchamp instance. Currently it features the following options:

  1. Debug-Mode
    • If debug mode is set to true, you are able to use a SWAGGER page to test your REST endpoints directly. For default the debug mode is false.
  2. Your licence
    • Define your APIchamp licence.
settings:
  debug: true
  licence: testlicence

Condition & Placeholder

Value Reference

In some places like queries and conditions you are able to reference a value dynamically by using result data or input parameters. The structure looks the following:

PATTERN.FIELDNAME

Patterns

Pattern Description
param Use the pattern param. to get a input parameter from the request. It does not matter if your input comes from a QUERY, PATH or HEADER parameter.
body Use the pattern body. to get a input parameter from the requestbody.
FULFILLMENTNAME If you need to specify a value which you retrieved from a fulfillment before you are able to use FULFILLMENTNAME. as a pattern.
# Placeholder for the Header Parameter Content-Language
param.Content-Language
  # Placeholder for a Path Parameter called id
param.Content-Language
  # Placeholder for a field userid retrieved in the requestbody json: { "userid":"1", "username":"Maria" }
body.userid
  # Placeholder to use a value called id from a fulfillments (fulfillmentname: ff1) result. 
ff1.id

Query Placeholder

The query placeholder follows a similar pattern as the condition table mentioned earlier, but it is enclosed within :[]. It is used to reference dynamic values based on data obtained from previous fulfillments or input parameters.

Here´s how it looks:

:[PATTERN.FIELDNAME]

Example usage:

# Placeholder for the Header Parameter Content-Language
SELECT * FROM news WHERE lang == :[param.Content-Language]
# Placeholder for a Path Parameter called id
SELECT * FROM news WHERE id == :[param.id]
# Placeholder for a field userid retrieved from the requestbody json: { "userid":"1", "username":"Maria" }
SELECT * FROM user WHERE id == :[body.userid]
# Placeholder to use a value called id from a fulfillments (fulfillmentname: ff1) result. 
SELECT * FROM notes_changelog WHERE notes_id == :[ff1.id]

Fulfillment Placeholder

The first entry from a previous fulfillment's result will be available in the query parameters using a pattern like :[ff1.id]. However, there's a distinction between READ and UPDATE fulfillments:

READ Fulfillment Parameters

In a READ fulfillment, the entire result of the first entry is available for use.

UPDATE Fulfillment Parameters

For UPDATE fulfillments will also return data but differs depending on the type of database being used:

  • MariaDb: If you run an INSERT command with an auto-incremental ID, you can use FF_NAME.insert_id afterward which provides the generated id.
  • PostgreSQL: PostgreSQL will deliver all columns that have been created in the UPDATE query.

Condition

Conditions should return a true, false value and are similar to a classical java if syntax. Conditions can be used in all if and join fields.

Operator Description
== Two values are equal.
!= Two values are not equal.
< Value 1 is smaller then value 2
<= Value 1 is smaller or equal to value 2
> Value 1 is bigger then value 2
> = Value 1 is bigger or equal to value 2
# Check if input parameter is english
param.Content-Language == 'en'
# Check if input parameter id is not equal to the result of ff1.id
param.Content-Language != ff1.id
# Check if the field age from result of fulfillment called ff1 is bigger then 30
ff1.age > "30"

Special Functions

Special functions can be used to calculate a new value from an existing one.

Operator Description
.size() Get the size of the value. Can only be used on arrays
# Check if the number of results on a fulfillment is bigger then 0
ff1.size() > 0