πŸ¦€ Rust Graph Routing runtime for Apollo Federation πŸš€

Overview

CircleCI Netlify Status

Apollo Router

The Apollo Router is a configurable, high-performance graph router for a federated graph.

Getting started

Follow the quickstart tutorial to get up and running with the Apollo Router.

See the documentation for more details.

Status

🚧 Apollo Router is experimental software. We're working on it! See our release stages for more information.

The Apollo Router can serve queries but is not yet feature complete nor fully compliant with the GraphQL specification.

We'd encourage you to experiment with it, report troubles and offer your feedback on it!

Usage

Apollo Router requires a supergraph file to be passed as the --supergraph argument and optional configuration. to be supplied. These are either located in the current directory or explicitly specified via flag, either by an absolute path, or a path relative to the current directory.

OPTIONS:
    -c, --config 
   
        Configuration file location [env:
                                         CONFIGURATION_PATH=]
    -s, --supergraph 
    
        Supergraph Schema location [env: SUPERGRAPH_PATH=]

    
   

Who is Apollo?

Apollo is building software and a graph platform to unify GraphQL across your apps and services. We help you ship faster with:

  • Apollo Studio – A free, end-to-end platform for managing your GraphQL lifecycle. Track your GraphQL schemas in a hosted registry to create a source of truth for everything in your graph. Studio provides an IDE (Apollo Explorer) so you can explore data, collaborate on queries, observe usage, and safely make schema changes.
  • Apollo Federation – The industry-standard open architecture for building a distributed graph. Compose and manage your graphs using Rover and then use Apollo Router to query plan and route requests across multiple subgraphs.
  • Apollo Client – The most popular GraphQL client for the web. Apollo also builds and maintains Apollo iOS and Apollo Android.
  • Apollo Server – A production-ready JavaScript GraphQL server that connects to any microservice, API, or database. Compatible with all popular JavaScript frameworks and deployable in serverless environments.

Learn how to build with Apollo

Check out the Odyssey learning platform, the perfect place to start your GraphQL journey with videos and interactive code challenges. Join the Apollo Community to interact with and get technical help from the GraphQL community.

Project maintainers

Apollo Graph, Inc.

Licensing

Source code in this repository is covered by the Elastic License 2.0. The default throughout the repository is a license under the Elastic License 2.0, unless a file header or a license file in a subdirectory specifies another license. See the LICENSE for the full license text.

