• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    迪恩网络公众号

graphql-crystal/graphql: GraphQL server library for Crystal

原作者: [db:作者] 来自: 网络 收藏 邀请

开源软件名称(OpenSource Name):

graphql-crystal/graphql

开源软件地址(OpenSource Url):

https://github.com/graphql-crystal/graphql

开源编程语言(OpenSource Language):

Crystal 99.6%

开源软件介绍(OpenSource Introduction):

Logo

GraphQL server library for Crystal.

  • Boilerplate-free: Schema generated at compile time
  • Type-safe: Crystal guarantees your code matches your schema
  • High performance: See benchmarks

Getting Started

Install the shard by adding the following to our shard.yml:

dependencies:
  graphql:
    github: graphql-crystal/graphql

Then run shards install.

The first step is to define a query object. This is the root type for all queries and it looks like this:

require "graphql"

@[GraphQL::Object]
class Query < GraphQL::BaseQuery
  @[GraphQL::Field]
  def hello(name : String) : String
    "Hello, #{name}!"
  end
end

Now we can create a schema object:

schema = GraphQL::Schema.new(Query.new)

To verify we did everything correctly, we can print out the schema:

puts schema.document.to_s

Which, among several built-in types, prints our query type:

type Query {
  hello(name: String!): String!
}

To serve our API over HTTP we call schema.execute with the request parameters and receive a JSON string. Here is an example for Kemal:

post "/graphql" do |env|
  env.response.content_type = "application/json"

  query = env.params.json["query"].as(String)
  variables = env.params.json["variables"]?.as(Hash(String, JSON::Any)?)
  operation_name = env.params.json["operationName"]?.as(String?)

  schema.execute(query, variables, operation_name)
end

Now we're ready to query our API:

curl \
  -X POST \
  -H "Content-Type: application/json" \
  --data '{ "query": "{ hello(name: \"John Doe\") }" }' \
  http://0.0.0.0:3000/graphql

This should return:

{ "data": { "hello": "Hello, John Doe!" } }

For easier development, we recommend using GraphiQL. A starter template combining Kemal and GraphiQL is found at examples/graphiql.

Context

context is a optional argument that our fields can retrieve. It lets fields access global data, like database connections.

# Define our own context type
class MyContext < GraphQL::Context
  @pi : Float64
  def initialize(@pi)
  end
end

# Pass it to schema.execute
context = MyContext.new(Math.PI)
schema.execute(query, variables, operation_name, context)

# Access it in our fields
@[GraphQL::Object]
class MyMath < GraphQL::BaseObject
  @[GraphQL::Field]
  def pi(context : MyContext) : Float64
    context.pi
  end
end

Context instances must not be reused for multiple executions.

Objects

Objects are perhaps the most commonly used type in GraphQL. They are implemented as classes. To define a object, we need a GraphQL::Object annotation and to inherit GraphQL::BaseObject. Fields are methods with a GraphQL::Field annotation.

@[GraphQL::Object]
class Foo < GraphQL::BaseObject
  # type restrictions are mandatory on fields
  @[GraphQL::Field]
  def hello(first_name : String, last_name : String) : String
    "Hello #{first_name} #{last_name}"
  end

  # besides basic types, we can also return other objects
  @[GraphQL::Field]
  def bar : Bar
    Bar.new
  end
end

@[GraphQL::Object]
class Bar < GraphQL::BaseObject
  @[GraphQL::Field]
  def baz : Float64
    42_f64
  end
end

For simple objects, we can use instance variables:

@[GraphQL::Object]
class Foo < GraphQL::BaseObject
  @[GraphQL::Field]
  property bar : String

  @[GraphQL::Field]
  getter baz : Float64
end

Query

Query is the root type of all queries.

@[GraphQL::Object]
class Query < GraphQL::BaseQuery
  @[GraphQL::Field]
  def echo(str : String) : String
    str
  end
end

schema = GraphQL::Schema.new(Query.new)

Mutation

Mutation is the root type for all mutations.

@[GraphQL::Object]
class Mutation < GraphQL::BaseMutation
  @[GraphQL::Field]
  def echo(str : String) : String
    str
  end
end

schema = GraphQL::Schema.new(Query.new, Mutation.new)

Input Objects

Input objects are objects that are used as field arguments. To define an input object, use a GraphQL::InputObject annotation and inherit GraphQL::BaseInputObject. It must define a constructor with a GraphQL::Field annotation.

@[GraphQL::InputObject]
class User < GraphQL::BaseInputObject
  getter first_name : String?
  getter last_name : String?

  @[GraphQL::Field]
  def initialize(@first_name : String?, @last_name : String?)
  end
end

Enums

Defining enums is straightforward. Just add a GraphQL::Enum annotation:

@[GraphQL::Enum]
enum IPAddressType
  IPv4
  IPv6
end

Scalars

The following scalar values are supported:

  • Int32 <-> Int
  • Float64 <-> Float
  • String <-> String
  • Bool <-> Boolean
  • GraphQL::Scalars::ID <-> String

Built-in custom scalars:

  • GraphQL::Scalars::BigInt <-> String

Custom scalars are created by implementing from_json/to_json:

@[GraphQL::Scalar]
class ReverseStringScalar < GraphQL::BaseScalar
  @value : String

  def initialize(@value)
  end

  def self.from_json(string_or_io)
    self.new(String.from_json(string_or_io).reverse)
  end

  def to_json(builder : JSON::Builder)
    builder.scalar(@value.reverse)
  end
end

Interfaces

Interfaces are not supported.

Subscriptions

Subscriptions are not supported.

Annotation Arguments

name

Supported on: Object, InputObject, Field, Enum, Scalar

We can use the name argument to customize the introspection type name of a type. This is not needed in most situations because type names are automatically converted to PascalCase or camelCase. However, item_id converts to itemId, but we might want to use itemID. For this, we can use the name argument.

@[GraphQL::Object(name: "Sheep")]
class Wolf
  @[GraphQL::Field(name: "baa")]
  def howl : String
    "baa"
  end
end

description

Supported on: Object, InputObject, Field, Enum, Scalar

Describes the type. Descriptions are available through the introspection interface so it's always a good idea to set this argument.

@[GraphQL::Object(description: "I'm a sheep, I promise!")]
class Wolf
end

deprecated

Supported on: Field

The deprecated argument marks a type as deprecated.

class Sheep
  @[GraphQL::Field(deprecated: "This was a bad idea.")]
  def fight_wolf : String
    "Wolf ate sheep"
  end
end

arguments

Sets names and descriptions for field arguments. Note that arguments cannot be marked as deprecated.

class Sheep
  @[GraphQL::Field(arguments: {weapon: {name: "weaponName", description: "The weapon the sheep should use."}})]
  def fight_wolf(weapon : String) : String
    if weapon == "Atomic Bomb"
      "Sheep killed wolf"
    else
      "Wolf ate sheep"
    end
  end
end

Field Arguments

Field arguments are automatically resolved. A type with a default value becomes optional. A nilable type is also considered a optional type.




鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
热门推荐
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap