Skip to content

Commit

Permalink
Merge branch 'master' into issues/918
Browse files Browse the repository at this point in the history
  • Loading branch information
benwilson512 authored May 13, 2023
2 parents 9b0cb1c + 086393b commit 8b004d2
Show file tree
Hide file tree
Showing 67 changed files with 892 additions and 196 deletions.
13 changes: 4 additions & 9 deletions .github/workflows/elixir.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,24 +9,19 @@ on:
jobs:
test:
name: Elixir ${{matrix.elixir}} / OTP ${{matrix.otp}}
runs-on: ubuntu-latest
runs-on: ubuntu-20.04

strategy:
matrix:
elixir:
- "1.10"
- "1.11"
- "1.12"
- "1.13"
- "1.14"
otp:
- "22"
- "23"
- "24"
exclude:
- elixir: "1.10"
otp: "24"
include:
- elixir: "1.13"
- elixir: "1.14"
otp: "24"
format: true

Expand All @@ -35,7 +30,7 @@ jobs:
uses: actions/checkout@v2

- name: Set up Elixir
uses: erlef/setup-elixir@v1
uses: erlef/setup-beam@v1
with:
elixir-version: ${{ matrix.elixir }}
otp-version: ${{ matrix.otp }}
Expand Down
13 changes: 12 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,30 @@

- Bug Fix: [Validate type references for invalid wrapped types](https://github.com/absinthe-graphql/absinthe/pull/1195)
- Feature: [Add `specifiedBy` type system directive](https://github.com/absinthe-graphql/absinthe/pull/1193)
- Bug Fix: [Object type extensions may be empty](https://github.com/absinthe-graphql/absinthe/pull/1228)
- Bug Fix: [Validate input object not being an Enum](https://github.com/absinthe-graphql/absinthe/pull/1231)
- Bug Fix: [Deduplicate directives when building schema](https://github.com/absinthe-graphql/absinthe/pull/1242)

## 1.7.1
- Breaking Bugfix: [Validate repeatable directives on schemas](https://github.com/absinthe-graphql/absinthe/pull/1179)
- Breaking Bugfix: [Add "Objects must define fields" schema validation](https://github.com/absinthe-graphql/absinthe/pull/1167)
- Bug Fix: [Validate field identifier uniqueness](https://github.com/absinthe-graphql/absinthe/pull/1200)
- Bug Fix: [Validate type references for invalid wrapped types](https://github.com/absinthe-graphql/absinthe/pull/1195)
- Bug Fix: Adds **optional fix** for non compliant built-in scalar Int type. `use Absinthe.Schema, use_spec_compliant_int_scalar: true` in your schema to use the fixed Int type. It is also advisable to upgrade for custom types if you are leveraging the use of integers outside the GraphQl standard. [#1131](https://github.com/absinthe-graphql/absinthe/pull/1131).
- Feature: [Support error tuples when scalar parsing fails](https://github.com/absinthe-graphql/absinthe/pull/1187)
- Feature: [Convert SDL Language.\* structs to SDL notation](https://github.com/absinthe-graphql/absinthe/pull/1160)
- Feature: [Support passing the resolution struct to dataloader helper callbacks](https://github.com/absinthe-graphql/absinthe/pull/1211)
- Feature: [Add support for type extensions](https://github.com/absinthe-graphql/absinthe/pull/1157)
- Bug Fix: [Add type system directives to introspection results](https://github.com/absinthe-graphql/absinthe/pull/1189)
- Bug Fix: [Add `__private__` field to EnumValueDefinition](https://github.com/absinthe-graphql/absinthe/pull/1148)
- Bug Fix: [Fix bug in Schema.**absinthe_types**(:all) for Persistent Term](https://github.com/absinthe-graphql/absinthe/pull/1161)
- Bug Fix: [Fix default enum value check for SDL schema's](https://github.com/absinthe-graphql/absinthe/pull/1188)
- Bug Fix: [Add "Objects must define fields" schema validation](https://github.com/absinthe-graphql/absinthe/pull/1167)
- Feature: [Add `import_directives` macro](https://github.com/absinthe-graphql/absinthe/pull/1158)
- Feature: [Support type extensions on schema declarations](https://github.com/absinthe-graphql/absinthe/pull/1176)
- Bug Fix: [Root objects are marked as referenced correctly](https://github.com/absinthe-graphql/absinthe/pull/1186)
- Bug Fix: [Prevent DDOS attacks with long queries](https://github.com/absinthe-graphql/absinthe/pull/1220)
- Feature: [pipeline_modifier option to Absinthe.run/3](https://github.com/absinthe-graphql/absinthe/pull/1221)
- Bug Fix: [Add end_time_mono to telemetry :stop events](https://github.com/absinthe-graphql/absinthe/pull/1174)

## 1.7.0

Expand Down
24 changes: 22 additions & 2 deletions guides/complexity-analysis.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,19 @@
# Complexity Analysis
# Safety Limits

A misbehaving client might send a very complex GraphQL query that would require
considerable resources to handle. In order to protect against this scenario, the
considerable resources to handle. There are two variations of this problem:

- Complex queries that overwhelm resolution resources.
- Extremely long queries that could take considerable resources to parse.
(For example, an attacker could craft a long query including thousands of
undefined fields or directives.)

Either of these could be a vector for a denial-of-service attack in any GraphQL
service. Absinthe includes mechanisms to protect services each of these.

## Complexity Analysis

To protect against queries that could overwhelm available resources, the
complexity of a query can be estimated before it is resolved and limited to a
specified maximum.

Expand Down Expand Up @@ -105,3 +117,11 @@ But this, at a complexity of `60`, wouldn't:
If a document's calculated complexity exceeds the configured limit, resolution
will be skipped and an error will be returned in the result detailing the
calculated and maximum complexities.

## Token Limits

To protect a service from invalid queries that could take considerable resources to parse,
Absinthe offers the option to configure a maximum limit on tokens in the GraphQL request document.
If the lexer encounters more tokens than this, it will stop the parse phase and return a phase error
with the message `"Token limit exceeded"`. This limit is `:infinity` by default (no limit)
and can be overridden by providing an integer to the option `token_limit` to `Absinthe.run`.
6 changes: 0 additions & 6 deletions guides/introspection.md
Original file line number Diff line number Diff line change
Expand Up @@ -123,9 +123,3 @@ end
If you'd prefer to use a desktop application, we recommend using the pre-built
[Electron](https://electron.atom.io)-based wrapper application,
[GraphiQL.app](https://github.com/skevy/graphiql-app).

### GraphQL Hub

[GraphQL Hub](https://www.graphqlhub.com/) is an interesting website that you
can use to introspect a number of public GraphQL servers, using GraphiQL in the
browser and providing useful examples.
9 changes: 9 additions & 0 deletions guides/subscriptions.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,17 @@ line:
Supervisor.start_link(children, opts)
```

See `Absinthe.Subscription.child_spec/1` for more information on the supported
options.

In your `MyAppWeb.Endpoint` module add:

```elixir
use Absinthe.Phoenix.Endpoint
```

Now, you need to configure your socket. I.e. in your `MyAppWeb.UserSocket` module add:

```elixir
use Absinthe.Phoenix.Socket,
schema: MyAppWeb.Schema
Expand Down
26 changes: 26 additions & 0 deletions guides/telemetry.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,29 @@ After a query is executed, you'll see something like:
}
}
```

## Opentelemetry

When using Opentelemetry, one usually wants to correlate spans that are created
in spawned tasks with the main trace. For example, you might have a trace started
in a Phoenix endpoint, and then have spans around database access.

One can correlate manually by attaching the OTel context the task function:

```elixir
ctx = OpenTelemetry.Ctx.get_current()

Task.async(fn ->
OpenTelemetry.Ctx.attach(ctx)

# do stuff that might create spans
end)
```

When using the `async` and `batch` middleware, the tasks are spawned by Absinthe,
so you can't attach the context manually.

Instead, you can add the `:opentelemetry_process_propagator` package to your
dependencies, which has a `Task.async/1` wrapper that will attach the context
automatically. If the package is installed, the middleware will use it in place
of the default `Task.async/1`.
2 changes: 1 addition & 1 deletion guides/tutorial/our-first-query.md
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ Once it's up-and-running, take a look at [http://localhost:4000/api/graphiql](ht

Make sure that the `URL` is pointing to the correct place and press the play button. If everything goes according to plan, you should see something like this:

<img style="box-shadow: 0 0 6px #ccc;" src="assets/tutorial/graphiql.png" alt=""/>
<img style="box-shadow: 0 0 6px #ccc;" src="/guides/assets/tutorial/graphiql.png" alt=""/>

## Next Step

Expand Down
2 changes: 1 addition & 1 deletion guides/tutorial/subscriptions.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ In `lib/blog/application.ex`:
children = [
# other children ...
{BlogWeb.Endpoint, []}, # this line should already exist
{Absinthe.Subscription, [BlogWeb.Endpoint]}, # add this line
{Absinthe.Subscription, BlogWeb.Endpoint}, # add this line
# other children ...
]
```
Expand Down
12 changes: 10 additions & 2 deletions lib/absinthe.ex
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ defmodule Absinthe do
| %{data: nil | result_selection_t, errors: [result_error_t]}
| %{errors: [result_error_t]}

@type pipeline_modifier_fun :: (Absinthe.Pipeline.t(), Keyword.t() -> Absinthe.Pipeline.t())

@doc """
Evaluates a query document against a schema, with options.
Expand Down Expand Up @@ -92,7 +94,8 @@ defmodule Absinthe do
operation_name: String.t(),
analyze_complexity: boolean,
variables: %{optional(String.t()) => any()},
max_complexity: non_neg_integer | :infinity
max_complexity: non_neg_integer | :infinity,
pipeline_modifier: pipeline_modifier_fun()
]

@type run_result :: {:ok, result_t} | {:error, String.t()}
Expand All @@ -103,9 +106,12 @@ defmodule Absinthe do
run_opts
) :: run_result
def run(document, schema, options \\ []) do
pipeline_modifier = options[:pipeline_modifier] || (&pipeline_identity/2)

pipeline =
schema
|> Absinthe.Pipeline.for_document(options)
|> pipeline_modifier.(options)

case Absinthe.Pipeline.run(document, pipeline) do
{:ok, %{result: result}, _phases} ->
Expand All @@ -126,12 +132,14 @@ defmodule Absinthe do
@spec run!(
binary | Absinthe.Language.Source.t() | Absinthe.Language.Document.t(),
Absinthe.Schema.t(),
Keyword.t()
run_opts
) :: result_t | no_return
def run!(input, schema, options \\ []) do
case run(input, schema, options) do
{:ok, result} -> result
{:error, err} -> raise ExecutionError, message: err
end
end

defp pipeline_identity(pipeline, _options), do: pipeline
end
Loading

0 comments on commit 8b004d2

Please sign in to comment.