Skip to content

2. Structuring and Retrieving Data

Peter Olson edited this page Nov 21, 2017 · 1 revision

Models, Properties and Queries

Dragonfruit translates JSON data into models which can be accessed by API endpoints and filtered by queries. Models and queries are stored in the larger Swagger specification that Dragonfruit generates.

The structure of your data governs both the structure of the APIs and the available queries.

Property names in your sample data will become the property names in the Swagger model. Query parameters are similarly named after the property they query. So, this sample data:

    {
        "numField": 1,
        "textField": "some text"
    }

would by queryable like this

http://your.api/api/resource/?numField=1&textField=some%20text

This section is a bit long, so we've added a table of contents:

Simple Data Types

Here's a quick summary of how Dragonfruit translates JSON data to datapoints in your model and into queries:

JSON Data Type Example Model Type Model Format Queries
Number 123 Integer - [fieldName]
[fieldName]RangeStart
[fieldName]RangeEnd
Number 123.23 Float - [fieldName]
[fieldName]RangeStart
[fieldName]RangeEnd
String hello String - [fieldName]
String em@example.com String email [fieldName]
String d6b7dde2-​0f82-​4f85-​b906-​42704813ff16 String UUID [fieldName]
String 2017-05-19​T16:59:25Z String DateTime [fieldName]
[fieldName]RangeStart
[fieldName]RangeEnd
String 2017-05-19 String Date [fieldName]
[fieldName]RangeStart
[fieldName]RangeEnd

Numbers

If the number in the sample data is a whole number (no decimal place), the property will be an integer, otherwise it will be a float.
Note: Dragonfruit parses explicit strings with numbers in them (like "123") as strings.

In addition to creating a parameter to query the numerical field directly, Dragonfruit will create "range" queries to allow you to set upper and lower bounds on the results returned.

  • Type: Integer or Float
  • Query Parameters:
    • [property name]: return records in which the field exactly matches the value in the query
    • [property name]RangeStart: Return records greater than the value in the query
    • [property name]RangeEnd: Return records less than the value in the query

Example

This sample data:

    {
        "intField": 1,
        "floatField": 1.1
    }

Would return this Swagger model:

    "Sample": {
        "properties": {
            "floatField": {
                "type": "number",
                "example": 1.1
            },
            "intField": {
                "type": "integer",
                "example": 1
            }
        }
    }

With these queries:

Query Field Type Returns
intFieldRangeStart integer Items which have intFields greater than or equal to the query value
intFieldRangeEnd integer Items which have intFields less than or equal to the the query value
intField integer Items which have intFields equal to the query value
floatFieldRangeStart integer Items which have floatFields greater than or equal to the query value
floatFieldRangeEnd integer Items which have floatFields less than or equal to the the query value
floatField integer Items which have floatFields equal to the query value

Strings

Dragonfruit will translate strings in your sample data into string fields in its model. All string fields are able to be queried directly. Dragonfruit will detect strings which are UUIDs, email addresses, dates and datetime, and add the format, additional validation rules, and in some cases additional queries.

Plain Strings:

  • Type: String
  • Query Parameters:
    • [property name]: return records in which the field exactly matches the value in the query

Example

This sample data:

    {
        "stringField": "hello"
    }

Would return this Swagger model:

    "Sample": {
        "properties": {
            "stringField": {
                "type": "string",
                "example": "hello"
            }
        }
    }

With these queries:

Query Field Type Returns
stringField string Items which have stringFields equal to the query value

Emails:

  • Type: Email Address
  • Query Parameters:
    • [property name]: return records in which the field exactly matches the value in the query
  • Validation Rule: The string must match the regular expression (?i)[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,4}
  • Format Label: email

Example

This sample data:

    {
        "emailField": "me@example.com"
    }

Would return this Swagger model:

    "Sample": {
        "properties": {
            "emailField": {
                "type": "string",
                "format": "email",
                "example": "me@example.com"
            }
        }
    }

With these queries:

Query Field Type Returns
emailField string Items which have emailFields equal to the query value

UUIDs:

  • Type: UUID
  • Query Parameters:
    • [property name]: return records in which the field exactly matches the value in the query
  • Validation Rule: The string must match the regular expression [0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}
  • Format Label: uuid

Example

This sample data:

    {
        "uuidField": "fc47c0d1-713d-4ee5-8af0-a593a2b35a12"
    }

