DMAP API DMAP API o Overview o End points o Quickstart ¦ Example o Schema and Table ¦ Table Aliases o Selecting Fields All fields ¦ Field Aliases ¦ Field Casts ¦ Valid Cast Types ¦ Aggregations ¦ Available aggregation methods ¦ Distinct ¦ Functions ¦ Standard Functions ¦ Sum Function ¦ Selecting from a Function ¦ Case Statements o Filtering ¦ Available Filter Operators ¦ Casting fields in filters ¦ Valid Field Cast Types ¦ Using functions in a filter o Dates o Joins ¦ Join Operator Types ¦ Functions in Joins o Subqueries o Pagination o Ordering Results ¦ Ordering Joined Columns o Grouping Results o Variables ¦ Example Query with limit, offset, and order by variables ¦ Query ¦ Variables ¦ Example Query with where clause variables ¦ Query ¦ Variables o Multiple queries o Returned data ------- o Export formats o Development Environment o SSL Certs - AWS Dev Configuration o Deployment o Run Tests Overview The DMAP API is a GraphQL-like API that will allow users to query all the tables in the Envirofacts database. The backend is written in Lambda functions using Chalice. It is not a true GraphQL implementation as it lacks the ability to use fragments, perform introspection, have a schema file, and a host of other functionality. Endpoints The production endpoint is located at https://data.epa.aov/dmapservice/querv. The internal endpoint is located at https://internal.aws-prod.aws.epa.gov/api/querv. Quickstart The basic structure of a query consists of a schema, table, and fields. All examples below are for tables and schemas which do not currently exist. They are simplified examples to clearly indicate functionality. Example query sampleQuery { users contact_list { id name address } } This query will select the fields id, name, and address from the contactjist table in the users schema. It will return all the records up to the current limit of 10,000 records. Schema and Table A schema and table must be supplied when querying data. The format is schema**table. For example, when to query the contactjist table in the users schema, the format would be users**contact_list. Table Aliases A table can be renamed in the resulting data set with the use of the alias function. query sampleQuery { users contact list (alias: contacts) { ------- id name address } } In the example above, the contact//sf data will be under the "contacts" element In the resulting data set. The original schema and table name are not referenced In the results. _The table alias Is not used when exporting results In the graphql format. Selecting Fields At least one field must be supplied (if not querying an aggregate column, see below) in a query. Fields are specified as a nested list within the table element There is no delimiter between fields. In the query: query sampleQuery { users contact_list { id name address } } The 3 fields id, name, and address will be returned in the result set. All fields If you want to return all the fields in a table, use the special field all columns . You do not need to include any other columns in the table. query sampleQuery { users contact_list { all_columns } } Field Aliases To rename a column's name for the purposes of a query, use the alias function with the value you want the column name's output to be in the result set. query sampleQuery { users contact_list { id name address (alias: "street_address") } ------- } In the example above, the address column will be returned as street_address in the JSON object array. Field Casts To cast a selected field to a different type when it is returned, add the cast attribute to the field in the query query sampleQuery { users contact_list { id name age (cast: "text") } } In this example, the age field will be returned as a text type instead of an integer. Valid Cast Types • date • decimal • float • integer • number • text Aggregations To perform an aggregation method on a table (e.g. count, min, max), the aggregate table needs to be queried. This aggregate table can have any filter and join applied to it. As an example of querying the count on the contactjist table, the table queried would be users contact_list aggregate. Then instead of listing the fields, query the count object within the aggregate. query sampleQuery { users contact_list aggregate { aggregate { count } } } Available aggregation methods • count o Purpose: Returns the total count of records. ------- o Format: count max o Purpose: Get the maximum value of a column, o Format: max column_name min o Purpose: Get the mininum value of a column, o Format: min column_name Distinct To add a distinct clause in the query, add an argument to the primary table that specifies distinct: true. query sampleQuery { users contact_list (distinct: true) { id name address (alias: "street_address") } } Functions To select a function in the results, add a parameters parameter that contains an array of the data to pass to the function. query sampleQuery { users contact_list { id name address (alias: "street_address") users name_concat (parameters: ["John", "Smith"]) } } Standard Functions To use a standard function in the query, add f n before the function name. Currently only coalesce, coalesceText and count are supported. Pass any parameters in the parameters argument. fn_add will add the values of any columns and numbers passed in as parameters. fn__coalesce will return the value in the database field supplied as the second parameter if the database field in the first parameter has a NULL value. fn_coalesceText will return the text supplied as the second parameter if the database field in the first parameter has a NULL value. fn_count will return the count of the database field supplied in the first parameter. fn_dateadd will add or subtract the interval provided to the date supplied in the first parameter. The second parameter is the date part to be added or subtracted, alid values for precision are: microseconds, milliseconds, second, minute, hour, day, week, month, quarter, year, decade, century, millennium. The third parameter is the ------- interval to be applied. fn_datetrunc will truncate a date database field supplied in the first parameter. The second parameter is the precision of the date field to be retrieved. Valid values for precision are: microseconds, milliseconds, second, minute, hour, day, week, month, quarter, year, decade, century, millennium. The third parameter is optional and is the time zone (e.g. America/New_York). fn_divide will divide the values of any columns and numbers passed in as parameters. fn__extract (fn__datepart is an alias) will return the specified part from a date database field supplied in the first parameter. The second parameter is the part of the date field to be retrieved. Valid values for the date part are: microseconds, milliseconds, second, minute, hour, day, dow (day of week), doy (day of year), week, month, quarter, year, decade, century, millennium. fn_lpad will return a padded version of the database field supplied in the first parameter. The second parameter is the length of the total number of characters to be returned. The third parameter is the character used to pad the database field. fn_ltrim will return a trimmed version of left beginning of the database field supplied in the first parameter. The trimming will occur on the leading and trailing characters. The second parameter is optional (it defaults to a blank space 1 ') and is the characters that are to be removed. fn_max is an aggregate function and will return the highest value based on the criteria supplied for the database field supplied in the first parameter. fn_min is an aggregate function and will return the lowest value based on the criteria supplied for the database field supplied in the first parameter. fn_multiply will multiply the values of any columns and numbers passed in as parameters. fn_replace rill return a modified version fo the database field supplied in the first parameter. The second parameter is the pattern to search for in the field's data. The third parameter is optional (it defaults to an empty string) and is the characters that will replace the pattern. fn_rtrim will return a trimmed version of right ending of the database field supplied in the first parameter. The trimming will occur on the leading and trailing characters. The second parameter is optional (it defaults to a blank space 1 ') and is the characters that are to be removed. fn_subtract will subtract the values of any columns and numbers passed in as parameters. fn_sum will return the sum of the values of the chosen column. It needs to be used in conjunction with a group by clause. fn_trim will return a trimmed version of the database field supplied in the first parameter. The trimming will occur on the leading and trailing characters. The second parameter is optional (it defaults to a blank space 1 ') and is the characters that are to be removed. query sampleQuery { users contact_list { id name address (alias: "street_address") fn coalesce (parameters: ["name", "address"], alias: "coalesce_resuit") } } Sum Function The fn_sum function returns the sum of the values of the chosen column. As it is an aggregation function, if there are any other columns being selected, they need to be in a groupBy clause.needs to be used in conjunction with the groupBy clause. query sampleQuery { ------- employees financials_list (groupBy: ["city", state"]) { city state fn sum (parameters: ["salary"], alias: "sum_salaries") } } This query will return the sum of salaries with it being grouped by employee cities and states. Selecting from a Function To select results from a function, add a parameters parameter to the function and query the function as if it was a table. query sampleQuery { users combine_user_orders (parameters: ["123ABC456"]) { all_columns } } Case Statements To enable if/else functionality when selecting fields, you can use a case statement in the query. query sampleQuery { users contact_list { name street_addres s city state_abbr (case: {if: {equals: "VA", then: "Virginia"}, elseif: {equals: "MD", then: "Maryland"}, elseif: {equals: "DC", then: "District of Columbia"}, else: "Other State"}) } } In the query above, when the results are returned, if the state_abbr field is "VA", then "Virginia" will be returned in the record. Likewise if the state_abbr field is "MD" or "DC", it will return "Maryland" or "District of Columbia", respectively. If the state_abbr field is any other value, "Other State" will be returned. If you need to create a case statement that that will be based on multiple fields, you can create a query that uses the "case" keyword. query sampleQuery { users contact_list { name street_addres s city ------- state_abbr (case: {if: {equals: "VA", then: "Virginia"}, elseif: {equals: "MD", then: "Maryland"}, elseif: {equals: "DC", then: "District of Columbia"}, else: "Other State"}) } } query sampleQuery { employees financials_list { city state case (if: {fn sum (parameters: ["salary"], greaterThanEqual: 1000000}, then: "Too much"}, elseif: {fn\_\_sum (parameters: ["salary"], lessThan: 1000000}, then: "Just right"}, else: "Not supplied", alias: "sum_salaries") } } Filtering Any table can have filters applied to it When creating the query, put a parentheses after the table with the filter criteria using the where operator. query sampleQuery { users\_\_contact_list (where: {state_abbr: {in: ["VA", "MD"]}}) { id name street_address city state_abbr } } In this query, only contacts whose state abbreviation is in "VA" or "MD" will be returned. Multiple filters can be applied to a table, by default, multiple filters are applied using "AND" logic. If you need to specify a filter on a separate table (for instance if you are using an "OR" clause on separate filter conditions) then qualify the column name with the schema and table in the schema table column format (each separated by two underscores). query sampleQuery { ------- users\_\_contact_list (where: {state_abbr: {in: ["PA", "IL"]}, city: {equals: "Springfield"}}) { id name street_address city state_abbr } } Here all users who reside in the city of Springfield and who live in Pennsylvania or Illinois will be returned. Multiple filter conditions can also be applied with "OR" logic. query sampleQuery { users\_\_contact_list (where: {state_abbr: {equals: "CT"}, or: {city: {equals: "New York"}}}) { id name street_address city state_abbr } } This query will return all users who live in Connecticut or their city of residence is New York. Filter conditions can also be nested (the equivalent of parentheses in order of operators). query sampleQuery { users\_\_contact_list (where: {state_abbr: {equals: "CT"}, or: {city: {equals: "New York"}, and: {street_address: {like: "%Avenue of the Americas"}}}}) { id name street_address city state_abbr } ------- } This query will get users who reside in Connecticut or they live in New York and their street address is on "Avenue of the Americas". (Equivalent to: (state_abbr=CT OR (city="New York" AND street_address LIKE "%Avenue of the Americas"))). Available Filter Operators When working with string values, most operators are case-insensitive. If applicable, there will be a case-sensitive version availabe in the format {operator} Sensitive. • beginsWith o Purpose: Finds values that will start with the supplied value, o Example: street_address : {beginsWith: "100"} o Expected Result: All users with street addresses that start with 100 will be returned, o beginsWithSensitive is available for case-sensitive queries. • between o Purpose: Finds values that are between two values, inclusive of the lower and upper values. o Example: age: {between: {lower: 20, upper: 30}} o Expected Result: All users who have an age greater than or equal to 20 and less than or equal to 30 will be returned, o betweenSensitive is available for case-sensitive queries. • contains o Purpose: Finds records that have the supplied value anywhere in the field, o Example: street_address : {contains: "Main"} o Expected Result: All users who have an address that contains "Main" will be returned. • endsWith o Purpose: Finds values that will end with the supplied value, o Example: street_address : {endsWith: "St."} o Expected Result: All users with street addresses that end with St. will be returned, o endsWithSensitive is available for case-sensitive queries. • equals o Purpose: Finds values that will equal the supplied value, o Example: state_abbr: {equals: "CA"} o Expected Result: All users in California will be returned, o equalsSensitive is available for case-sensitive queries. • excludes o Purpose: Finds values that will not be like the supplied value anywhere in the field (the opposite of contains), o Example: street_address : {excludes: "Main"} o Expected Result: All users whose street address does not include Main will be returned. o excludesSensitive is available for case-sensitive queries. • greaterThan o Purpose: Finds values that are greater than the supplied value. ------- o Example: age : { greaterThan : 30} o Expected Result: All users with an age of 31 or higher will be returned, o greaterThanSensitive is available for case-sensitive queries. greaterThanEqual o Purpose: Finds values that are greater than or equal to the supplied value, o Example: age: {greaterThanEqual: 30} o Expected Result: All users with an age of 30 or higher will be returned, o greaterThanEqualSensitive is available for case-sensitive queries. in o Purpose: Finds values that are in the supplied list, o Example: state_abbr: {in: ["MS", "AL", "LA"]} o Expected Result: All users in the states of Mississippi, Alabama, and Lousiana will be returned. o insensitive is available for case-sensitive queries. inSubQuery o Purpose: Finds values that are in a subquery in the query. o Example: state_abbr : {inSubQuery: insubquery: "state_query"} } o Expected Result: All users whose state is supplied in the subquery aliased as "state_query" will be returned, o insensitive is available for case-sensitive queries. lessThan o Purpose: Finds values that are less than the supplied value, o Example: age: {lessThan: 30} o Expected Result: All users with an age of 29 or lower will be returned, o lessThanSensitive is available for case-sensitive queries. lessThanEqual o Purpose: Finds values that are less than or equal to the supplied value, o Example: age: {lessThanEqual: 30} o Expected Result: All users with an age of 30 or lower will be returned, o lessThanEqualSensitive is available for case-sensitive queries. like o Purpose: Finds values that are similar to the supplied value. Uses the % character as a wildcard. o Example: street_address : {like: "%Main St."} o Expected Result: All users with an any address that begins with Main St. will be returned. o likeSensitive is available for case-sensitive queries. notBeginsWith o Purpose: Finds values that will not start with the supplied value, o Example: street_address : {notBeginsWith: "100"} o Expected Result: All users with street addresses that do not start with 100 will be returned. o notBeginsWithSensitive is available for case-sensitive queries. notEndsWith o Purpose: Finds values that will not end with the supplied value, o Example: street_addres s : {notEndsWith: "St."} ------- o Expected Result: All users with street addresses that do not end with St will be returned. o notEndsWithSensitive is available for case-sensitive queries. • notEquals o Purpose: Finds values that are not equal to the supplied value, o Example: state_abbr: {notEquals: "FL"} o Expected Result: All users who do not reside in Florida will be returned, o notEqualsSensitive is available for case-sensitive queries. • notln o Purpose: Finds values that are not in the supplied list, o Example: state_abbr: {in: ["TX", "OK", "KS"]} o Expected Result: All users who are not in the states of Texas, Oklahoma, and Kansas will be returned, o notlnSensitive is available for case-sensitive queries. • notLike o Purpose: Finds values that are not similar to the supplied value. Uses the % character as a wildcard. o Example: street_address : {notLike: "%Main St."} o Expected Result: All users with an any address that do not begin with Main St. will be returned. o likeSensitive is available for case-sensitive queries. • null o Purpose: Finds values that are either null or not null, o Example: state_abbr: {null: true} o Expected Result: All users who do not have a value for state will be returned, o Example: state_abbr: {null: false} o Expected Result: All users who do have a value for state will be returned. • regex o Purpose: Finds values that match the supplied regular expression. o Example: street_address : {regex: " (main) {1, 3 } " } o Expected Result: All users who have a street address that contains main at least once and at most three times, o regexSensitive is available for case-sensitive queries. Casting fields in filters When needing to cast a field to a different type to work with a filter, use the cast attribute in the filter. query sampleQuery { users\_\_contact_list (where: {street_number: {like: "%10%", cast: "text"}}) { id name ------- address (alias: "street_address") } } In the example above, the results will be filtered by the street number. Since the street number is stored as an integer, it is cast to a text field so the like operator can be used. Valid Field Cast Types • date • decimal • float • integer • number • text Using functions in a filter You can use the LPad, Replace, and Trim (along with LTrim and RTrim) functions in the filter. To do so, add the function as an attribute for the field in the where clause. • Ipad - Left-pads a string with a specified character. Example: (where : {age: {like: "%l", lpad: [3, " 0 "}}). The first parameter is the length, the second is the character to pad with, the default pad character is a single space (" "). • replace - Replaces the pattern in the database field values with the replacement text. Example: "(where: {email: {like: "@gmail.com", replace: "."]}}). The first parameter is the pattern to search for, the second parameter is the text to replace the pattern with, the default replacement text is an empty string. • trim - Trim the string. Example: (where : {age: {like: "%1", trim: "123"}}).The parameter is the characters to trim, ihe default trim is a single space (" "). • Itrim and rtrim - Trim the left or right of the string, similar to trim. Dates You can filter by dates and datetimes for fields that are of a date data type. For dates, the value must be in the format yyyy-mm-dd. For datetimes, the value must be in the format yyyy-mm-dd hh :mm : ss. Datetimes use the 24 hour format. query sampleQuery { users\_\_contact_list (where: {start_date: {greaterThanEqual: "2021-05- 21"}}) { id name address (alias: "street address") ------- } } In the example above, the results will be filtered to get the users who started on or after May 21, 2021. query sampleQuery { users\_\_contact_list (where: {start_date: {greaterThanEqual: "2021-06-13 15:30:00"}}) { id name address (alias: "street_address") } } In the example above, the results will be filtered to get the users who started on or after June 13, 2021 at 3:30 PM. Joins Tables can be joined to each other in queries. A joined table can still have filters, orderBy, and groupBy clauses applied to it. Tables can be joined using the equals, notEquals, equalslnsensitive, and notEqualslnsensitive operators. When using the equals or notEquals operators, the join will be equalivalent to equalsSensitive and notEqualsSensitive, respectively. query sampleQuery { users contact_list (where: {state_abbr: {in: ["VA", "MD"]}}) { id name street_address city state_abbr users orders (left_outer_join: {users contact_list id: {equals: user_id}}) { order_id order_name order_date } } ------- } This query will be run against the contactjist and orders table in the users schema. A left outer join will be performed on the contactjist table's id column and the orders table's userjd column. Join Operator Types • cross_join: Cross Join • full_outer_j oin: Full Outer Join • hash_j oin: Hash Join • inner_j oin: Inner Join • left_j oi n: Left Join • left_outer_join: Left Outer Join • right_j oin: Right Join • right_outer_j oin: Right Outer Join • outer_j oin: Outer Join Functions in Joins Joins support the use of functions when joining tables. Trim (along with LTrim and RTrim), LPad, Replace, and Cast are supported. Here is an example of a join using Ipad: query joinQuery { users contact_list { name street_address form_type_ind users orders (left_outer_join: {users contact_list id: {equals: {user_id: {lpad: [10, '0']}}, lpad: [10, '0']}}) { order_id order_name order_date } } } Subqueries The API supports a limited version of subqueries. A subquery can be created similar to a join, only using the subquery parameters. A subquery can still have filters, orderBy, and groupBy clauses applied to it. ------- query sampleQuery { users contact_list (where: {state_abbr: {in: ["VA", "MD"]}}) { id name street_address city state_abbr users orders (subquery: {alias: "orders"}) { order_id order_name order_date } } } This query will be run against the contactjist and orders table in the users schema. A subquery will be performed on the orders table as it pulls in the orderjd, order_name, and order_date columns. If the subquery is to be used with the inSubquery filter, then the alias parameter must be supplied! Pagination To paginate through results, the limit and offset parameters can be supplied. query sampleQuery { users\_\_contact_list (limit: 10, offset: 20) { id name street_address city state_abbr } } In this query, a maximum of 10 records will be returned. The first 20 matching records in the contactjist table will be skipped and the next 10 records will be returned. The API will return a maximum of 10,000 records. Ordering Results Results can be ordered through the orderBy query parameter. ------- query sampleQuery { users\_\_contact_list (orderBy: {city: "asc", state_abbr: "desc"}) { id name street_address city state_abbr } } The results in this example will be ordered by first the city field ascending and then by the state_abbr field descending, "asc", "ascNullsFirst", "ascNullsLast","desc", "descNullsFirst", and "descNullsLast" are the only valid values for orderBy. Ordering Joined Columns When joining tables and wanting to order the results by columns in a joined table, specify all the joins in the primary table. For the columns in the joined table, use the format schema table column to specify the column that should be joined. (The schema, table, and column are separated by double underscores .) query sampleQuery { users contact_list (where: {state_abbr: {in: ["VA", "MD"]}}, orderBy: {name: "asc", users orders order_date: "desc"}) { id name street_address city state_abbr users orders (left_outer_join: {users contact_list id: {equals: user_id}}) { order_id order_name order_date } } } ------- In this query, the results will be ordered first in ascending order by the name column in the users.contactjist table. Then the results will be ordered by the order_date column in the users.orders table in descending order. Grouping Results query sampleQuery { users\_\_contact_list (groupBy: ["city", "state_abbr"]) { id name street_address city state_abbr } } The results in this example will be grouped by the city and state_abbr fields. Variables As with normal GraphQL queries, variables can be substituted for values in query parameters, for example in the limit field or the filter values. The allowed types of values are String, Int, Float, and OrderBy. The String, Int, and Float values can also be stored in arrays. Example Query with limit, offset, and order by variables Query query query($limit: Int!, $offset: Int!, $orderBy: OrderBy!]) { users contact_list (limit: $limit, offset: $offset, where: {state_abbr: {in: ["VA", "MD"]}}, order_by: $orderBy) { all_columns\_\_ } } Variables {"limit": 10, "offset": 30, "orderBy": {"city": "asc", "state_abbr": "desc"}} Here the limit, offset, and orderBy variables will be substituted in the query when it is executed against the data source. The $limit, $offset variables are required integers. The $orderBy variable is a required variable in the order by clause structure. ------- Example Query with where clause variables Query query query($state: [String]) { users contact_list (state_abbr: {in: $state}}) { all_columns\_\_ } } Variables {"state": ["ND", "SD"]} Here the $state variable is an array of strings. The values of "ND" and "SD" will be provided to the query when it runs against the database. Multiple queries Multiple queries can be sent in the same request. query sampleQuery { users contact_list { id name street_address city state_abbr } users contact_list\_\_aggregate { aggregate { count } } } They will be run sequentially. This increases the chance of a timeout on the request with no results being returned. Returned data ------- Data is returned from the service in a nested JSON object The primary element is called data. Each table's results will be returned as a property within the data element For example: { "data": { "users contact list": [ Main Street" }, Broad Street" }, "id": 123, "name": "John Doe", "address": "123 "id": 124, "name": "Jane Doe", "address": "456 users contact_list\_\_aggregate": [ "count": 45 6 } Export formats Data can also be returned in the following formats: CSV, Excel, JSON, JSONP, XML, HTML, PDF, and GraphQL. To export a query's results to a different format, append the format to the end of the URL If using JSONP, add the callback to wrap the result in with the "callback" query parameter. CSV: /query/csv Excel: /query/excel XML: /query/xml JSON: /query/json JSONP: /query/jsonp?callback=callback-value HTML: /query/html PDF: /query/pdf GraphQL: /query/graphql The GraphQL export format is similar to the regular format (/query). This format is provided to have greater compatibility with some GraphQL clients. ------- |