QuickAPI Documentation

QuickAPI offers an easy way to convert CSV files into fully operational REST APIs. This documentation explains how to create, configure, and query APIs with QuickAPI, allowing for organized and efficient access to CSV data using typical REST endpoints, with authentication, user management, automatic type inference, among other cool features.

Getting Started with QuickAPI

QuickAPI is different from typical tools that only convert CSV data to JSON. It allows users to create a fully functional REST API with minimal effort. By following a few simple steps, users can upload a CSV file, and let QuickAPI automatically detect the data types for you, and quickly generate an API that is ready for queries.

Steps to Create an API

  1. Register for a free account at QuickAPI https://quickapi.io/signup

  2. Choose an appropriate name for your project. Creating a new project on QuickAPI

  3. Upload your CSV file and let QuickAPI take care of inferring the correct datatypes for your data.

    The list of possible data types is as follows:

    • INTEGER.
      • The value is a signed integer, stored in 0, 1, 2, 3, 4, 6, or 8 bytes depending on the size of the value.
    • REAL.
      • The value is a floating point value, stored as an 8-byte IEEE floating point number.
    • TEXT.
      • The value is a text string, stored using the UTF-8 encoding.
      • Dates are also represented as a string since it is not a valid JSON datatype.
    • BOOLEAN.
      • The value is a boolean type, recognized using the keywords TRUE and FALSE.
    • NULL.
      • The value is a NULL value.
  4. Create the related endpoint that you will be able to call to query your data. Linking the file to the API endpoint

  5. You can now query your CSV file like any other API. You're ready to query

QuickAPI’s CSV endpoints are GET only, which means you cannot create, update, or delete data, you can only query your data.

Querying the API

This section explains how to use the QuickAPI Query Language (QQL) supported by all our CSV APIs, which follows the json:api specification. We can use a variety of operators to construct queries against our data.

Query Parameter Families

The way to query our data and filter it using query arguments is via a Query Parameter Family.

That means that all arguments must belong to a family to be used, that is, if we have a column in our CSV called is_active, for example, we do not do it by sending the name of the column at the first level of the argument.

GET /myEndpoint?is_active=true # 🙅‍♂️ `is_active` cannot be at the top level
GET /myEndpoint?is_active=true # 🙅‍♂️ `is_active` cannot be at the top level

Instead, if we want to filter that column, it must belong to the filter family:

GET /myEndpoint?filter[is_active]=true # 👍
GET /myEndpoint?filter[is_active]=true # 👍

Note that is_active is now inside two square brackets [].

The square brackets always enclose the column name, followed by the value we want to filter, of course, right after the filter Query Family.

We can also use dots (.) to separate the query family from the column name, and the operator:

GET /myEndpoint?filter.Year.eq=2000
GET /myEndpoint?filter.Year.eq=2000

If we do not specify an operator, by default it will be assumed that it is an equality comparison eq.

# Both give the same result
GET /myEndpoint?filter.Year=2000
GET /myEndpoint?filter.Year.eq=2000
# Both give the same result
GET /myEndpoint?filter.Year=2000
GET /myEndpoint?filter.Year.eq=2000

We can also combine many filters in a single query:

GET /users?
filter[name][eq]=Alice&
filter[age][between]=25:35&
filter[email][notlike]=@spam.com
GET /users?
filter[name][eq]=Alice&
filter[age][between]=25:35&
filter[email][notlike]=@spam.com

This returns users named "Alice" between ages 25 and 35 whose email does not contain @spam.com.