Issues
  • finish experimental response post-processing

    finish experimental response post-processing

    PR #86 reduces the performance when processing queries. In a benchmark, we saw that the breaking point went from 15k rps to 3k rps with that PR.

    For now, #99 feature gates the response post processing, but this is a temporary solution, we need a proper fix soon.

    For more context about the performance issue, here's a flamegraph of the format_response function: Screenshot from 2021-11-08 17-04-05

    That function takes about 3% of the total processing time, of which a large part happens in parsing the query and extracting selection sets (about 2.7% of the total processing time). The call to apply_selection_set that actually modifies the response takes about 0.22%, which is fine for now.

    We might want to cache the result of the query parsing, but the selection set structure comes from apollo-rs, and contains references to the input data. So caching that would require storing a copy of the query, and the apollo-rs Document that refers to it, and hope that we don't get too many issues with self referential structures. Another path would be to have a completely owned structure to represent selection sets. The structure would not be too complex for now, but I worry this will collide with future work about query planning and execution.

    Any thoughts on this?

    2021-11 
    opened by Geal 18
  • Remove unwanted derives

    Remove unwanted derives

    @Geal I noticed in your PR #106 that a few impl are making us do unwanted things. I'm making this PR which will remove a few derive and that should simplify your code on #106.

    1. Removed Serialize on QueryPlan:

      There is no reason for us to provide serialization on the QueryPlan. We tend to add Serialize on things we want to test but this is wrong: it should be added only if there is a legit purpose in the API usage.

    2. Removed Clone

      As @Geal noticed:

      should the query planner return a Arc? This would allow us to cache things more efficiently, maybe?

      I believe you are :100: right on that. Such a big data structure shouldn't be cloned in the first pace.

      We tend to implement Clone compulsively everywhere we can but I think this is yet another misuse of the trait. In this case, the QueryPlan is kinda immutable object received from the query planner. If there is no reason to mutate it, there is also no reason to Clone it either.

    Thoughts on traits and #[derive(...)]

    One way to avoid this error is to conditionally add the trait using cfg_attr but in the case of Serialize I personally prefer to use insta. This crates allows storing a snapshot of an object. In this case I use the Debug snapshot because we don't need to check that we serialize back properly, we only need to check that we parsed the information properly.

    Among the traits we miuse a bit: PartialEq, Eq, Default, Serialize/Deserialize, ... and apparently Clone can be misused.

    Note that it is true and healthy that beginner Rust developers should Clone all the things :broom: to make things work first but I believe as you get experienced you must reflect on what you provide in your API. Think about how a trait will be used on your objects, why it will be used and finally: does it encourage wrong or a good pattern? In these cases: Serialize was adding maintenance load and Clone was encouraging waste of memory.

    I think these are good tips for all of us. cc @BrynCooke @o0Ignition0o @Geal

    opened by cecton 16
  • fix configuration file in docs

    fix configuration file in docs

    it was not matching the configuration loader

    also mark the username and password fields as not skipped so they can be used from the config file

    opened by Geal 16
  • make the OTLP exporters non exclusive

    make the OTLP exporters non exclusive

    this allows users to choose which exporter they want without recompiling the router, at the price of a larger binary (unstripped binary goes from 59MB to 66MB)

    I started on this to see if I could reduce the time spent in xtask test in CI, but I think it makes more sense anyway to have all the exporters available in the released version

    This PR also includes CI tuning to reduce the time spent, mainly by:

    • building the router and router-core only once
    • caching the xtask build step
    • running xtask lint only on linux

    The result:

    • build from scratch (without cache, ie anytime Cargo.lock changes): 18mn https://app.circleci.com/pipelines/github/apollographql/router/237/workflows/c3e173d9-ff51-40a5-b816-b5d500115eca
    • build with cache: 6mn49s https://app.circleci.com/pipelines/github/apollographql/router/237/workflows/ba8f4055-b5a0-4182-9a45-8aee9a9e6ce0
    • in comparison, on the main branch, all builds are around 16mn: https://app.circleci.com/pipelines/github/apollographql/router?branch=main
    opened by Geal 15
  • Split execution and planning (refactoring)

    Split execution and planning (refactoring)

    List of changes in this PR

    • ~~Renamed models.rs to query_plan.rs: these models were meant to work on for the QueryPlan and I would like to make it more explicit~~ [edit: revert for now as it makes the review harder]
    • Use String instead of Query in Request: the query there was fine but involved parsing. So Request will keep a simple string but a Query can be parsed from this string later on
    • Naive introspection knits: takes a query string in parameter instead of an entire request + return directly a response instead of a Value that we convert to a response anyway.
    • Moved/Added validation functions to PlanNode: all the validation functions require the plan so I moved them there.
    • Moved plan execution to PlanNode: the user doesn't need to customize that.
    • Added a wrapper to the execute() PlanNode function: this makes the public API of PlanNode easier.

    Most important changes

    • Remove Fetcher from FederatedGraph
    • Rename FederatedGraph to Router
    • Added 2 new traits: Router and Route
      • A "Router" is an object that creates route
      • A "Route" is an object that you execute to create the ResponseStream
    • Moved Router/Route/FederatedGraph's logic to apollo-router/apollo_router.rs: this now becomes the "default implementation of a router". The user will be able to replace those parts.

    Related to #106 #62 #100

    opened by cecton 11
  • do we need 2 different GRPC implementations?

    do we need 2 different GRPC implementations?

    Opentelemetry is set up to have 3 different exporters: HTTP, tonic(grpc) and grpcio( grpc)

    I'd like to remove grpcio because building with this library greatly increases the compilation time and the size of the build directory, and we already have the tonic GRPC implementation. On my machine, building apollo-router in debug mode:

    • cargo build --features tls,otlp-http,otlp-tonic -p apollo-router: builds in 47s, target/ weights at 2.4GB
    • cargo build --features tls,otlp-http,otlp-tonic,otlp-grpcio -p apollo-router: builds in 1mn29s, target/ weights at 3.4GB

    They apparently have different feature sets:

    grpcio:

    • setup credentials
    • add additional headers
    • config compression
    • select whether to use TLS
    • set the number of GRPC worker threads to poll queues

    tonic:

    • add additional metadata
    • set tls config(with tls feature enabled)
    • bring custom channel

    Which features do we actually need? Can we contribute the missing ones in tonic? Can we get away with using tonic and a local collector thant handles credentials, custom headers, etc?

    @cecton WDYT?

    size/large 2021-11 
    opened by Geal 9
  • Parse & cache queries

    Parse & cache queries

    Changes

    • Removal of feature flag post-processing
    • Introduction of new object QueryCache in core crate, shamelessly copy-pasting the logic from CachingQueryPlanner (will be refactored in a future PR)
    • Move Query to its own file (query.rs)
    • Add CLI argument --query-cache-limit
    • Query parsing in parallel to plan execution (because it's in a spawn_blocking)
    • Regrets (refactor in a future PR)

    Task list from #106

    • [x] fragments can be defined in the supergraph (this is the most common case) so fragments definition should be obtained from there too, not only in the query
    • [x] we should check the operation name, to apply the correct selection set (a query can contain multiple operations)

    Superseeds #106 Closes #100 Related to #166

    opened by cecton 9
  • Hot reloading (file watching) probably does not work on OSX

    Hot reloading (file watching) probably does not work on OSX

    While working on the release workflow I had to ignore some tests for OSX because they were not working. I believe it is possible the hot reloading of the configuration and schema is not working on OSX.

    cc @BrynCooke

    size/small 2021-11 
    opened by cecton 7
  • Remove grpcio

    Remove grpcio

    Fix #150 supplant #147

    This PR includes:

    • commits cherry picked from #147 and refactored, to allow multiple OTLP exporters to be used in the same compiled binary
    • removing grpcio, in favor of using tonic for OTLP/gRPC
    • renaming the otlp-tonic feature to otlp-grpc
    • the tls feature forces otlp-grpc since it cannot be used independently (maybe we could merge them?)
    • allow choosing the http or grpc exporter in the configuration without setting any fields (74374925c8a105d05b9217cb4c8a). I'm not sure about that one, I may be making some invalid yaml here
    opened by Geal 6
  • Reduce cloning in Response composition

    Reduce cloning in Response composition

    I noticed that we are cloning cached naiveintrospection values when we don't need to. If we modify that behaviour to return a reference we can avoid unnecessary work.

    resolves #168

    opened by garypen 6
  • subgraph errors should bubble up to the next nullable parent field

    subgraph errors should bubble up to the next nullable parent field

    as described in https://www.apollographql.com/blog/graphql/basics/using-nullability-in-graphql/

    With this schema:

    type Restaurant {
      name: String!
      rating: Int!
      location: Location!
    }
    
    type Location {
      address: String!
    }
    
    type LatLng {
      lat: Int!
      lng: Int!
    }
    
    type Query {
      restaurants(query: String): [Restaurant]
    }
    

    if a subgraph returns a response with this content:

    {
            name: "All Star Cafe",
            rating: 5,
            location: null
    }
    

    location must not be null, so we register an error, and mark the restaurant itself as null:

    {
      "data": {
        "restaurants": [ null ]
      },
      "errors": [{
        "message": "Cannot return null for non-nullable field Restaurant.location."
      }]
    }
    
    triage 
    opened by Geal 1
  • Draft ADR for telemetry improvements

    Draft ADR for telemetry improvements

    A template (copied from internet) and a draft ADR for telemetry.

    Please use the github "discussion" (shared in slack) for framing discussion about these documents.

    opened by garypen 1
  • set OTLP service name and namespace

    set OTLP service name and namespace

    fix #180 related to #38

    • a5b8581 sets default values for service name and namespace, to fix #180
    • 26045c3 fixes a regression introduced in https://github.com/apollographql/router/commit/34f5f9ea64fdeb488e0c99a4420394cc066b7744: if reqwest-tracing uses a different tracing-opentelemetry version, tracing headers are not propagated
    • 3bc699f fixes a regression introduced in 44840e4: the execute and format_response phases were appearing as their own root spans

    26045c3 is temporary, I'll send a PR to reqwest-tracing to support the tracing-opentelemetry 0.16

    we should get #38 implemented, to make sure those kinds of regressions do not happen

    opened by Geal 0
  • fix(deps): update cargo pre-1.0 packages (patch)

    fix(deps): update cargo pre-1.0 packages (patch)

    WhiteSource Renovate

    This PR contains the following updates:

    | Package | Type | Update | Change | |---|---|---|---| | derive_more | dependencies | patch | 0.99.16 -> 0.99.17 | | tracing-subscriber | dev-dependencies | patch | 0.3.2 -> 0.3.3 | | tracing-subscriber | dependencies | patch | 0.3.2 -> 0.3.3 |


    Configuration

    πŸ“… Schedule: At any time (no schedule defined).

    🚦 Automerge: Disabled due to failing status checks.

    β™» Rebasing: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

    πŸ‘» Immortal: This PR will be recreated if closed unmerged. Get config help if that's undesired.


    • [ ] If you want to rebase/retry this PR, click this checkbox.

    This PR has been generated by WhiteSource Renovate. View repository job log here.

    opened by renovate[bot] 0
  • Move licenses.html to Git LFS

    Move licenses.html to Git LFS

    I see the licenses.html getting bigger and bigger which worries me.

    If possible I would like this file to be moved to Git LFS.

    triage 
    opened by cecton 1
  • test trace sampling

    test trace sampling

    related:

    • #29
    • #50

    this is an exploration of trace sampling. Currently the custom sampler just prints its parameters. With the query query ExampleQuery($topProductsFirst: Int) { me { id avis: reviews { body } } topProducts(first: $topProductsFirst) { name price inStock }} it will print:

    {"timestamp":"Nov 25 11:14:54.182","level":"INFO","fields":{"message":"Starting Apollo Router\n*******************************************************************\n⚠️  Experimental software, not YET recommended for production use ⚠️\n****************************************
    ***************************"},"target":"router"}                   
    {"timestamp":"Nov 25 11:14:54.659","level":"INFO","fields":{"message":"Listening on http://127.0.0.1:4000 πŸš€"},"target":"router"}
    Nov 25 11:15:17.822 ERROR graphql_request: apollo_router::warp_http_server_factory: TEST ERROR stream_request
    should_sample:                          
    parent context: Some(Context { entries: 0 })                                                                                            
    trace id: TraceId(271433600488164807808896833698919480999)
    name:graphql_request                                                                                                                    
    span_kind: Internal                               
    attributes: [                                                                                                                           
        KeyValue {                                                                                                                          
            key: Key(                         
                "code.filepath",                                                                                                            
            ),                                                                                                                              
            value: String(    
                "crates/apollo-router/src/warp_http_server_factory.rs",                                                                                                                                                                                                             
            ),                                         
        },                                                                                                                                  
        KeyValue {                                                      
            key: Key(                                                                                                                       
                "code.namespace",                
            ),                                                                                                                                                                                                                                                                              value: String(                                                                                                                  
                "apollo_router::warp_http_server_factory",                                                                                                                                                                                                                          
            ),
        },
        KeyValue {
            key: Key(
                "code.lineno",
            ),
            value: I64(
                275,
            ),
        },
    ]
    links: []
    
    should_sample:                                     
    parent context: Some(Context { entries: 0 })                                                                                            
    trace id: TraceId(10389225646006697978543566376744025668)
    name:execution                                                     
    span_kind: Internal         
    attributes: [                                                                                                                           
        KeyValue {                                                                                                                          
            key: Key(                                                                                                                       
                "code.filepath",                                  
            ),                                                                                                                              
            value: String(                                                                                                                                                                                                                                                          
                "crates/apollo-router-core/src/query_planner/model.rs",
            ),                                                                                                                              
        },                                                                                                                                  
        KeyValue {
            key: Key(                           
                "code.namespace",                             
            ),          
            value: String(
                "apollo_router_core::query_planner::model",
            ),    
        },           
        KeyValue {              
            key: Key(
                "code.lineno",
            ),                                                         
            value: I64(
                249,
            ),    
        },           
    ]                            
    links: [] 
                                                                        
    Nov 25 11:15:18.149 ERROR format_response{self=Query { string: "query ExampleQuery($topProductsFirst: Int) {\n  me {\n    id\n avis: reviews { body } \n }\n  topProducts(first: $topProductsFirst) {\n    name\n    price\n    inStock\n  }\n}\n" } response=Response { label: 
    None, data: Object({"me": Object({"__typename": String("User"), "id": String("1"), "avis": Array([Object({"body": String("Love it!")}), Object({"body": String("Too expensive.")})])}), "topProducts": Array([Object({"__typename": String("Product"), "upc": String("1"), "name
    ": String("Table"), "price": Number(899), "inStock": Bool(true)}), Object({"__typename": String("Product"), "upc": String("2"), "name": String("Couch"), "price": Number(1299), "inStock": Bool(false)}), Object({"__typename": String("Product"), "upc": String("3"), "name": S
    tring("Chair"), "price": Number(54), "inStock": Bool(true)})])}), path: None, has_next: None, errors: [], extensions: {} }}: apollo_router_core::request: TEST ERROR format_response 
    
    should_sample:                                            
    parent context: Some(Context { entries: 0 })                                                                                                                                                                                                                                    
    trace id: TraceId(272298814962264935456849981390735724192)                                                                                                                                                                                                                      
    name:format_response                                                                                                                                                                                                                                                            
    span_kind: Internal                                                                                                                                                                                                                                                             
    attributes: [                                                                                                                                                                                                                                                                   
        KeyValue {                                                                                                                                                                                                                                                                  
            key: Key(                                                                                                                                                                                                                                                               
                "code.filepath",                                                                                                                                                                                                                                                    
            ),                                                                                                                                                                                                                                                                      
            value: String(                                                                                                                                                                                                                                                          
                "crates/apollo-router-core/src/request.rs",                                                                                                                                                                                                                         
            ),                                                                                                                                                                                                                                                                      
        },                                                                                                                                                                                                                                                                          
        KeyValue {                                                                                                                                                                                                                                                                  
            key: Key(                                                                                                                                                                                                                                                               
                "code.namespace",                                                                                                                                                                                                                                                   
            ),                                                                                                                                                                                                                                                                      
            value: String(                                                                                                                                                                                                                                                          
                "apollo_router_core::request",                                                                                                                                                                                                                                      
            ),                                                                                                                                                                                                                                                                      
        },                                                                                                                                                                                                                                                                          
        KeyValue {                                                                                                                                                                                                                                                                  
            key: Key(                                                                                                                                                                                                                                                               
                "code.lineno",                                                                                                                                                                                                                                                      
            ),                                                                                                                                                                                                                                                                      
            value: I64(                                                                                                                                                                                                                                                             
                51,                                                                                                                                                                                                                                                                 
            ),                                                                                                                                                                                                                                                                      
        },                                                                                                                                                                                                                                                                          
        KeyValue {                                                                                                                                                                                                                                                                  
            key: Key(                                                                                                                                                                                                                                                               
                "self",                                                                                                                                                                                                                                                             
            ),                                                                                                                                                                                                                                                                      
            value: String(                                                                                                                                                                                                                                                          
                "Query { string: \"query ExampleQuery($topProductsFirst: Int) {\\n  me {\\n    id\\n avis: reviews { body } \\n }\\n  topProducts(first: $topProductsFirst) {\\n    name\\n    price\\n    inStock\\n  }\\n}\\n\" }",                                               
            ),                                                                                                                                                                                                                                                                      
        },                                                                                                                                                                                                                                                                          
        KeyValue {                                                                                                                                                                                                                                                                  
            key: Key(                                                                                                                                                                                                                                                               
                "response",                                                                                                                                                                                                                                                         
            ),                                                                                                                                                                                                                                                                      
            value: String(                                                                                                                                                                                                                                                          
                "Response { label: None, data: Object({\"me\": Object({\"__typename\": String(\"User\"), \"id\": String(\"1\"), \"avis\": Array([Object({\"body\": String(\"Love it!\")}), Object({\"body\": String(\"Too expensive.\")})])}), \"topProducts\": Array([Object({\"__t
    ypename\": String(\"Product\"), \"upc\": String(\"1\"), \"name\": String(\"Table\"), \"price\": Number(899), \"inStock\": Bool(true)}), Object({\"__typename\": String(\"Product\"), \"upc\": String(\"2\"), \"name\": String(\"Couch\"), \"price\": Number(1299), \"inStock\": 
    Bool(false)}), Object({\"__typename\": String(\"Product\"), \"upc\": String(\"3\"), \"name\": String(\"Chair\"), \"price\": Number(54), \"inStock\": Bool(true)})])}), path: None, has_next: None, errors: [], extensions: {} }",
            ),
        },
        KeyValue {                                                      
            key: Key(                                                                                                                       
                "busy_ns",                                   
            ),                                                       
            value: I64(                                       
                504336,                                             
            ),                                              
        },                                                                                                                                  
        KeyValue {                                 
            key: Key(                                            
                "idle_ns",                               
            ),                                                                                                                              
            value: I64(
                29067,                                                                                                                      
            ),                                                                                                                              
        },                                                              
    ]                                                                                                                                       
    links: []                                                                                                                               
                                                                        
    Nov 25 11:15:18.149 ERROR apollo_router::apollo_router: TEST ERROR
    

    Apparently it does not receive information that there was an error event inside a span. In its result, a sampler has a SamplingDecision:

    • Drop: delete the span from the trace
    • RecordOnly: keep the span, but it is not sent
    • RecordAndSample: keep the span, send it

    RecordOnly is useful if we want to process the span (example: for statistics or SLO/SLA) but don't want to send it because we're sampling The sampler can look at the parent span to see if it should be sampled. The sampling decision depends on the parent so here in the logs, we have three different traces (probably a bug, they should be merged). The spec on sampled flag usage: https://www.w3.org/TR/trace-context/#sampled-flag

    needs

    The kind of sampling I'd like to integrate:

    • send all traces where we saw an error (or at least most of them, we should be careful not to overwhelm the collection system during an incident)
    • sample successful queries, with a configurable rate (percentage based, time based, maybe per query hash, etc)
    • honor sampling orders sent by the client in a header
    • indicate in the trace the sample rate

    design

    • we make a sampler like the parent based that defers the decision to the parent if it's sampled
    • our sampler looks at the attributes to see if there's one indicating it should be sampled (can be done with Context::current().span().set_attribute(key_value))
    • at the end of the response processing, if there was an error, we set the attribute for it
    opened by Geal 4
  • Display schema parse errors

    Display schema parse errors

    Now that we're using the latest version of apollo-parser, we can retrieve and display schema parse errors.

    size/small triage 
    opened by o0Ignition0o 0
  • Zipkin reports UNKNOWN_SERVICE : graphql_request for router spans

    Zipkin reports UNKNOWN_SERVICE : graphql_request for router spans

    Describe the bug As a follow-on to #149 I'm now seeing Zipkin report UNKNOWN_SERVICE : graphql_request for router spans.

    The subgraph spans are also offset, so not sure if trace propagation is working correctly.

    To Reproduce Steps to reproduce the behavior:

    1. git clone [email protected]:apollographql/supergraph-demo-fed2.git
    2. make docker-up-router-otel - uses docker-compose.router-otel.yml
    3. make smoke-router
    4. http://localhost:9411/ -> Run Query
    5. see UNKNOWN_SERVICE : graphql_request for router requests
    6. click Show and see the offset subgraph spans

    Expected behavior

    1. router to set a default resource/service name so it shows up in the Zipkin serviceName field, and ideally allow setting the field via config.yaml and include it in the config docs
    2. subgraph trace spans to align with the parent router spans, like it does for the Gateway in https://github.com/apollographql/supergraph-demo-fed2#tracing-with-open-telemetry

    Output image

    Desktop (please complete the following information):

    ProductName:	macOS
    ProductVersion:	11.6
    BuildVersion:	20G165
    
    size/medium 2021-11 
    opened by prasek 2
  • multiple levels of cache depending on the branch

    multiple levels of cache depending on the branch

    Right now, when restoring the cache, we first look for a cache matching the Cargo.lock file, or any valid cache for that platform:

    https://github.com/apollographql/router/blob/3f282070d350b1ec1ca0c7f10334f03d98a273e9/.circleci/config.yml#L270-L273

    The issue here is that it will take the same cache as the last time Cargo.lock changed, while the PR's code could change significantly compared to main, so we'll rebuild things often.

    There's a small improvement I tested in a PR: https://github.com/apollographql/router/blob/43d8a5cbaf67bb06410fd6419f17be94105111bb/.circleci/config.yml#L53-L57

    The idea is that when e start the PR, we take the last known cache for main, then we build the PR, and save the cache for the PR's branch. That way, for all future builds of that branch, we start from the branch specific cache and have less work to do

    cc @o0Ignition0o

    size/small triage 
    opened by Geal 6
  • should we validate the list of services in the query plan?

    should we validate the list of services in the query plan?

    from https://github.com/apollographql/router/pull/166#discussion_r754493609

    Since we're extracting the services from the schema, and the query plan is established from the same schema, we already know that the service registry will have all the required services, so we can avoid validating that part.

    But could there be cases where we need to? Like if we add a circuit breaker for failing services, we might want to reject the request right there?

    triage 
    opened by Geal 0
Releases(v0.1.0-alpha.1)
  • v0.1.0-alpha.1(Nov 19, 2021)

    Public alpha release: An alpha or beta release is in volatile, active development. The release might not be feature-complete, and breaking API changes are possible between individual versions. See our [release stages] for more information.

    :bug: Fixes

    • Handle commas in the @join__graph directive parameters #101

      There are several accepted syntaxes to define @join__graph parameters. While we did handle whitespace separated parameters such as @join__graph(name: "accounts" url: "http://accounts/graphql")for example, we discarded the url in@join__graph(name: "accounts", url: "http://accounts/graphql") (notice the comma). This pr fixes that.

    • Invert subgraph URL override logic #135

      Subservices endpoint URLs can both be defined in supergraph.graphql and in the subgraphs section of the configuration.yml file. The configuration now correctly overrides the supergraph endpoint definition when applicable.

    • Parse OTLP endpoint address #156

      The router OpenTelemetry configuration only supported full URLs (that contain a scheme) while OpenTelemtry collectors support full URLs and endpoints, defaulting to https. This pull request fixes that.

    :books: Documentation

    • A lot of configuration examples and links have been fixed (#117, #120, #133)

    :pray: Thank you!

    Special thanks to @sjungling, @hsblhsn, @martin-dd, @Mithras and @vvakame for trying out the router, opening issues and documentation fixes! :rocket:

    Source code(tar.gz)
    Source code(zip)
    md5sums.txt(231 bytes)
    router-0.1.0-alpha.1-x86_64-linux.tar.gz(20.48 MB)
    router-0.1.0-alpha.1-x86_64-macos.tar.gz(16.69 MB)
    router.exe-0.1.0-alpha.1-x86_64-windows.tar.gz(14.06 MB)
    sha1sums.txt(255 bytes)
    sha256sums.txt(327 bytes)
  • v0.1.0-alpha.0(Nov 10, 2021)

    :rocket::waxing_crescent_moon: Initial public alpha release

    An alpha or beta release is in volatile, active development. The release might not be feature-complete, and breaking API changes are possible between individual versions.

    See our release stages for more information.

    :sparkles: Features

    • Federation 2 alpha

      The Apollo Router supports the new alpha features of Apollo Federation 2, including its improved shared ownership model and enhanced type merging. As new Federation 2 features are released, we will update the Router to bring in that new functionality.

    • Supergraph support

      The Apollo Router supports supergraphs that are published to the Apollo Registry, or those that are composed locally. Both options are enabled by using Rover to produce (rover supergraph compose) or fetch (rover supergraph fetch) the supergraph to a file. This file is passed to the Apollo Router using the --supergraph flag.

      See the Rover documentation on supergraphs for more information!

    • Query planning and execution

      The Apollo Router supports Federation 2 query planning using the same implementation we use in Apollo Gateway for maximum compatibility. In the future, we would like to migrate the query planner to Rust. Query plans are cached in the Apollo Router for improved performance.

    • Performance

      We've created benchmarks demonstrating the performance advantages of a Rust-based Apollo Router. Early results show a substantial performance improvement over our Node.js based Apollo Gateway, with the possibility of improving performance further for future releases.

      Additionally, we are making benchmarking an integrated part of our CI/CD pipeline to allow us to monitor the changes over time. We hope to bring awareness of this into the public purview as we have new learnings.

      See our blog post for more.

    • Apollo Sandbox Explorer

      Apollo Sandbox Explorer is a powerful web-based IDE for creating, running, and managing GraphQL operations. Visiting your Apollo Router endpoint will take you into the Apollo Sandbox Explorer, preconfigured to operate against your graph.

    • Introspection support

      Introspection support makes it possible to immediately explore the graph that's running on your Apollo Router using the Apollo Sandbox Explorer. Introspection is currently enabled by default on the Apollo Router. In the future, we'll support toggling this behavior.

    • OpenTelemetry tracing

      For enabling observability with existing infrastructure and monitoring performance, we've added support using OpenTelemetry tracing. A number of configuration options can be seen in the configuration documentation under the opentelemetry property which allows enabling Jaeger or OTLP.

      In the event that you'd like to send data to other tracing platforms, the OpenTelemetry Collector can be run an agent and can funnel tracing (and eventually, metrics) to a number of destinations which are implemented as exporters.

    • CORS customizations

      For a seamless getting started story, the Apollo Router has CORS support enabled by default with Access-Control-Allow-Origin set to *, allowing access to it from any browser environment.

      This configuration can be adjusted using the CORS configuration in the documentation.

    • Subgraph routing URL overrides

      Routing URLs are encoded in the supergraph, so specifying them explicitly isn't always necessary.

      In the event that you have dynamic subgraph URLs, or just want to quickly test something out locally, you can override subgraph URLs in the configuration.

      Changes to the configuration will be hot-reloaded by the running Apollo Router.

    πŸ“š Documentation

    The beginnings of the [Apollo Router's documentation] is now available in the Apollo documentation. We look forward to continually improving it!

    • Quickstart tutorial

      The quickstart tutorial offers a quick way to try out the Apollo Router using a pre-deployed set of subgraphs we have running in the cloud. No need to spin up local subgraphs! You can of course run the Apollo Router with your own subgraphs too by providing a supergraph.

    • Configuration options

      On our configuration page we have a set of descriptions for some common configuration options (e.g., supergraph and CORS) as well as a full configuration file example of the currently supported options.

    :eyes: Ahead...

    We'll be working to open issues and surface designs about these things and more, as the planning progresses. Follow our ROADMAP.md for more details as they become available and we'll link to issues as they're available. We look forward to your participation!

    • Apollo Studio integrations

      We'll be building out stories for Apollo Studio, including:

      • Tracing
      • Metrics reporting
      • Schema reporting

      We'd like to make the Apollo Router as much as part of the Studio story as Apollo Gateway is today.

    • Newer Federation 2 features

      As new Apollo Federation 2 features are released, we'll integrate those updates into the Router. In most cases, this will be just as simple as updating the Apollo Router's dependencies.

    • More customizations

      We're excited about a number of opportunities for customizing behavior, including exploring options for:

      • Header manipulation
      • Request context propagation
      • Dynamic routing
      • Authorization
      • Auditing

      We hope to provide first-class experiences for many of the things which required a more-than-ideal amount of configuration.

    • Specification compliance

      We're still working on making the Apollo Router fully GraphQL specification compliant. This will be a continued effort and is also embodied in the Apollo Router's design principles.

      Until we finish this work, there may be responses returned to the clients which are not fully specification compliant, including artifacts of Federation query plan execution. (e.g., the inclusion of additional metadata).

    • OpenTelemetry/Prometheus metrics

      These will compliment the existing OpenTelemetry traces which we already support. It will help to paint a clearer picture of how the Apollo Router is performing and allow you to set alerts in your favorite alerting software.

    • Structured logging

      The logs that are produced from the Apollo Router should integrate well with existing log facilities. We'll be adding configuration to enable this (e.g., JSON-formatted logging).

    • Continued performance tuning

      The Apollo Router is already fast, but we'll be looking for more ways to make it faster. We'll be setting up CI/CD performance measurements to track regressions before they end up in user's deployments and to understand the cost of new features we introduce.

    • Hardening

      The Router will need new functionality to remain performant. This will include exploring options for rate-limiting, payload size checking, reacting to back-pressure, etc.

    Source code(tar.gz)
    Source code(zip)
    md5sums.txt(231 bytes)
    router-0.1.0-alpha.0-x86_64-linux.tar.gz(20.45 MB)
    router-0.1.0-alpha.0-x86_64-macos.tar.gz(16.67 MB)
    router.exe-0.1.0-alpha.0-x86_64-windows.tar.gz(14.02 MB)
    sha1sums.txt(255 bytes)
    sha256sums.txt(327 bytes)
Owner
Apollo GraphQL
A community building flexible open source tools for GraphQL.
Apollo GraphQL
A graph library for Rust.

Gamma A graph library for Rust. Gamma provides primitives and traversals for working with graphs. It is based on ideas presented in A Minimal Graph AP

Metamolecular, LLC 111 Nov 6, 2021
Simple but powerful graph library for Rust

Graphlib Graphlib is a simple and powerful Rust graph library. This library attempts to provide a generic api for building, mutating and iterating ove

Purple Protocol 158 Nov 9, 2021
GraphScope: A One-Stop Large-Scale Graph Computing System from Alibaba

A One-Stop Large-Scale Graph Computing System from Alibaba GraphScope is a unified distributed graph computing platform that provides a one-stop envir

Alibaba 1.2k Nov 30, 2021
A simple and elegant, pipewire graph editor

pw-viz A simple and elegant, pipewire graph editor This is still a WIP, node layouting is kinda jank at the moment. Installation A compiled binary is

null 88 Nov 26, 2021
A graph crate with simplicity in mind

A graph crate with simplicity in mind. Prepona aims to be simple to use (for users of the crate) and develop further (for contributors). Nearly every

Mohamad Amin Rayej 68 Nov 19, 2021
A toy ray tracer in Rust

tray_rust - A Toy Ray Tracer in Rust tray_rust is a toy physically based ray tracer built off of the techniques discussed in Physically Based Renderin

Will Usher 452 Nov 27, 2021
A low-overhead Vulkan-like GPU API for Rust.

Getting Started | Documentation | Blog gfx-rs gfx-rs is a low-level, cross-platform graphics and compute abstraction library in Rust. It consists of t

Rust Graphics Mages 5k Nov 24, 2021
A complete harfbuzz's shaping algorithm port to Rust

rustybuzz rustybuzz is a complete harfbuzz's shaping algorithm port to Rust. Matches harfbuzz v2.7.0 Why? Because you can add rustybuzz = "*" to your

Evgeniy Reizner 218 Nov 18, 2021
An OpenGL function pointer loader for Rust

gl-rs Overview This repository contains the necessary building blocks for OpenGL wrapper libraries. For more information on each crate, see their resp

Brendan Zabarauskas 570 Nov 29, 2021
Safe OpenGL wrapper for the Rust language.

glium Note to current and future Glium users: Glium is no longer actively developed by its original author. That said, PRs are still welcome and maint

null 2.7k Nov 25, 2021
GLFW3 bindings and idiomatic wrapper for Rust.

glfw-rs GLFW bindings and wrapper for The Rust Programming Language. Example extern crate glfw; use glfw::{Action, Context, Key}; fn main() { le

PistonDevelopers 468 Nov 20, 2021
Safe and rich Rust wrapper around the Vulkan API

Vulkano See also vulkano.rs. Vulkano is a Rust wrapper around the Vulkan graphics API. It follows the Rust philosophy, which is that as long as you do

null 2.9k Nov 28, 2021
A vector graphics renderer using OpenGL with a Rust & C API.

bufro A vector graphics renderer using OpenGL with a Rust & C API. A Rust example can be found in examples/quickstart.rs (using glutin). A C example c

Aspect 6 Nov 21, 2021
Kiss3d - Keep it simple, stupid 3d graphics engine for Rust.

Kiss3d - Keep it simple, stupid 3d graphics engine for Rust.

SΓ©bastien Crozet 1k Nov 26, 2021
A cool, fast maze generator and solver written in Rust

MazeCruncher Welcome to maze cruncher! Download Standalone Here Usage To get started, just run the standalone .exe in target/release or compile and ru

null 57 Nov 17, 2021
ASCII 3D-renderer using Ray Marching technique written in Rust with NCurses

pistol ASCII renderer using Ray Marching technique written in Rust ?? with NCurses. This project is a giga-chad compared to my previous attempt to wri

Eugene Sokolov 2 Nov 21, 2021
A high-performance SVG renderer, powered by Rust based resvg and napi-rs.

resvg-js resvg-js is a high-performance SVG renderer, powered by Rust based resvg and napi-rs. Fast, safe and zero dependencies! No need for node-gyp

一丝 66 Nov 20, 2021
A little cross-platform graphics engine written in rust.

Bismuth This is a version of my C++ graphics engine named Bismuth re-written with Rust. My goal is to learn more about the Rust language and make my g

Admiral γ‚΅γ‚€γ‚Ώγƒž 1 Nov 1, 2021
The library provides basic functions to work with Graphviz dot lang from rust code.

Description The library provides the basic access to the graphs in graphviz format with ability to import into or export from it. Base examples: Parse

Boris 9 Nov 17, 2021