ENotion is a Kotlin library for interacting with the Notion API, supporting the conversion of Notion database content into HTML format.
-
Database Query –
getDataBase
Query any Notion database with optional filter and sorts.
Each page is returned as a JSON object whosecontentfield already contains fully‑rendered HTML for all supported block types. -
Record Insertion –
insertRecord
Insert a row into a database while automatically converting Kotlin/SQL values to the correct Notion property structure, with optional markdownContent rendered as rich Notion blocks. -
Record Update –
updateRecord
Patch one or more columns of an existing page with the same automatic type handling as insertRecord, and optionally append converted Markdown content. -
Markdown Content Support –
markdownContent
TheinsertRecordandupdateRecordmethods now accept an optional markdownContent parameter.- Converts full Markdown (headings 1‑3, paragraphs, images, tables, lists, block quotes, horizontal rules, inline *
bold* / italic /
code, links, strike‑through) into native Notion blocks on‑the‑fly. - Images inside tables are automatically extracted and appended with captions to satisfy Notion API constraints.
- Supports an optional high‑fidelity converter via Node’s
@tryfabric/martianwhen available; otherwise falls back to the built‑in Kotlin converter. - Code blocks normalize languages to Notion’s allowed list and degrade to
plain textwhen unknown, preventing 400 validation errors.
- Converts full Markdown (headings 1‑3, paragraphs, images, tables, lists, block quotes, horizontal rules, inline *
bold* / italic /
-
Data image auto‑upload
Markdowndata:image/...;base64,...blobs are uploaded automatically via Notion's Direct Upload API and rendered asfile_uploadimage blocks. Optionally provide adataImageUploadercallback to override the behaviour and return anexternalUrlorfileUploadId. On failure the content falls back to a paragraph to avoid Notion validation errors. -
HTML Rendering & Safety
HTML output fromgetDataBaseescapes text and attributes and usesrel="noopener noreferrer"on links. -
Video Blocks
getDataBaserenders Notionvideoblocks with a default 640x360 footprint, streaming uploaded files via<video>and auto-converting YouTube/Vimeo links into embeddable<iframe>players (falling back to external links for other providers). -
Workspace Search –
findNotionDatabase
Locate a database by its exact title and return its ID. -
Database Creation –
createNotionDatabase
Programmatically create a brand‑new database with a custom schema under any parent page. -
Schema Management –
ensureDatabaseSchema
Compare the remote schema with local column definitions and add any missing properties on‑the‑fly. -
Timestamp Helper –
getLatestTimestamp
Quickly obtain the newest ISO date stored in a designated date column (useful for incremental sync). -
Miscellaneous Utilities
Helpers for reading a database’spropertiesobject, mapping SQL types to Notion types, and extracting primitive values from Notion properties.
Add ENotion to your project and initialize it with your Notion API key:
import easy.notion.ENotion
import java.io.FileInputStream
import java.util.Properties
fun main() {
val props = Properties().apply { load(FileInputStream("config.properties")) }
val notion = ENotion(props.getProperty("NOTIONKEY"))
println(notion.getDataBase("your_database_id"))
}val dbId = notion.findNotionDatabase("My Tasks")
if (dbId == null) println("Database not found") else println("ID = $dbId")val newDbId = notion.createNotionDatabase(
pageId = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", // parent page
databaseName = "Log Entries",
columns = mapOf("Level" to "select", "Message" to "rich_text"),
timeField = "Created",
primaryKey = "ID",
)// insert (with Markdown body)
notion.insertRecord(
databaseId = newDbId!!,
markdownContent = """
# Welcome
This record was **created** via *ENotion*.
---
| Picture | Description |
|:------:|-------------|
|  | Cute kitten |
""".trimIndent(),
"ID" to "42",
"Level" to "INFO",
"Message" to "Application started",
"Created" to "2025-05-25 10:00:00",
)
// update (patch fields + append more Markdown)
notion.updateRecord(
databaseId = newDbId,
pageId = "pppppppppppppppppppppppppppppppp",
markdownContent = "- **现价**:¥208",
"Level" to "ERROR",
"Message" to "Oops, something went wrong",
)
// Optional: data image auto‑upload (custom uploader example)
val notionWithUploader = ENotion(
apikey = props.getProperty("NOTIONKEY"),
dataImageUploader = { mime, bytes, suggestedName ->
// Upload bytes to your hosting and return an https URL. Example only:
val url = myUpload(bytes, suggestedName ?: "image", mime) // implement yourself
if (url != null) ENotion.DataImageUploadResult(externalUrl = url) else null
}
)val ok = notion.ensureDatabaseSchema(
databaseId = newDbId,
localColumns = mapOf("ID" to "VARCHAR", "Level" to "VARCHAR", "Detail" to "TEXT"),
timeField = "Created",
primaryKey = "ID",
)Convert Notion database content to HTML:
<style>
hr { border: none; border-top: 1px solid #E1E3E5; margin: 16px 0; }
table { border-collapse: collapse; border: 1px solid #E1E3E5; }
th, td { border: 1px solid #E1E3E5; padding: 8px; text-align: left; }
thead th { background-color: #f2f2f2; }
tbody th { background-color: #f2f2f2; }
img { max-width: 600px; }
a { text-decoration: underline; }
pre { background: #f5f5f5; padding: 10px; border-radius: 3px; overflow: auto; }
pre code { background: transparent; padding: 0; }
code { background: #f5f5f5; padding: 2px 4px; border-radius: 3px; font-family: monospace; }
</style>
<p>Sample paragraph content</p>
<h1>Sample Heading</h1>
<ul>
<li>Sample list item</li>
</ul>
<table style="width:600px;">
<thead>
<tr>
<th>Header 1</th>
<th>Header 2</th>
</tr>
</thead>
<tbody>
<tr>
<td>Cell 1</td>
<td>Cell 2</td>
</tr>
</tbody>
</table>The library automatically prepends a lightweight default stylesheet (visible in the snippet above) so the HTML is ready for direct embedding.
Note
When you supply markdownContent to insertRecord / updateRecord, ENotion converts the Markdown to Notion blocks first, so the HTML produced bygetDataBasewill precisely match your original Markdown—including images, tables, and dividers.
Create a config.properties file in the project root directory and add the following content:
NOTIONKEY=your_notion_api_key
# Optional for examples
# DATABASEID=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Optional: for high‑fidelity Markdown conversion, install Node and Martian globally:
npm i -g @tryfabric/martian
- Language: Kotlin
- HTTP: OkHttp 4.x
- JSON: org.json
- Build Tool: Gradle (Maven optional)
- Build:
./gradlew build - Run tests only:
./gradlew test - Publish to local Maven:
./gradlew publishMavenJavaPublicationToMavenLocal
For a quick online example (manual, not a unit test), run src/test/kotlin/TestNotionTools.kt in your IDE with a valid
config.properties in the project root.
- Ensure that the
config.propertiesfile is not committed to version control (already configured in.gitignore). - Make sure the Notion API key and database ID are valid before use.
This project is licensed under the MIT License.