Write an Imagine config file

A general overview of the syntax and some general rules for writing an Imagine config file

As we mention in the domains overview page, you can use Imagine's SmartCompiler to generate production ready Django code by expressing your app and domain specifications in an Imagine (.im) config file.

In this document we wanted to provide a a high-level overview the two types of syntax that you will use when you write an Imagine config file (including the key parts and some general rules for each):

Settings

Imagine's settings provides an easy way for you to choose various settings for:

  • your app, such as
    • the name of the app,
    • the framework you want your app's code to be generated in,
    • framework related sub-settings such as:
      • the package manager to use to the framework
      • the layout of the generated files
  • each domain, such as
    • the API format you want to use in your app

This gives you the flexibility to choose how you want your app and its various code modules to be generated, organized, stored, formatted etc.

The comprehensive set and description of all the settings is covered in the Settings guide page.

Key parts

At a high level, our settings has two simple parts:

  • the settings demarcator
    • this allows us to separate settings syntax from the rest of the code module syntax
  • the actual settings, which follow the yaml syntax [ADD LINK]

For example, take a look at the settings below:

settings
app:
# name of your app
name: 'demo'
# [django]
framework: 'django'
django:
# [virtualenv, pipenv, poetry]
package-manager: 'virtualenv'
# [gunicorn, uwsgi, mod_wsgi, cherrypy]
server: 'gunicorn'
layout:
# [single-file, separate-files]
models: 'single-file'
# [single-file, separate-files]
views: 'separate-files'
# name of the project settings directory
project-root-dir: 'project'
api:
# [graphql, restapi]
format: 'graphql'
end settings

In this example:

  • this syntax represents the settings demarcator
settings
end settings
  • the rest of the syntax pertains to various app, framework and domain-specific settings.

General rules

  • Our settings syntax is the same as yaml syntax - you can read more about this [here] (ADD LINK).

  • As long as you use the settings demarcator before and after any settings syntax to demarcate it from the domain-specific syntax, you can place all your settings:

    • together or in separate parts
    • in the same file or different files

Domain-specific syntax

We've created a simple syntax to represent various concepts tied to various domains (For more information about what we mean by domains, read this).

Key parts

For each domain, code modules are the highest level representation of concepts pertinent to building that domain. For example:

Each code module further contains Imagine parameter(s), where some Imagine parameters have user-selected names.

Let's take the example of Imagine's data model and API syntax to explain this.

(Please note, the specifics of the data model syntax are described in the data model page; we are simply using this as an example to highlight some general aspects of our syntax that broadly apply to all code modules).

Model Musician {
first_name string [primary-key, max-length 100]
last_name string [max-length 100]
age integer [range 10 100]
}
API /musician-profile {
actions [Read, ReadMany]
model Musician
data [first_name, last_name]
}

In this example:

  • Model is an Imagine class
  • Musician is a User-selected model-name
  • first-name last-name age are User-selected field-names
  • string and integer are Imagine fields-types
  • primary-key, max-length 100 and range 10 100 are Imagine field-properties with their respective field-property-values.

General rules

These are just some general rules which we have listed to avoid repeating in each page. The comprehensive set and description of all the code modules syntax is covered in each individual domain-specific page.

  • Imagine parameters

    • These are completely case insensitive in our syntax
      • so, whether you write Model, model, MODEL, mOdEl, our compiler recognizes all these as Model.
    • Our syntax allows a lot of flexibility
      • max-length, max_length and maxlength are all recognized by our compiler.
  • User-selected names

    • In the above example: Musician first-name last-name and age are all user-selected names.
    • All user-selected names need to be unique for each parameter respectively, but can be repeated across different parameters.
      • so, you can have a Model called Musician and an API called Musician, but you cannot have two Models classes called Musician.
    • Can include letters in any case, numbers, hyphens and underscores, but MUST start with a letter
      • so, first-name, firstName123, First_NAME are all valid user-selected names, but 1firstname and firstname!! are not.
      • NOTE: In Django hyphens are not supported, so any hyphens in your user-selected name in the .im config file will be converted to underscores
        • so, while firstName and first_name are two distinct field names in Django output code, first-name and first_name would both be treated at first_name in Django.
    • Once a user-selected parameter is created, their subsequent use becomes fully case-sensitive and needs to be an exact case match to the original user-selected parameter
      • so, for a user-selected parameter called first-name, our compiler would not recognize First-name or first-NAME.
      • Differently said, a Model could have two user-selected parameters called First-name and first-NAME and our compiler would treat each of these as unique.
    • In Django,
  • Order of declarations with {} is irrelevant

    • Both of the following API endpoint definitions would result in the same generated code.
    API /musician-profile {
    actions [Read, ReadMany]
    model Musician
    data [first_name, last_name]
    }
    API /musician-profile {
    data [first_name, last_name]
    actions [Read, ReadMany]
    model Musician
    }
  • Any number of spaces, tabs and new lines are treated as a single space

    • Both of the following API endpoint definitions would result in the same generated code.
    API /musician-profile {
    actions [Read, ReadMany]
    model Musician
    data [first_name, last_name]
    }
    API /musician-profile {
    data [first_name, last_name]
    actions [Read, ReadMany]
    model Musician
    }