This introductory SOML section provides information about the metadata, configuration, and prefixes of a schema. It also describes some common concepts applicable throughout the schema, such as naming convention, IRI processing, and reserved words.

Schema Metadata

You can provide some info (metadata) about the schema.

id:          /soml/some-domain
label:       Some Domain schema
created:     2019-04-15
updated:     2019-05-10
versionInfo: 1.0


It is highly recommended to provide an id. If you do not do so, the Semantic Objects will generate a random id when you post the schema to the Semantic Objects, but you should use this only in testing and never in production.

All other fields are optional and have sensible defaults.

  • id: used for SOML operations (create, update, delete) by the Semantic Objects. It should start with /soml/.
  • versionInfo: the version of the schema (SOML instance and corresponding ontology), not a version of the SOML language.

The rest of the preamble defines prefixes (namespaces) that are used to map object and prop names to IRIs as used in RDF.

Schema Configuration

You can provide configurations that are specific to the current schema.

id:          /soml/some-domain
label:       Some Domain schema
versionInfo: 1.0

  enable_mutations: true
  lang: {fetch: "en", validate: "UNIQ", implicit: "en", defaultNameFetch: "ANY", appendDefaultNameFetch: true} # or lang: "en"
  queryPfx: ""
  mutationPfx: ""
  nullJsonArrays: false

All of the supported configurations are optional and have reasonable defaults.

