Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

graphiti-api/graphiti

Repository files navigation

Graphiti

CI Gem Version Ruby Style Guide semantic-release: angular

discord guides

Graphiti logo

Graphiti is a resource-oriented framework that sits on top of your models (usually ActiveRecord) and exposes them via a JSON:API-compliant interface. It abstracts common concerns like serialization, filtering, sorting, pagination, and sideloading relationships, so you can build powerful APIs with minimal boilerplate. By defining resources instead of controllers and serializers, Graphiti helps you keep your API logic organized, consistent, and easy to maintain.

Examples

Here's an example resource from the example app just to give you a taste of the possibilities.

class EmployeeResource < ApplicationResource
 attribute :first_name, :string
 attribute :last_name, :string
 attribute :age, :integer
 attribute :created_at, :datetime, writable: false
 attribute :updated_at, :datetime, writable: false
 attribute :title, :string, only: [:filterable, :sortable]
 has_many :positions
 has_many :tasks
 many_to_many :teams
 polymorphic_has_many :notes, as: :notable
 has_one :current_position, resource: PositionResource do
 params do |hash|
 hash[:filter][:current] = true
 end
 end
 filter :title, only: [:eq] do
 eq do |scope, value|
 scope.joins(:current_position).merge(Position.where(title: value))
 end
 end
 sort :title do |scope, value|
 scope.joins(:current_position).merge(Position.order(title: value))
 end
 sort :department_name, :string do |scope, value|
 scope.joins(current_position: :department)
 .merge(Department.order(name: value))
 end
end

A pretty boilerplate controller that just interfaces with the resource

class EmployeesController < ApplicationController
 def index
 employees = EmployeeResource.all(params)
 respond_with(employees)
 end
 def show
 employee = EmployeeResource.find(params)
 respond_with(employee)
 end
 def create
 employee = EmployeeResource.build(params)
 if employee.save
 render jsonapi: employee, status: 201
 else
 render jsonapi_errors: employee
 end
 end
 def update
 employee = EmployeeResource.find(params)
 if employee.update_attributes
 render jsonapi: employee
 else
 render jsonapi_errors: employee
 end
 end
 def destroy
 employee = EmployeeResource.find(params)
 if employee.destroy
 render jsonapi: { meta: {} }, status: 200
 else
 render jsonapi_errors: employee
 end
 end
end

Now you can query your endpoints simply and powerfully, like:

Request: http://localhost:3000/api/v1/employees?filter[title][eq]=Future Government Administrator&filter[age][lt]=40

JSON-API response
{
 "data": [
 {
 "id": "1",
 "type": "employees",
 "attributes": {
 "first_name": "Quinn",
 "last_name": "Homenick",
 "age": 36,
 "created_at": "2025年03月21日T23:04:40+00:00",
 "updated_at": "2025年03月21日T23:04:40+00:00"
 },
 "relationships": {
 "positions": {
 "links": {
 "related": "/api/v1/positions?filter[employee_id]=1"
 },
 "data": [
 {
 "type": "positions",
 "id": "1"
 },
 {
 "type": "positions",
 "id": "2"
 }
 ]
 },
 "tasks": {
 "links": {
 "related": "/api/v1/tasks?filter[employee_id]=1"
 }
 },
 "teams": {
 "links": {
 "related": "/api/v1/teams?filter[employee_id]=1"
 }
 },
 "notes": {
 "links": {
 "related": "/api/v1/notes?filter[notable_id]=1&filter[notable_type][eql]=Employee"
 }
 },
 "current_position": {
 "links": {
 "related": "/api/v1/positions?filter[current]=true&filter[employee_id]=1"
 },
 "data": {
 "type": "positions",
 "id": "1"
 }
 }
 }
 }
 ],
 "included": [
 {
 "id": "1",
 "type": "positions",
 "attributes": {
 "title": "Future Government Administrator",
 "active": true
 },
 "relationships": {
 "employee": {
 "links": {
 "related": "/api/v1/employees/1"
 }
 },
 "department": {
 "links": {
 "related": "/api/v1/departments/3"
 }
 }
 }
 },
 {
 "id": "2",
 "type": "positions",
 "attributes": {
 "title": "Manufacturing Specialist",
 "active": false
 },
 "relationships": {
 "employee": {
 "links": {
 "related": "/api/v1/employees/1"
 }
 },
 "department": {
 "links": {
 "related": "/api/v1/departments/2"
 }
 }
 }
 }
 ],
 "meta": {}
}

Graphiti Guides

Join the Discord

AltStyle によって変換されたページ (->オリジナル) /