Would return this Swagger model:

    "Sample": {
        "properties": {
            "uuidField": {
                "type": "string",
                "format": "uuid",
                "example": "fc47c0d1-713d-4ee5-8af0-a593a2b35a12"
            }
        }
    }

With these queries:

Query Field Type Returns
uuidField string Items which have uuidFields equal to the query value

Date Time:

  • Type: Date Time
  • Query Parameters:
    • [property name]: Return records in which the field exactly matches the value in the query
    • [property name]RangeStart: Return records from after the value in the query
    • [property name]RangeEnd: Return records from before the value in the query
  • Validation Rule: The string must be parsable as an RFC 3339 date/time string with the format YYYY-MM-DDTHH:MM:SSZ
  • Format Label: date-time

This sample data:

    {
        "dateTimeField": "2016-01-01T00:00:00Z"
    }

Would return this Swagger model:

    "Sample": {
        "properties": {
            "dateField": {
                "type": "string",
                "format": "date-time",
                "example": "2016-01-01T00:00:00Z"
            }
        }
    }

With these queries:

Query Field Type Returns
dateTimeFieldRangeStart integer Items which have dateTimeFields greater than or equal to the query value
dateTimeFieldRangeEnd integer Items which have dateTimeFields less than or equal to the the query value
dateTimeField integer Items which have dateTimeFields equal to the query value

Date:

  • Type: Date
  • Query Parameters:
    • [property name]: Return records in which the field exactly matches the value in the query
    • [property name]RangeStart: Return records from after the value in the query
    • [property name]RangeEnd: Return records from before the value in the query
  • Validation Rule: The string must be parsable as a date string with the format YYYY-MM-DD
  • Format Label: date

Example

This sample data:

    {
        "dateField": "2016-01-01"
    }

Would return this Swagger model:

    "Sample": {
        "properties": {
            "dateField": {
                "type": "string",
                "format": "date",
                "example": "2016-01-01"
            }
        }
    }

With these queries:

Query Field Type Returns
dateFieldRangeStart integer Items which have dateFields greater than or equal to the query value
dateFieldRangeEnd integer Items which have dateFields less than or equal to the the query value
dateField integer Items which have dateFields equal to the query value

Hints

Generally, you should use real data when you create a new set of APIs with Dragonfruit. This allows Dragonfruit to introspect the types more cleanly and for non-technical people to help validate that the data is correct. You can, however, add two types of "hints" to data to add important constraints to it. These hints allow you to set bounds on numerical data and to set constrained, enumerated values for strings and numbers.

Bounded Ranges

Bounded ranges allow you to set a minimum and maximum for numerical values. Dragonfruit will reject queries which fall outside the bounds. To add a bound to a data point, add a <> to the data point in your sample data:

    {
        "boundedField": "20<>30"
    }

In this example, the boundedField would only allow inputs ranging from 20 to 30. (The <> symbol tells Dragonfruit to interpret the elements as numbers, even though the data point is a string.)

Enumerated Values

Enumerated fields are restricted to a set of specific values. To create an enumerated field, separate the elements with a pipe |:

    {
        "enumeratedField": "A|B|C|D"
    }

In this example, the enumeratedField would only allow A, B, C and D as inputs.

Arrays

Because Dragonfruit saves and returns data as JSON, items can have arrays nested within them. Depending on the contents of the array, Dragonfruit will parse and serve it in slightly different ways.

Arrays of Simple Data

You can include arrays of simple data types (strings and numbers) in your sample data. Arrays can only be acted on in whole - arrays can be added to, replaced in or removed from items, but individual elements of arrays cannot be changed.

You can query elements within an array. For example an item with an array element like this:

    {
        "arrayField": [
            "A",
            "B",
            "C"   
        ]
    }

would be returned by this query: http://your.api/api/resource/?arrayField=A

Arrays of Objects

If your sample data contains an array which contains one or more objects, Dragonfruit will create a child endpoint to access the items within the array (see Endpoints and Operations).

For example, the sample data:

    {
        "id": 1,
        "child": [
             {
                   "branchId": 1
             }
        ]
    }

Would be queryable at this endpoint: http://your.api/api/resource/1/branches

Child items are parsed just like parent items - simple data points will follow the same rules as simple data points above and arrays of objects will make sub-endpoints (sub-endpoints can go indefinitely).