{"id":13513754,"url":"https://github.com/graphql-crystal/graphql","last_synced_at":"2025-04-05T02:06:02.423Z","repository":{"id":41855744,"uuid":"277227369","full_name":"graphql-crystal/graphql","owner":"graphql-crystal","description":"GraphQL server library for Crystal","archived":false,"fork":false,"pushed_at":"2025-02-19T18:50:35.000Z","size":1799,"stargazers_count":137,"open_issues_count":7,"forks_count":13,"subscribers_count":7,"default_branch":"main","last_synced_at":"2025-03-29T01:06:43.985Z","etag":null,"topics":["crystal","graphql"],"latest_commit_sha":null,"homepage":"https://graphql-crystal.github.io/graphql/index.html","language":"Crystal","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/graphql-crystal.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-07-05T03:56:40.000Z","updated_at":"2025-03-21T21:59:41.000Z","dependencies_parsed_at":"2024-05-18T17:32:13.456Z","dependency_job_id":"f422bd24-4bc1-462f-a47d-891e5cc5a3c2","html_url":"https://github.com/graphql-crystal/graphql","commit_stats":{"total_commits":130,"total_committers":10,"mean_commits":13.0,"dds":0.3615384615384616,"last_synced_commit":"72d68deb6b25d513658c3748e0fb40871d77666e"},"previous_names":[],"tags_count":7,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/graphql-crystal%2Fgraphql","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/graphql-crystal%2Fgraphql/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/graphql-crystal%2Fgraphql/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/graphql-crystal%2Fgraphql/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/graphql-crystal","download_url":"https://codeload.github.com/graphql-crystal/graphql/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247276163,"owners_count":20912288,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["crystal","graphql"],"created_at":"2024-08-01T05:00:37.145Z","updated_at":"2025-04-05T02:06:02.391Z","avatar_url":"https://github.com/graphql-crystal.png","language":"Crystal","readme":"![Logo](assets/logo.svg)\n\nGraphQL server library for Crystal.\n\n- **Boilerplate-free**: Schema generated at compile time\n- **Type-safe**: Crystal guarantees your code matches your schema\n- **High performance**: See [benchmarks](https://github.com/graphql-crystal/benchmarks)\n\n## Getting Started\n\nInstall the shard by adding the following to our `shard.yml`:\n\n```yaml\ndependencies:\n  graphql:\n    github: graphql-crystal/graphql\n```\n\nThen run `shards install`.\n\nThe first step is to define a query object. This is the root type for all\nqueries and it looks like this:\n\n```crystal\nrequire \"graphql\"\n\n@[GraphQL::Object]\nclass Query \u003c GraphQL::BaseQuery\n  @[GraphQL::Field]\n  def hello(name : String) : String\n    \"Hello, #{name}!\"\n  end\nend\n```\n\nNow we can create a schema object:\n\n```crystal\nschema = GraphQL::Schema.new(Query.new)\n```\n\nTo verify we did everything correctly, we can print out the schema:\n\n```crystal\nputs schema.document.to_s\n```\n\nWhich, among several built-in types, prints our query type:\n\n```graphql\ntype Query {\n  hello(name: String!): String!\n}\n```\n\nTo serve our API over HTTP we call `schema.execute` with the request parameters and receive a JSON string. Here is an example for Kemal:\n\n```crystal\npost \"/graphql\" do |env|\n  env.response.content_type = \"application/json\"\n\n  query = env.params.json[\"query\"].as(String)\n  variables = env.params.json[\"variables\"]?.as(Hash(String, JSON::Any)?)\n  operation_name = env.params.json[\"operationName\"]?.as(String?)\n\n  schema.execute(query, variables, operation_name)\nend\n```\n\nNow we're ready to query our API:\n\n```bash\ncurl \\\n  -X POST \\\n  -H \"Content-Type: application/json\" \\\n  --data '{ \"query\": \"{ hello(name: \\\"John Doe\\\") }\" }' \\\n  http://0.0.0.0:3000/graphql\n```\n\nThis should return:\n\n```json\n{ \"data\": { \"hello\": \"Hello, John Doe!\" } }\n```\n\nFor easier development, we recommend using [GraphiQL](https://github.com/graphql/graphiql).\nA starter template combining Kemal and GraphiQL is found at [examples/graphiql](examples/graphiql).\n\n## Context\n\n`context` is a optional argument that our fields can retrieve. It lets fields\naccess global data, like database connections.\n\n```crystal\n# Define our own context type\nclass MyContext \u003c GraphQL::Context\n  @pi : Float64\n  def initialize(@pi)\n  end\nend\n\n# Pass it to schema.execute\ncontext = MyContext.new(Math::PI)\nschema.execute(query, variables, operation_name, context)\n\n# Access it in our fields\n@[GraphQL::Object]\nclass MyMath \u003c GraphQL::BaseObject\n  @[GraphQL::Field]\n  def pi(context : MyContext) : Float64\n    context.pi\n  end\nend\n```\n\nContext instances must not be reused for multiple executions.\n\n## Objects\n\nObjects are perhaps the most commonly used type in GraphQL. They are implemented\nas classes. To define a object, we need a `GraphQL::Object` annotation and to inherit\n`GraphQL::BaseObject`. Fields are methods with a `GraphQL::Field` annotation.\n\n```crystal\n@[GraphQL::Object]\nclass Foo \u003c GraphQL::BaseObject\n  # type restrictions are mandatory on fields\n  @[GraphQL::Field]\n  def hello(first_name : String, last_name : String) : String\n    \"Hello #{first_name} #{last_name}\"\n  end\n\n  # besides basic types, we can also return other objects\n  @[GraphQL::Field]\n  def bar : Bar\n    Bar.new\n  end\nend\n\n@[GraphQL::Object]\nclass Bar \u003c GraphQL::BaseObject\n  @[GraphQL::Field]\n  def baz : Float64\n    42_f64\n  end\nend\n```\n\nFor simple objects, we can use instance variables:\n\n```crystal\n@[GraphQL::Object]\nclass Foo \u003c GraphQL::BaseObject\n  @[GraphQL::Field]\n  property bar : String\n\n  @[GraphQL::Field]\n  getter baz : Float64\n\n  def initialize(@bar, @baz)\n  end\nend\n```\n\n## Query\n\nQuery is the root type of all queries.\n\n```crystal\n@[GraphQL::Object]\nclass Query \u003c GraphQL::BaseQuery\n  @[GraphQL::Field]\n  def echo(str : String) : String\n    str\n  end\nend\n\nschema = GraphQL::Schema.new(Query.new)\n```\n\n## Mutation\n\nMutation is the root type for all mutations.\n\n```crystal\n@[GraphQL::Object]\nclass Mutation \u003c GraphQL::BaseMutation\n  @[GraphQL::Field]\n  def echo(str : String) : String\n    str\n  end\nend\n\nschema = GraphQL::Schema.new(Query.new, Mutation.new)\n```\n\n## Input Objects\n\nInput objects are objects that are used as field arguments. To define an input\nobject, use a `GraphQL::InputObject` annotation and inherit `GraphQL::BaseInputObject`.\nIt must define a constructor with a `GraphQL::Field` annotation.\n\n```crystal\n@[GraphQL::InputObject]\nclass User \u003c GraphQL::BaseInputObject\n  getter first_name : String?\n  getter last_name : String?\n\n  @[GraphQL::Field]\n  def initialize(@first_name : String?, @last_name : String?)\n  end\nend\n```\n\n## Enums\n\nDefining enums is straightforward. Just add a `GraphQL::Enum` annotation:\n\n```crystal\n@[GraphQL::Enum]\nenum IPAddressType\n  IPv4\n  IPv6\nend\n```\n\n## Scalars\n\nThe following scalar values are supported:\n\n- `Int32` \u003c-\u003e `Int`\n- `Float64` \u003c-\u003e `Float`\n- `String` \u003c-\u003e `String`\n- `Bool` \u003c-\u003e `Boolean`\n- `GraphQL::Scalars::ID` \u003c-\u003e `String`\n\nBuilt-in custom scalars:\n\n- `GraphQL::Scalars::BigInt` \u003c-\u003e `String`\n\nCustom scalars are created by implementing from_json/to_json:\n\n```crystal\n@[GraphQL::Scalar]\nclass ReverseStringScalar \u003c GraphQL::BaseScalar\n  @value : String\n\n  def initialize(@value)\n  end\n\n  def self.from_json(string_or_io)\n    self.new(String.from_json(string_or_io).reverse)\n  end\n\n  def to_json(builder : JSON::Builder)\n    builder.scalar(@value.reverse)\n  end\nend\n```\n\n## Interfaces\n\nInterfaces are not supported.\n\n## Subscriptions\n\nSubscriptions are not supported.\n\n## Annotation Arguments\n\n### name\n\nSupported on: `Object`, `InputObject`, `Field`, `Enum`, `Scalar`\n\nWe can use the `name` argument to customize the introspection type name of a\ntype. This is not needed in most situations because type names are automatically\nconverted to PascalCase or camelCase. However, `item_id` converts to\n`itemId`, but we might want to use `itemID`. For this, we can use the `name`\nargument.\n\n```crystal\n@[GraphQL::Object(name: \"Sheep\")]\nclass Wolf\n  @[GraphQL::Field(name: \"baa\")]\n  def howl : String\n    \"baa\"\n  end\nend\n```\n\n### description\n\nSupported on: `Object`, `InputObject`, `Field`, `Enum`, `Scalar`\n\nDescribes the type. Descriptions are available through the introspection interface\nso it's always a good idea to set this argument.\n\n```crystal\n@[GraphQL::Object(description: \"I'm a sheep, I promise!\")]\nclass Wolf\nend\n```\n\n### deprecated\n\nSupported on: `Field`\n\nThe deprecated argument marks a type as deprecated.\n\n```crystal\nclass Sheep\n  @[GraphQL::Field(deprecated: \"This was a bad idea.\")]\n  def fight_wolf : String\n    \"Wolf ate sheep\"\n  end\nend\n```\n\n### arguments\n\nSets names and descriptions for field arguments. Note that\narguments cannot be marked as deprecated.\n\n```crystal\nclass Sheep\n  @[GraphQL::Field(arguments: {weapon: {name: \"weaponName\", description: \"The weapon the sheep should use.\"}})]\n  def fight_wolf(weapon : String) : String\n    if weapon == \"Atomic Bomb\"\n      \"Sheep killed wolf\"\n    else\n      \"Wolf ate sheep\"\n    end\n  end\nend\n```\n\n## Field Arguments\n\nField arguments are automatically resolved. A type with a default value becomes\noptional. A nilable type is also considered a optional type.\n","funding_links":[],"categories":["Crystal","Framework Components","Libraries","Implementations"],"sub_categories":["Crystal Libraries","Crystal"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgraphql-crystal%2Fgraphql","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgraphql-crystal%2Fgraphql","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgraphql-crystal%2Fgraphql/lists"}