
Baeldung Pro comes with both absolutely No-Ads as well as finally with Dark Mode, for a clean learning experience:
Once the early-adopter seats are all used, the price will go up and stay at $33/year.
Last updated: May 15, 2025
RESTHeart is a Java-based framework that lets us quickly build HTTP APIs on top of MongoDB. It enables us to expose the MongoDB collections as REST and GraphQL APIs with minimal setup, while still allowing us to control things as needed.
In this tutorial, we’re going to take a quick look at the RESTHeart API Framework.
RESTHeart provides an open-source API server built on top of MongoDB. It automatically exposes our collections as REST and GraphQL endpoints, allowing us to create APIs without needing to write any code.
Out of the box, we get:
This provides a zero-code solution for building HTTP-based APIs, enabling rapid implementation. When needed, we can also integrate custom Java code for extra functionality that’s not possible out of the box.
If we want to run RESTHeart locally, we’ll need a working installation of Java 21 or higher. Additionally, we’ll need to download the RESTHeart distribution. Once this is downloaded and unpacked, we can immediately start the service by running restheart.jar:
$ java -jar restheart.jar
17:39:17.943 [main] INFO org.restheart.Bootstrapper - Starting RESTHeart instance default
17:39:17.945 [main] INFO org.restheart.Bootstrapper - Version 8.4.0
.....
17:39:19.188 [main] INFO org.restheart.Bootstrapper - RESTHeart started
With no configuration, this will attempt to use a MongoDB that’s accessible on 127.0.0.1:27017 and which requires no credentials.
Alternatively, a Docker image is provided that can be used to run RESTHeart. This also enables us to run a Docker Compose setup that includes MongoDB, so it can all start as a single stack. For this, we need a docker-compose.yml file:
$ cat docker-compose.yml
services:
mongodb:
image: mongo:latest
container_name: mongodb
ports:
- "27017:27017"
networks:
- mongo-restheart-network
restheart:
image: softinstigate/restheart:latest
container_name: restheart
ports:
- "8080:8080"
networks:
- mongo-restheart-network
environment:
MONGO_URI: mongodb://mongodb:27017
depends_on:
- mongodb
networks:
mongo-restheart-network:
driver: bridge
We can then start the services with docker compose, and we’re ready to go:
$ docker compose up -d
[+] Running 3/3
Network restheart_mongo-restheart-network Created
Container mongodb Started
Container restheart Started
Once everything has started, we can test the setup by calling the /ping endpoint on our server:
$ curl localhost:8080/ping
{"message": "Greetings from RESTHeart!", "client_ip": "192.168.65.1", "host": "localhost:8080", "version": "8.4.0"}
At this point, we’ve got a fully functional service.
Most of the API calls made to our RESTHeart service require authentication, which RESTHeart handles automatically. For example, if we make an unauthenticated request to the root resource, then we’ll get an HTTP 401 Unauthorized response back:
$ curl -v localhost:8080/
> GET / HTTP/1.1
>
< HTTP/1.1 401 Unauthorized
< WWW-Authenticate: Basic realm="RESTHeart Realm"
By default, user records are all managed within our MongoDB database, in the users collection. If we start RESTHeart up against an empty database, this collection will be automatically created, and a single admin user will be added to it:
Although the password is securely hashed and can’t be viewed, the default credentials consist of the username admin and the password secret. We can now make our request again using these credentials:
$ curl -v -u admin:secret localhost:8080/
> GET / HTTP/1.1
> Authorization: Basic YWRtaW46c2VjcmV0
>
< HTTP/1.1 200 OK
< Content-Type: application/json
<
["acl", "users"]
This now works correctly, and we get the expected response.
RESTHeart automatically exposes MongoDB collections from our database so that we can read and manipulate them via standard REST and GraphQL APIs with minimal effort.
RESTHeart exposes a REST API with a standard set of URL patterns for each collection:
We can also create a new collection by sending a special request. To do this, we issue a PUT request directly to the collection’s endpoint:
$ curl -v -u admin:secret -X PUT localhost:8080/posts
> PUT /posts HTTP/1.1
>
< HTTP/1.1 200 OK
< Content-Type: application/json
< Content-Length: 0
<
Once we’ve got a collection, let’s create a new record in it using a POST request:
$ curl -v -u admin:secret -X POST localhost:8080/posts -d '{"title": "Introduction to RESTHeart", "author": "Baeldung"}' -H "Content-Type: application/json"
> POST /posts HTTP/1.1
> Content-Type: application/json
> Content-Length: 60
>
< HTTP/1.1 201 Created
< Location: http://localhost:8080/posts/681a139012d5c00fcb674298
This doesn’t return the actual record, but it does give us a Location header pointing to it. This is also visible directly in the database:
We can then retrieve this record using a GET request while specifying the ID:
$ curl -v -u admin:secret localhost:8080/posts/681a139012d5c00fcb674298
> GET /posts/681a139012d5c00fcb674298 HTTP/1.1
>
< HTTP/1.1 200 OK
< Content-Type: application/json
< Content-Length: 152
<
{
"_id": { "$oid": "681a139012d5c00fcb674298" },
"title": "Introduction to RESTHeart",
"author": "Baeldung",
"_etag": { "$oid": "681a139012d5c00fcb674297" }
}
We can also select the entire collection by using a GET request to the collection as a whole:
$ curl -v -u admin:secret localhost:8080/posts
> GET /posts HTTP/1.1
>
< HTTP/1.1 200 OK
< Content-Type: application/json
< Content-Length: 154
<
[
{
"_id": { "$oid": "681a139012d5c00fcb674298" },
"title": "Introduction to RESTHeart",
"author": "Baeldung",
"_etag": { "$oid": "681a139012d5c00fcb674297" }
}
]
As expected, we can also update and delete these records using PUT, PATCH, and DELETE calls:
$ curl -v -u admin:secret -X PUT localhost:8080/posts/681a139012d5c00fcb674298 -H "Content-Type: application/json" -d '{"title": "Intro to RESTHeart", "author": "Baeldung"}'
> PUT /posts/681a139012d5c00fcb674298 HTTP/1.1
> Content-Type: application/json
> Content-Length: 53
>
< HTTP/1.1 200 OK
< Content-Type: application/json
< Content-Length: 0
<
None of these return the result, but it’s immediately available if we query again.
In addition to a REST API, RESTHeart also enables us to expose our data via a GraphQL API. Unlike with the REST API, this needs some initial configuration to make everything work as desired.
All of the GraphQL APIs are defined by records in the gql-apps collection. So the first thing we need to do is to create this:
$ curl -v -u admin:secret -X PUT localhost:8080/gql-apps
We then need to create a special record in this collection containing our GraphQL API definition. To create an API that exposes the Posts we’ve been working with, the configuration would look something like this:
$ cat posts.schema
{
"_id": "restheart-posts",
"descriptor": {
"name": "restheart-posts",
"description": "RESTHeart Tutorial",
"enabled": true,
"uri": "restheart-posts"
},
"schema": "type Post { title: String author: String } type Query { posts: [Post] }",
"mappings": {
"Post": {
"name": "name",
"author": "author"
},
"Query": {
"posts": {
"db": "restheart",
"collection": "posts"
}
}
}
}
The descriptor field gives some definitions that RESTHeart uses to manage the API. The most important part here is the uri field, which we’ll use shortly. The schema field here is the full GraphQL Schema definition for our API, written in the GraphQL Schema Definition Language. The mappings field tells RESTHeart how to map between the GraphQL API and the MongoDB collections. In this case, we define a Post type with name and author fields and a Query type with a posts field that maps to the posts collection in our database.
We then create this record in the same way as before:
$ curl -v -u admin:secret -X POST localhost:8080/gql-apps -d "@posts.schema" -H "Content-Type: application/json"
Once we’ve done this, our GraphQL API is ready to use. We’ve set our uri field to restheart-posts, which means our API is exposed on /graphql/restheart-posts:
$ curl -v -u admin:secret -X POST localhost:8080/graphql/restheart-posts -d "{ posts { title author } }" -H "Content-Type: application/graphql"
> POST /graphql/restheart-posts HTTP/1.1
> Content-Type: application/graphql
> Content-Length: 26
>
* upload completely sent off: 26 bytes
< HTTP/1.1 200 OK
< Content-Type: application/graphql-response+json
< Content-Length: 83
<
{
"data": {
"posts": [
{
"title": "Intro to RESTHeart",
"author": "Baeldung"
}
]
}
}
We can immediately see this is the same data that our REST API was managing.
In this article, we’ve taken a very brief look at RESTHeart and what we can do with it. There’s a lot more that can be achieved using this framework, so the next time you need to create an HTTP API, it’s well worth a look.