Gemini Starter: Model-Driven CRUD REST APIs With Spring

DZone 's Guide to

Gemini Starter: Model-Driven CRUD REST APIs With Spring

Let's see how to start with a full Gemini project to set up a CRUD REST API with Spring.

· Integration Zone ·
Free Resource

Gemini stars


This article explains what is included in the Gemini Starter Repository and how to start with a full Gemini project to set up a CRUD REST API, starting from Data Model and without generating code.

You may also like: Developing REST APIs

Gemini is a model-driven REST framework that automatically generates CRUD APIs. You can take a look at the official repository here. We are going to define entities and code to obtain the following CRUD APIs.

1. Gemini Custom Module

Gemini is made of a series of modules (core, auth, GUI, and so on..). When you start a project, you can also provide your custom Module that is the container for your entities, code, and APIs.

The previous code shows how to start with a Gemini Module. Gemini has two Spring Context: the root that loads entities and handles core features and the API context that starts the Web Application. So we use MyCustomModule to scan core components and events, while MyCustomModuleAPI is used to scan API modules (that may be useful if you want to register totally custom Spring web/rest endpoints). But usually, you don’t need them to start with Gemini basic REST features.

The important thing is that the core bean must override the Module Gemini Interface.

2. Gemini DSL and Entities

Since the name of the custom module is CUSTOM_MODULE, we can put the schema definition in the resources file schemas/CUSTOM_MODULE.at

In the repository, we have:

Note that Employee has two entity references: Company and Gender.

Gender is a special entity that implements a Domain (a built-in Gemini interface that provides two fields: code and description).

3. Immutable Entities

Immutable Entities are entities that cannot be modified, so it is not permitted to add a record (POST) or modify an existing one (PUT). But how can Gemini initialize them? It is simple, just add all the records inside the module record initialization file records/CUSTOM_MODULE.atr

In the previous file, we have defined:

  • The domain values for the Gender Entity
  • We made Gender Immutable, specifying that it is a closed domain

NB: In Gemini, each Entity has a lot of metadata associated with it. All these metas are stored in the Entity called Entity, and you can query all the metadata with Swagger using the Entity endpoint.

So after Gemini completes its startup, you have already the Gender filled with the value initialized in the file. And if you take a look at the Gender APIs, you can see that you cannot POST/PUT/DELETE. It is a closed immutable domain. Just GET Gender records.

4. Calculated Field Using Gemini Events

CRUD APIs are useful, but sometimes you want to add some logic or a custom behavior, like validation or calculated fields or records that automatically create other records as a dependency.

For example, let's make the fullName a calculated field by the concatenation of firstName and lastName. We are working on the EMPLOYEE entity, and we register the event before the record is inserted (create) the first time and also each time the records change (update).

It's simple. You only need a combination of Gemini annotations and the function to extract the fullName.

As you can see, if we POST a new Entity, the fullName is automatically calculated.


In this article, I showed you how to easily start with Gemini. But a lot of improvements will be developed, so I suggest following me, and the main repository will be updated about each release.

Further Reading

Creating a REST API Part 4: Handling POST, PUT and DELETE Requests

How to Create a REST API With Spring Boot

crud api, integration, java, microservices, model driven development, opensource, rest api, restful, spring, swagger

Published at DZone with permission of Andrea Tarquini . See the original article here.

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}