Supported Query Parameter Families

  • filter

    All of our CSV APIs support the following filtering operators:

    • eq: Equal to
    • ne: Not equal to
    • between: Between two values (inclusive)
    • notbetween: Outside a range
    • like: Case-insensitive substring match
    • notlike: Case-insensitive substring exclusion
    • startswith: Value starts with a given string
    • endswith: Value ends with a given string
    • null: Check for null
    • gt: Greater than
    • gte: Greater than or equal to
    • lt: Less than
    • lte: Less than or equal to
    • in: Match one of several values
    • notin: Exclude a list of values
  • page

    The page query family will help us to manage the pagination of the responses.

    • number.

      • Represents the current page number.
      • Starts from 1.
      • Determines which subset of the data is retrieved.
    • size.

      • Represents the number of records per page.
      • Controls how many items are returned in a single API response.
      • Default to 20.
      • Maximum of 200.

    The following formula is used to fetch the correct subset of data:

    offset = (page - 1) * pageSize
    offset = (page - 1) * pageSize
    • Page 1 → offset = (1–1) * 5 = 0 (fetch 1–5)
    • Page 2 → offset = (2–1) * 5 = 5 (fetch 6–10)
    • Page 3 → offset = (3–1) * 5 = 10 (fetch 11–15)

    Example:

    GET /myEndpoint?page[number]=1&page[size]=200
    GET /myEndpoint?page[number]=1&page[size]=200
    # Use the page query family using dots
    GET /myEndpoint?page.number=50&page.size=5
    # Use the page query family using dots
    GET /myEndpoint?page.number=50&page.size=5
  • fields

    Controls which columns of our datasource the API will return. If this argument is not specified, all columns will be returned by default.

    • include

      The value of any fields[type] parameter must be a comma-separated list that refers to the name(s) of the fields to be returned.

      # Return only the id, age, and name columns.
      GET /myUsersEndpoint?fields[include]=id,age,name
      # Return only the id, age, and name columns.
      GET /myUsersEndpoint?fields[include]=id,age,name
      {
      "data": [
      {
      "id": 1,
      "age": 44,
      "name": "Rick"
      },
      {
      "id": 2,
      "age": 50,
      "name": "Carol"
      }
      ]
      }
      {
      "data": [
      {
      "id": 1,
      "age": 44,
      "name": "Rick"
      },
      {
      "id": 2,
      "age": 50,
      "name": "Carol"
      }
      ]
      }
      # Return all columns.
      GET /myUsersEndpoint
      # Return all columns.
      GET /myUsersEndpoint

      When we send the parameter include but do not specify columns, we will get an error:

      # Bad Request. No columns to select
      GET /myUsersEndpoint?fields[include]=
      # Bad Request. No columns to select
      GET /myUsersEndpoint?fields[include]=

      If no include or exclude parameter is specified within the fields family, include will be used by default:

      # These fields will be included if we omit the [include] operation
      GET /myUsersEndpoint?fields=id,name

      # Is equivalent to:
      GET /myUsersEndpoint?fields[include]=id,name
      # These fields will be included if we omit the [include] operation
      GET /myUsersEndpoint?fields=id,name

      # Is equivalent to:
      GET /myUsersEndpoint?fields[include]=id,name
    • exclude

      Exclude these fields from the final answer.

      # Will return all fields except «password_hash»
      GET /myUsersEndpoint?fields[exclude]=password_hash
      # Will return all fields except «password_hash»
      GET /myUsersEndpoint?fields[exclude]=password_hash
      {
      "data": [
      {
      "id": 1,
      "age": 44,
      "name": "Rick",
      "description": "The Ones Who Live",
      "is_active": true
      },
      {
      "id": 2,
      "age": 50,
      "name": "Carol",
      "description": "Fierce Warrior",
      "is_active": false
      }
      ]
      }
      {
      "data": [
      {
      "id": 1,
      "age": 44,
      "name": "Rick",
      "description": "The Ones Who Live",
      "is_active": true
      },
      {
      "id": 2,
      "age": 50,
      "name": "Carol",
      "description": "Fierce Warrior",
      "is_active": false
      }
      ]
      }

      Unlike include, exclude does not have a short or abbreviated form for using it, so we have to specify the complete family and operation (e.g. fields[exclude]) we want to perform to use it:

      GET /myEndpoint?fields=city,name # <- abbreviated form of `fields[include]`

      GET /myEndpoint?fields[exclude]=id,age # <- exclude does not have an abbreviated form
      GET /myEndpoint?fields=city,name # <- abbreviated form of `fields[include]`

      GET /myEndpoint?fields[exclude]=id,age # <- exclude does not have an abbreviated form

      This also means that if one of the two full forms of fields is present (either &fields[include]= or &fields[exclude]=), the short form of include will be ignored.

      # «city» and «name» are ignored and «id» and «age» are returned:
      GET /myEndpoint?fields=city,name&fields[include]=id,age

      # The same applies to exclude:
      GET /myEndpoint?fields=id,age&fields[exclude]=name
      # This will return ALL available columns except «name»
      # «city» and «name» are ignored and «id» and «age» are returned:
      GET /myEndpoint?fields=city,name&fields[include]=id,age

      # The same applies to exclude:
      GET /myEndpoint?fields=id,age&fields[exclude]=name
      # This will return ALL available columns except «name»

      When both include and exclude properties are provided, the exclude property will take precedence. This means if a field is listed in both include and exclude, it will be excluded from the result set. For example, specifying the exact same fields in both include and exclude will result in an empty set of columns, causing an error:

      # Bad Request. No columns to select
      GET /myUsersEndpoint?fields[include]=password_hash&fields[exclude]=password_hash
      # Bad Request. No columns to select
      GET /myUsersEndpoint?fields[include]=password_hash&fields[exclude]=password_hash

      In other words, if we only include in the answer the columns a, b, and c, and we also exclude the column c, we will only end up with a and b:

      # This answer will only include "a" and "b"
      GET /myUsersEndpoint?fields[include]=a,b,c&fields[exclude]=c
      # This answer will only include "a" and "b"
      GET /myUsersEndpoint?fields[include]=a,b,c&fields[exclude]=c
  • sort

    The sort query family enables sorting data by one or more criteria.

    • The sort parameter accepts a comma-separated list of fields.
    • Prefix a field with - (a minus sign) to indicate descending order.
    • Fields without a prefix are sorted in ascending order by default.

    Example:

    # Sorts rows by `title` in ascending order (A–Z):
    GET /myEndpoint?sort=title
    # Sorts rows by `title` in ascending order (A–Z):
    GET /myEndpoint?sort=title
    # Sorts rows by `createdAt` in descending order (newest first):
    GET /myEndpoint?sort=-createdAt
    # Sorts rows by `createdAt` in descending order (newest first):
    GET /myEndpoint?sort=-createdAt

    The following query sorts the data by «country» in ascending order and by the column «name» in descending order. This means that it orders it by Country, but if some rows have the same Country, it orders them by the column «name»:

    # Sort by several columns, comma-separated
    GET /myEndpoint?sort=country,-name
    # Sort by several columns, comma-separated
    GET /myEndpoint?sort=country,-name