The currently supported keys are:

  • enable_mutations: with possible values true (default) / false. Controls whether the generated GraphQL schema should include object mutations or not. To learn more about GraphQL mutations, see the GraphQL Mutation Tutorial.


    This option cannot override the service configuration graphql.mutation.enabled=false to forcefully enable mutations.

  • lang: provides a schema level default for langString language handling.

    • defaultNameFetch: specifies the default fetch spec to use or append to the name fetch spec. Default value is ANY.
    • appendDefaultNameFetch: specifies whether the default spec, if any, should be appended or not to any user-defined name fetch spec. Default value is true.

    The configuration values above are for illustration purposes. For more information how to configure the language handling, see the Language Configurations section. For more information about name fetching, see the Interface Nameable section.

  • queryPfx: allows setting a prefix that will be put in all queries in the GraphQL schema. Does not have a default value.


    If not configured, the query for the type Person will look like this:

    type Query {
       person(orderBy: Person_OrderBy, limit: PositiveInteger, offset: PositiveInteger, ID: [ID!], where: Person_Where_Multi, lang: String): [Person]!

    But if changed to queryPfx: query_, for example, the query would look like this:

    type Query {
       query_person(orderBy: Person_OrderBy, limit: PositiveInteger, offset: PositiveInteger, ID: [ID!], where: Person_Where_Multi, lang: String): [Person]!
  • mutationPfx: allows setting a prefix that will be put in all mutations in the GraphQL schema. Does not have a default value.


    If not configured, the mutation queries for the type Person will look like this:

    type Mutation {
      create_Person(objects: [Person_Create_Input!]): Person_Mutation_Response
      update_Person(objects: Person_Update_Input!, where: Person_Where_Multi): Person_Mutation_Response
      delete_Person(where: Person_Delete_Filter!): Person_Mutation_Response

    But if changed to mutationPfx: mutation_, for example, the mutations would look like this:

    type Mutation {
      mutation_create_Person(objects: [Person_Create_Input!]): Person_Mutation_Response
      mutation_update_Person(objects: Person_Update_Input!, where: Person_Where_Multi): Person_Mutation_Response
      mutation_delete_Person(where: Person_Delete_Filter!): Person_Mutation_Response
  • nullJsonArrays: changes the default behavior on how to interpret missing data for multi-valued properties. If set to true, multi-valued properties will be returned as null instead of empty array []. The default value is false.


    Given a property friends of type Person that has no values, the following behavior can be observed:

    Array definition nullJsonArrays: true nullJsonArrays: false
    [Person] null []
    [Person]! error, destroy parent []
    [Person!] null []
    [Person!]! error, destroy parent []

For more information, see Property Nullability.

Special Prefixes

  vocab_prefix: voc

The special prefixes (namespaces) include:

  • base_iri: base IRI for data (resources), used in SOML characteristics such as type and prefix. We currently use full IRIs in GraphQL queries and responses, but in the future may shorten them using the base (see Naming Convention and IRI Processing).

  • vocab_iri: default namespace for vocabulary (ontology) terms, i.e. object and prop names. SOML allows the use of multiple ontologies (see Own Prefixes) through underscore prefixes like pfx_prop, and one of them is designated as default so it can be used without prefix.

  • vocab_prefix: prefix corresponding to the vocab IRI. The vocabulary prefix is not materialized in the GraphQL schema for ordinary properties. For example, if prop is defined as pfx:prop, it will be visualized simply as prop. However, name (which is a reserved word) has to be defined as pfx:name to avoid collision with the predefined property, and will be visualized as pfx_name. The same applies to id and type, which are reserved words as well.

    • It must be used in SOML for prop names that conflict with a reserved word (see Reserved Words)
    • It is also useful in languages that do not have such a concept (e.g., Turtle), as we do not like to use an empty prefix.

The following IRIs may be used in the future:

  • ontology_iri: an RDF Ontology IRI used to make statements about the ontology. Typically, it is the same as the vocab IRI but without a trailing slash or hash.
  • shapes_iri: RDF Shapes IRI: all generated shapes live under this IRI.

Predefined Prefixes

SOML predefines a few commonly used prefixes such as dct: gn: owl: rdf: xsd:, and some more exotic prefixes:

  • puml:: used by the rdfpuml diagramming tool.
  • so:: in the future may transmit in JSON-LD built-in SOML properties like so:name and so:type.
  • res:: in the future may transmit in JSON-LD dynamic properties calculated in queries.
  # common prefixes

The Special Prefixes shown in the previous section and those above are predefined and may be used without having to define them (but can be overridden): This means that a valid SOML does not need to define any prefixes.

  • A plain name like Obj or prop is mapped using vocab_iri, which by using the predefined prefixes maps to voc:Obj or voc:prop respectively, and thus to IRIs.
  • Of course, in a real application you would want to define your own special prefixes.

Own Prefixes

You can also define your own prefixes for your domain, e.g.,:

  # schema-specific prefixes


  • Each prefix should conform to the Turtle grammar production PN_PREFIX.
  • Prefixes should not mask defined IRI schemes such as http: https: mailto: ftp: mailto: urn: geo:. (In some cases, you may want to break this guideline for convenience, e.g., the JSON-LD context defines a prefix geo: that breaks it.)

Naming Convention and IRI Processing

Class and property names (the YAML key) play several important roles:

  • They are used in SOML to describe objects, properties, and the connection between them.
  • They (together with prefixes and vocab_iri) are used to derive RDF IRIs.
  • They are used in GraphQL as type and field names. pfx:name is translated to pfx_name to make it GraphQL and JSON friendly.

If a name includes : , the part before it must be a defined prefix (see Own Prefixes).

The local parts of property and class names (part after : if any) must comply with the following naming conventions:

  • Prop names must start with a lowercase Unicode letter, and are recommended to follow a lowerCamelCase convention.
  • Class names must start with an uppercase Unicode letter, and are recommended to follow an UpperCamelCase (also called PascalCase) convention.
  • Both must conform to the Turtle grammar production PN_PREFIX. Please note that this is stricter than RDF and Turtle local name conventions.
  • Cannot start with two underscores __, which is reserved for GraphQL introspection.
  • If they include an underscore, they cannot start with pfx_ where pfx: is a defined prefix. Use pfx:name if you mean that prefix, or voc:pfx_name if you mean the default vocab namespace (see Special Prefixes)
  • Cannot be a reserved word, see Reserved Words.

Names in SOML are converted to IRIs as follows:

  • If the prop has characteristic rdfProp, use that instead of the name.
  • If a name starts with a defined prefix pfx:, replace the prefix with the corresponding IRI.
  • Otherwise, prepend vocab_iri.

Strings in the type and rdfProp characteristics are converted to IRIs as follows:

  • If the string starts with a defined IRI scheme, use it directly (absolute IRI).
  • Else if the string starts with a defined prefix pfx:, replace the prefix with the corresponding IRI (prefixed IRI).
  • Else if the string includes only Unicode alphanumerics and [-._], prepend vocab_iri (relative ontology IRI).
  • Else prepend base_iri (relative instance IRI). Typically, such a string will include / or # and is used in the type characteristic to designate a “business type” not defined in an ontology, e.g., a skos:ConceptScheme IRI.

GraphQL queries and JSON responses use absolute IRIs for iri fields. This includes:

  • the id field of every object, which is its IRI.
  • fields of type iri (e.g., websiteUrl of a company) that reference external resources.
  • the type field, which is the datatype of Literals or rdf:type of objects (most of the time you will not need to specify these explicitly).

We are planning to use Compact URIs (CURIEs) in the future to shorten GraphQL queries and JSON responses (see CURIE in Wikipedia and the CURIE W3C TR) but it has not been done yet as it may may cause confusion in some cases. If you would like to use CURIEs, please do send us your feedback about it.

Reserved Words

The following reserved words cannot be used as prop names:

  • id: the node IRI that is a mandatory field for every object (the GraphQL type ID! is used)
  • type: the rdf:type of objects or the datatype of scalars
  • lang: the language tag of a Literal or langString
  • value: the value of a Literal
  • name: a uniform preferred name for an object

The following reserved words cannot be used as object names:

  • Literal: together with lang, type, and value, it is used to represent an RDF literal
  • Object: an interface for common functionality: the presence of id and type
  • Nameable: an interface used for the presence of name

To use such prop/object names in the vocab namespace, you need to spell them out in full, e.g., voc:type voc:name voc:Object.

GraphQL descr Directive

Objects and properties have label and descr. These are emitted separately in GraphQL, so they can be used more conveniently in a UI app.

  • Label comes before the object/prop as a “string”: this is a standard GraphQL feature.
  • Descr comes after the object/prop as a @descr directive.

For example, this SOML property:

prefName: {label: "Preferred name", min: 1, descr: "A single selected name"}

Is emitted in GraphQL as follows:

"Preferred name"
prefName: String @descr(_:"A single selected name") @constraints(minCount : 1, maxCount : 1)

The directive is defined as follows:

directive @descr(_:String!) on FIELD_DEFINITION | OBJECT | INTERFACE

According to the GraphQL specification, directive values are not returned as part of GraphQL schema introspection. This problem is discussed in issue graphql-spec#300: we have added @descr as a use case, and return the directive value anyway.