Welcome to the Marim tutorial! Follow the steps below to develop your first data service.
This tutorial makes use of a sample database. To execute it, type the command
docker run --rm --network host marimplatform/dvdrental
A Marim project, i.e., a set of specification files, is simply a directory. Therefore, create the tutorial project typing the command
mkdir ./dvdrental
Create the ./dvdrental/dvdrental.marim
file with the specification below.
table Category // Declares the structure of a query result
column Id type integer // Declares a column of a query result
column Name type string // Supported datatypes are date, decimal, integer, string, time and timestamp
column LastUpdate type timestamp
source DvdRental // Declares a JDBC data source
dialect postgresql // Supported dialects are calcite, db2, mysql, oracle, postgresql, sqlserver and teradata
url "jdbc:postgresql://localhost:5432/dvdrental" // JDBC URL with which the service will connect to the database
property "user" "postgres" // The property keyword sets a JDBC driver property value
property "password" "postgres" // All JDBC drivers support the properties "user" and "password"
query Categories // Declares a query
result table Category // Declares the query result structure
source DvdRental // Declares the data source in which the service will execute the query
statement // The query statement is a single or multiline string
"select category_id as Id,
name as Name,
last_update as LastUpdate
from category"
query Category
parameter Id schema type integer not null // Declares a query parameter and its schema, i.e., its type, nullability etc.
result table Category
source DvdRental
statement
"select category_id as Id,
name as Name,
last_update as LastUpdate
from category
where category_id = (" Id ")" // Parameterized query statements may refer its parameters
To execute the service, type the command
docker run --rm --network host -v $(pwd)/dvdrental:/marim marimplatform/service
which will result in
__ __ _ | \/ | (_) | \ / | __ _ _ __ _ _ __ ___ | |\/| |/ _` | '__| | '_ ` _ \ | | | | (_| | | | | | | | | | |_| |_|\__,_|_| |_|_| |_| |_| Data Services Platform 1.0.0-SNAPSHOT https://www.marimplatform.dev Copyright (C) 2022 Saulo Araujo All rights reserved 2023-04-09T13:37:13.530Z INFO 1 --- [ main] dev.marimplatform.ServiceApplication : Starting ServiceApplication using Java 17.0.6 with PID 1 (/app/classes started by root in /) 2023-04-09T13:37:13.538Z INFO 1 --- [ main] dev.marimplatform.ServiceApplication : No active profile set, falling back to 1 default profile: "default" 2023-04-09T13:37:17.333Z INFO 1 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http) 2023-04-09T13:37:17.356Z INFO 1 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat] 2023-04-09T13:37:17.357Z INFO 1 --- [ main] o.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/10.1.7] 2023-04-09T13:37:17.748Z INFO 1 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext 2023-04-09T13:37:17.753Z INFO 1 --- [ main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 3941 ms 2023-04-09T13:37:24.263Z INFO 1 --- [ main] o.s.b.a.e.web.EndpointLinksResolver : Exposing 3 endpoint(s) beneath base path '/actuator' 2023-04-09T13:37:24.563Z INFO 1 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path '' 2023-04-09T13:37:24.668Z INFO 1 --- [ main] dev.marimplatform.ServiceApplication : Started ServiceApplication in 12.349 seconds (process running for 13.697)
Marim maps queries to URLs. Query identifiers become URL suffixes. Thus, to
execute a query, send a HTTP request to its URL. For example, to execute the
query Categories
, send a request to the URL
http://localhost:8080/rest/Categories
. To send such request with
curl, type the command
curl http://localhost:8080/rest/Categories
The service will respond
[{"Id":1,"Name":"Action","LastUpdate":"2006-02-15T09:46:27Z"},{"Id":2,"Name":"Animation","LastUpdate":"2006-02-15T09:46:27Z"},{"Id":3,"Name":"Children","LastUpdate":"2006-02-15T09:46:27Z"},{"Id":4,"Name":"Classics","LastUpdate":"2006-02-15T09:46:27Z"},{"Id":5,"Name":"Comedy","LastUpdate":"2006-02-15T09:46:27Z"},{"Id":6,"Name":"Documentary","LastUpdate":"2006-02-15T09:46:27Z"},{"Id":7,"Name":"Drama","LastUpdate":"2006-02-15T09:46:27Z"},{"Id":8,"Name":"Family","LastUpdate":"2006-02-15T09:46:27Z"},{"Id":9,"Name":"Foreign","LastUpdate":"2006-02-15T09:46:27Z"},{"Id":10,"Name":"Games","LastUpdate":"2006-02-15T09:46:27Z"},{"Id":11,"Name":"Horror","LastUpdate":"2006-02-15T09:46:27Z"},{"Id":12,"Name":"Music","LastUpdate":"2006-02-15T09:46:27Z"},{"Id":13,"Name":"New","LastUpdate":"2006-02-15T09:46:27Z"},{"Id":14,"Name":"Sci-Fi","LastUpdate":"2006-02-15T09:46:27Z"},{"Id":15,"Name":"Sports","LastUpdate":"2006-02-15T09:46:27Z"},{"Id":16,"Name":"Travel","LastUpdate":"2006-02-15T09:46:27Z"}]
To reduce response length, Marim does not pretty-print responses, but you can easily pretty-print JSON responses piping to jq. For instance, the command
curl http://localhost:8080/rest/Categories | jq
results in
[ { "Id": 1, "Name": "Action", "LastUpdate": "2006-02-15T09:46:27Z" }, { "Id": 2, "Name": "Animation", "LastUpdate": "2006-02-15T09:46:27Z" }, { "Id": 3, "Name": "Children", "LastUpdate": "2006-02-15T09:46:27Z" }, { "Id": 4, "Name": "Classics", "LastUpdate": "2006-02-15T09:46:27Z" }, { "Id": 5, "Name": "Comedy", "LastUpdate": "2006-02-15T09:46:27Z" }, { "Id": 6, "Name": "Documentary", "LastUpdate": "2006-02-15T09:46:27Z" }, { "Id": 7, "Name": "Drama", "LastUpdate": "2006-02-15T09:46:27Z" }, { "Id": 8, "Name": "Family", "LastUpdate": "2006-02-15T09:46:27Z" }, { "Id": 9, "Name": "Foreign", "LastUpdate": "2006-02-15T09:46:27Z" }, { "Id": 10, "Name": "Games", "LastUpdate": "2006-02-15T09:46:27Z" }, { "Id": 11, "Name": "Horror", "LastUpdate": "2006-02-15T09:46:27Z" }, { "Id": 12, "Name": "Music", "LastUpdate": "2006-02-15T09:46:27Z" }, { "Id": 13, "Name": "New", "LastUpdate": "2006-02-15T09:46:27Z" }, { "Id": 14, "Name": "Sci-Fi", "LastUpdate": "2006-02-15T09:46:27Z" }, { "Id": 15, "Name": "Sports", "LastUpdate": "2006-02-15T09:46:27Z" }, { "Id": 16, "Name": "Travel", "LastUpdate": "2006-02-15T09:46:27Z" } ]
Set the Accept
HTTP request header to text/csv
to get CSV responses. For
example, the command
curl -v -H "Accept: text/csv" http://localhost:8080/rest/Categories
results in
Id,Name,LastUpdate 1,Action,2006-02-15T09:46:27Z 2,Animation,2006-02-15T09:46:27Z 3,Children,2006-02-15T09:46:27Z 4,Classics,2006-02-15T09:46:27Z 5,Comedy,2006-02-15T09:46:27Z 6,Documentary,2006-02-15T09:46:27Z 7,Drama,2006-02-15T09:46:27Z 8,Family,2006-02-15T09:46:27Z 9,Foreign,2006-02-15T09:46:27Z 10,Games,2006-02-15T09:46:27Z 11,Horror,2006-02-15T09:46:27Z 12,Music,2006-02-15T09:46:27Z 13,New,2006-02-15T09:46:27Z 14,Sci-Fi,2006-02-15T09:46:27Z 15,Sports,2006-02-15T09:46:27Z 16,Travel,2006-02-15T09:46:27Z
By default, every Marim data service URL accepts the following parameters:
The _select
parameter allows one to specify which property/column names the response
will include. Its value must be a comma-separated list of property/column names. For
instance, the command
curl -H "Accept: text/csv" http://localhost:8080/rest/Categories?_select=Id,Name
results in
Id,Name 1,Action 2,Animation 3,Children 4,Classics 5,Comedy 6,Documentary 7,Drama 8,Family 9,Foreign 10,Games 11,Horror 12,Music 13,New 14,Sci-Fi 15,Sports 16,Travel
The _filter
parameter allows one to specify which elements the response will
include. Its value must be a RSQL
expression. For example, the command
curl -H "Accept: text/csv" http://localhost:8080/rest/Categories?_filter=Name=gt=Games
results in
Id,Name,LastUpdate 11,Horror,2006-02-15T09:46:27Z 12,Music,2006-02-15T09:46:27Z 13,New,2006-02-15T09:46:27Z 14,Sci-Fi,2006-02-15T09:46:27Z 15,Sports,2006-02-15T09:46:27Z 16,Travel,2006-02-15T09:46:27Z
Through the _orderby
parameter, one can specify how the service will sort the
response. Its value must be a comma-separated list of sort criterias, i.e., a
column name and a sort direction (asc or desc) separated by a white space. For
instance, the command
curl -H "Accept: text/csv" http://localhost:8080/rest/Categories?_orderby=Name%20desc
results in
Id,Name,LastUpdate 16,Travel,2006-02-15T09:46:27Z 15,Sports,2006-02-15T09:46:27Z 14,Sci-Fi,2006-02-15T09:46:27Z 13,New,2006-02-15T09:46:27Z 12,Music,2006-02-15T09:46:27Z 11,Horror,2006-02-15T09:46:27Z 10,Games,2006-02-15T09:46:27Z 9,Foreign,2006-02-15T09:46:27Z 8,Family,2006-02-15T09:46:27Z 7,Drama,2006-02-15T09:46:27Z 6,Documentary,2006-02-15T09:46:27Z 5,Comedy,2006-02-15T09:46:27Z 4,Classics,2006-02-15T09:46:27Z 3,Children,2006-02-15T09:46:27Z 2,Animation,2006-02-15T09:46:27Z 1,Action,2006-02-15T09:46:27Z
The _skip
parameter allows one to specfy how many elements will be excluded
from the response start. Its value must be a integer greater than or equal to
zero. For example, the command
curl -H "Accept: text/csv" http://localhost:8080/rest/Categories?_skip=1
results in
Id,Name,LastUpdate 2,Animation,2006-02-15T09:46:27Z 3,Children,2006-02-15T09:46:27Z 4,Classics,2006-02-15T09:46:27Z 5,Comedy,2006-02-15T09:46:27Z 6,Documentary,2006-02-15T09:46:27Z 7,Drama,2006-02-15T09:46:27Z 8,Family,2006-02-15T09:46:27Z 9,Foreign,2006-02-15T09:46:27Z 10,Games,2006-02-15T09:46:27Z 11,Horror,2006-02-15T09:46:27Z 12,Music,2006-02-15T09:46:27Z 13,New,2006-02-15T09:46:27Z 14,Sci-Fi,2006-02-15T09:46:27Z 15,Sports,2006-02-15T09:46:27Z 16,Travel,2006-02-15T09:46:27Z
The _top
parameter allows one to specfy the maximum number of elements the
response will have. Its value must be a integer greater than zero. For
instance, the command
curl -H "Accept: text/csv" http://localhost:8080/rest/Categories?_top=1
results in
Id,Name,LastUpdate 1,Action,2006-02-15T09:46:27Z
Request the service OpenAPI specification typing the command
curl http://localhost:8080/openapi
The service will respond
{ "openapi" : "3.0.1", "servers" : [ { "url" : "http://localhost:8080/rest" } ], "paths" : { "/Categories" : { "get" : { "tags" : [ "Categories" ], "responses" : { "200" : { "description" : "OK", "content" : { "application/json" : { "schema" : { "type" : "array", "items" : { "type" : "object", "properties" : { "Id" : { "type" : "integer", "format" : "int64" }, "Name" : { "type" : "string" }, "LastUpdate" : { "type" : "string", "format" : "date-time" } } } } }, "text/csv" : { } } }, "400" : { "description" : "BAD_REQUEST", "content" : { "text/plain" : { "schema" : { "type" : "string" } } } }, "500" : { "description" : "INTERNAL_SERVER_ERROR", "content" : { "text/plain" : { "schema" : { "type" : "string" } } } } } }, "post" : { "tags" : [ "Categories" ], "responses" : { "200" : { "description" : "OK", "content" : { "application/json" : { "schema" : { "type" : "array", "items" : { "type" : "object", "properties" : { "Id" : { "type" : "integer", "format" : "int64" }, "Name" : { "type" : "string" }, "LastUpdate" : { "type" : "string", "format" : "date-time" } } } } }, "text/csv" : { } } }, "400" : { "description" : "BAD_REQUEST", "content" : { "text/plain" : { "schema" : { "type" : "string" } } } }, "500" : { "description" : "INTERNAL_SERVER_ERROR", "content" : { "text/plain" : { "schema" : { "type" : "string" } } } } } }, "parameters" : [ { "name" : "$select", "in" : "query", "style" : "form", "explode" : false, "schema" : { "type" : "array", "items" : { "type" : "string", "enum" : [ "Id", "Name", "LastUpdate" ] } } }, { "name" : "$filter", "in" : "query", "schema" : { "type" : "string" } }, { "name" : "$orderby", "in" : "query", "style" : "form", "explode" : false, "schema" : { "type" : "array", "items" : { "type" : "string", "enum" : [ "Id asc", "Id desc", "Name asc", "Name desc", "LastUpdate asc", "LastUpdate desc" ] } } }, { "name" : "$skip", "in" : "query", "schema" : { "type" : "integer", "format" : "int64", "maximum" : 9223372036854775807, "minimum" : 0 } }, { "name" : "$top", "in" : "query", "schema" : { "type" : "integer", "format" : "int32", "maximum" : 2147483647, "minimum" : 1 } } ] }, "/Category" : { "get" : { "tags" : [ "Category" ], "responses" : { "200" : { "description" : "OK", "content" : { "application/json" : { "schema" : { "type" : "array", "items" : { "type" : "object", "properties" : { "Id" : { "type" : "integer", "format" : "int64" }, "Name" : { "type" : "string" }, "LastUpdate" : { "type" : "string", "format" : "date-time" } } } } }, "text/csv" : { } } }, "400" : { "description" : "BAD_REQUEST", "content" : { "text/plain" : { "schema" : { "type" : "string" } } } }, "500" : { "description" : "INTERNAL_SERVER_ERROR", "content" : { "text/plain" : { "schema" : { "type" : "string" } } } } } }, "post" : { "tags" : [ "Category" ], "responses" : { "200" : { "description" : "OK", "content" : { "application/json" : { "schema" : { "type" : "array", "items" : { "type" : "object", "properties" : { "Id" : { "type" : "integer", "format" : "int64" }, "Name" : { "type" : "string" }, "LastUpdate" : { "type" : "string", "format" : "date-time" } } } } }, "text/csv" : { } } }, "400" : { "description" : "BAD_REQUEST", "content" : { "text/plain" : { "schema" : { "type" : "string" } } } }, "500" : { "description" : "INTERNAL_SERVER_ERROR", "content" : { "text/plain" : { "schema" : { "type" : "string" } } } } } }, "parameters" : [ { "name" : "Id", "in" : "query", "required" : true, "explode" : false, "schema" : { "type" : "integer", "format" : "int64" } }, { "name" : "$select", "in" : "query", "style" : "form", "explode" : false, "schema" : { "type" : "array", "items" : { "type" : "string", "enum" : [ "Id", "Name", "LastUpdate" ] } } }, { "name" : "$filter", "in" : "query", "schema" : { "type" : "string" } }, { "name" : "$orderby", "in" : "query", "style" : "form", "explode" : false, "schema" : { "type" : "array", "items" : { "type" : "string", "enum" : [ "Id asc", "Id desc", "Name asc", "Name desc", "LastUpdate asc", "LastUpdate desc" ] } } }, { "name" : "$skip", "in" : "query", "schema" : { "type" : "integer", "format" : "int64", "maximum" : 9223372036854775807, "minimum" : 0 } }, { "name" : "$top", "in" : "query", "schema" : { "type" : "integer", "format" : "int32", "maximum" : 2147483647, "minimum" : 1 } } ] } } }
Open the address http://localhost:8080/swagger-ui
in a browser to visualize
the service OpenAPI specification and send requests to it in a more
human-friendly way through the embedded
Swagger UI application.
Read the manual to learn more about Marim and start developing your own data services!