Meta

The top level key meta is used for:

  • Include non-standard, extra information related to your datasource.
  • Details such as pagination info, record counts, processing times, datasource schema, or any other contextual data.

Example:

{
"data": [
{
"id": "1",
"type": "articles"
}
],
"meta": {
"rows": 100,
"page": 1,
"pageSize": 10,
"elapsed": 0.077545,
"schema": [
{
"cid": 0,
"name": "id",
"type": "BIGINT",
"notnull": 0,
"dflt_value": null,
"pk": 0
},
{
"cid": 1,
"name": "type",
"type": "TEXT",
"notnull": 0,
"dflt_value": null,
"pk": 0
}
]
}
}
{
"data": [
{
"id": "1",
"type": "articles"
}
],
"meta": {
"rows": 100,
"page": 1,
"pageSize": 10,
"elapsed": 0.077545,
"schema": [
{
"cid": 0,
"name": "id",
"type": "BIGINT",
"notnull": 0,
"dflt_value": null,
"pk": 0
},
{
"cid": 1,
"name": "type",
"type": "TEXT",
"notnull": 0,
"dflt_value": null,
"pk": 0
}
]
}
}

Although we can use the top level meta key to know the schema of our datasource, like column name, type, if it accepts null or not, for example, we can also use this endpoint separately, when we are only interested in knowing the schema of our data without actually issuing a query to our datasource:

GET /api/myCSVEndpoint/schema
GET /api/myCSVEndpoint/schema

Just add /schema to the end of the URL.

Example response:

[
{
"cid": 0,
"name": "poll_id",
"type": "BIGINT",
"notnull": 0,
"dflt_value": null,
"pk": 0
},
{
"cid": 1,
"name": "pollster_id",
"type": "BIGINT",
"notnull": 0,
"dflt_value": null,
"pk": 0
},
{
"cid": 2,
"name": "pollster",
"type": "TEXT",
"notnull": 0,
"dflt_value": null,
"pk": 0
}
]
[
{
"cid": 0,
"name": "poll_id",
"type": "BIGINT",
"notnull": 0,
"dflt_value": null,
"pk": 0
},
{
"cid": 1,
"name": "pollster_id",
"type": "BIGINT",
"notnull": 0,
"dflt_value": null,
"pk": 0
},
{
"cid": 2,
"name": "pollster",
"type": "TEXT",
"notnull": 0,
"dflt_value": null,
"pk": 0
}
]