Rust GraphQL demo/test API written in Rust, using Axum for routing, async-graphql and SQLx.
For Rust developers building a GraphQL API, considering using Axum and async-graphql.
APIs are minimal and represent a blog site back-end, with GraphQL queries to create and delete draft posts, as well as, publish them.
The app is based on How to Build a Powerful GraphQL API with Rust by Oliver Jumpertz, updated to use Axum 0.8. It also has more extensive observability, implemented using OpenTelemetry. Data are pushed from the app to an OpenTelemetry collector, which in turn:
- has a Prometheus metrics endpoint;
- pushes traces to a Jaeger collector, which exposes a Jaeger Query UI endpoint; and
- exports logs to a Loki endpoint.
OpenTelemetry collector, Prometheus, Jaeger Collector, Jaeger Query and Loki all
get spun up via docker-compose
. Additionally, the
docker-compose configuration initialises a Grafana session (collecting all
previously mentioned observability components into a single interface).
- Introduction
- Spinning up the app
- App and Observability Endpoints
- What’s inside?
- Why did I create this?
- What this is not
- Issues and Support
- Contributions
- Acknowledgements
- License
Requires:
- Rust 1.86 toolchain or newer; and
- docker-compose.
-
Clone this repo and change into the new directory.
-
Start the observability services with docker-compose:
docker compose up -d
-
Start the app with
cargo run
. The app will create the SQLite database file and run database migrations in themigrations
directory. -
Open a browser window at
http://localhost:8000
to bring up the GraphQL Playground and run some queries. -
The observability services might take a few moments to spin up, and in this case you will see Terminal output:
OpenTelemetry trace error occurred. Exporter otlp encountered the following error(s): the grpc server returns error (The service is currently unavailable): , detailed error message: tcp connect error: Connection refused (os error 61)
This should be temporary.
The project database migrations create an SQLite database with a Post table,
which has id
, title
, body
and published
fields. You can run GraphQL
queries to create, read, update and delete from this table.
- Hello world:
query HelloQuery {
hello
}
- Create a draft:
mutation CreateDraftMutation {
createDraft(title: "Post working title", body: "Draft body text") {
id
title
}
}
- Delete a draft:
mutation DeleteDraftMutation {
deleteDraft(id: 1) {
__typename
... on DeleteDraftSuccessResponse {
post {
id
title
}
}
... on DeleteDraftErrorResponse {
error {
field
message
received
}
}
}
}
- List existing drafts:
query DraftsQuery {
drafts {
id
title
}
}
GraphQL Playground: http://localhost:8000/
Metrics raw output: http://localhost:8889/metrics
Jaeger Query UI: http://localhost:16686/search
Grafana: http://localhost:3000/
The tracing service is provided via the OpenTelemetry Collector, Jaeger Query UI and a Cassandra database, all running in Docker. Docker also spins up a Cassandra database for storing traces.
The API uses an SQLite single-file database for simplicity, at
sqlite.db
. This is automatically created (if it does not yet
exist) when the app spins up.
The repo is just intended as a reference to speed up creating am Axum-based GraphQL API with observability features.
- A production-ready app.
- Guide to using Axum, async-graphql or SQLx that covers every feature.
- To learn more about async-graphql, see:
- Axum also has great resource, including:
- axum docs; and
- axum examples.
- For SQLx resources, see:
- For a general introduction to building a web-based API in Rust, Zero to Production in Rust is marvellous.
Open an issue if something does not work as expected or if you have some improvements.
Feel free to jump into the Rodney Lab matrix chat room.
Contributions welcome, write a short issue with your idea, before spending to much time on more involved additions.
- Before working on a new feature it's preferable to submit a feature request first and state that you'd like to implement it yourself
- Please don't submit PRs for feature requests that are either in the roadmap[1], backlog[2] or icebox[3]
- Avoid introducing new dependencies
- Avoid making backwards-incompatible configuration changes
[1] [2] [3]
[1] The feature likely already has work put into it that may conflict with your implementation
[2] The demand, implementation or functionality for this feature is not yet clear
[3] No plans to add this feature for the time being
Inspired by:
The project is released under the BSD 3-Clause License — see the LICENSE file for details.