adapter.ex (4084B)
1 defmodule Absinthe.Adapter do 2 @moduledoc """ 3 Absinthe supports an adapter mechanism that allows developers to define their 4 schema using one code convention (eg, `snake_cased` fields and arguments), but 5 accept query documents and return results (including names in errors) in 6 another (eg, `camelCase`). 7 8 Adapters aren't a part of GraphQL, but a utility that Absinthe adds so that 9 both client and server can use use conventions most natural to them. 10 11 Absinthe ships with four adapters: 12 13 * `Absinthe.Adapter.LanguageConventions`, which expects schemas to be defined 14 in `snake_case` (the standard Elixir convention), translating to/from `camelCase` 15 for incoming query documents and outgoing results. (This is the default as of v0.3.) 16 * `Absinthe.Adapter.Underscore`, which is similar to the `Absinthe.Adapter.LanguageConventions` 17 adapter but converts all incoming identifiers to underscores and does not 18 modify outgoing identifiers (since those are already expected to be 19 underscores). Unlike `Absinthe.Adapter.Passthrough` this does not break 20 introspection. 21 * `Absinthe.Adapter.Passthrough`, which is a no-op adapter and makes no 22 modifications. (Note at the current time this does not support introspection 23 if you're using camelized conventions). 24 * `Absinthe.Adapter.StrictLanguageConventions`, which expects schemas to be 25 defined in `snake_case`, translating to `camelCase` for outgoing results. 26 This adapter requires incoming query documents to use `camelCase`. 27 28 To set an adapter, you pass a configuration option at runtime: 29 30 For `Absinthe.run/3`: 31 32 ``` 33 Absinthe.run( 34 query, 35 MyApp.Schema, 36 adapter: YourApp.Adapter.TheAdapterName 37 ) 38 ``` 39 40 For `Absinthe.Plug`: 41 42 ``` 43 forward "/api", 44 to: Absinthe.Plug, 45 init_opts: [schema: MyAppWeb.Schema, adapter: YourApp.Adapter.TheAdapterName] 46 ``` 47 48 For GraphiQL: 49 50 ``` 51 forward "/graphiql", 52 to: Absinthe.Plug.GraphiQL, 53 init_opts: [schema: MyAppWeb.Schema, adapter: YourApp.Adapter.TheAdapterName] 54 ``` 55 56 Check `Absinthe.Plug` for full documentation on using the Plugs 57 58 Notably, this means you're able to switch adapters on case-by-case basis. 59 In a Phoenix application, this means you could even support using different 60 adapters for different clients. 61 62 A custom adapter module must merely implement the `Absinthe.Adapter` protocol, 63 in many cases with `use Absinthe.Adapter` and only overriding the desired 64 functions. 65 66 ## Writing Your Own 67 68 All you may need to implement in your adapter is `to_internal_name/2` and 69 `to_external_name/2`. 70 71 Check out `Absinthe.Adapter.LanguageConventions` for a good example. 72 73 Note that types that are defined external to your application (including 74 the introspection types) may not be compatible if you're using a different 75 adapter. 76 """ 77 78 @type t :: module 79 80 defmacro __using__(_) do 81 quote do 82 @behaviour unquote(__MODULE__) 83 84 def to_internal_name(external_name, _role) do 85 external_name 86 end 87 88 def to_external_name(internal_name, _role) do 89 internal_name 90 end 91 92 defoverridable to_internal_name: 2, 93 to_external_name: 2 94 end 95 end 96 97 @typedoc "The lexical role of a name within the document/schema." 98 @type role_t :: :operation | :field | :argument | :result | :type | :directive 99 100 @doc """ 101 Convert a name from an external name to an internal name. 102 103 ## Examples 104 105 Prefix all names with their role, just for fun! 106 107 ``` 108 def to_internal_name(external_name, role) do 109 role_name = role |> to_string 110 role_name <> "_" <> external_name 111 end 112 ``` 113 """ 114 @callback to_internal_name(binary | nil, role_t) :: binary | nil 115 116 @doc """ 117 Convert a name from an internal name to an external name. 118 119 ## Examples 120 121 Remove the role-prefix (the inverse of what we did in `to_internal_name/2` above): 122 123 ``` 124 def to_external_name(internal_name, role) do 125 internal_name 126 |> String.replace(~r/^\#{role}_/, "") 127 end 128 ``` 129 """ 130 @callback to_external_name(binary | nil, role_t) :: binary | nil 131 end