1651899600
react-apollo with ReasonML
yarn add reason-apollo
# Add graphql_ppx
yarn add @baransu/graphql_ppx_re --dev
Add reason-apollo
to your bs-dependencies
and @baransu/graphql_ppx_re/ppx
to your ppx-flags
bsconfig.json
"bs-dependencies": [
"reason-react",
"reason-apollo"
],
"ppx-flags": [
"@baransu/graphql_ppx_re/ppx"
]
This will generate a graphql_schema.json
which will be used to safely type your GraphQL queries/mutations.
npx get-graphql-schema ENDPOINT_URL -j > graphql_schema.json
Watch its usage in this video:
Usage
Client.re
/* Create an InMemoryCache */
let inMemoryCache = ApolloInMemoryCache.createInMemoryCache();
/* Create an HTTP Link */
let httpLink =
ApolloLinks.createHttpLink(~uri="http://localhost:3010/graphql", ());
let instance =
ReasonApollo.createApolloClient(~link=httpLink, ~cache=inMemoryCache, ());
Index.re
/*
Enhance your application with the `ReasonApollo.Provider`
passing it your client instance
*/
ReactDOMRe.renderToElementWithId(
<ReasonApollo.Provider client=Client.instance>
<App />
</ReasonApollo.Provider>,
"index",
);
MyQuery.re
/* Create a GraphQL Query by using the graphql_ppx */
module GetUserName = [%graphql
{|
query getUserName($id: ID!){
user(id: $ID) {
id
device {
id
brand {
id
name
}
}
}
}
|}
];
module GetUserNameQuery = ReasonApollo.CreateQuery(GetUserName);
[@react.component]
let make = () => {
let userNameQuery = GetUserName.make(~id="42", ());
<GetUserNameQuery variables=userNameQuery##variables>
...{({result}) =>
switch (result) {
| Loading => <div> {ReasonReact.string("Loading")} </div>
| Error(error) => <div> {ReasonReact.string(error##message)} </div>
| Data(response) =>
<div>
{/* Handles a deeply nested optional response */
response##user
->Belt.Option.flatMap(user => user##device)
->Belt.Option.flatMap(device => device##brand)
->Belt.Option.mapWithDefault("", brand => brand##name)}
</div>
}
}
</GetUserNameQuery>;
};
MyMutation.re
module AddUser = [%graphql
{|
mutation addUser($name: String!) {
addUser(name: $name) {
id
name
}
}
|}
];
module AddUserMutation = ReasonApollo.CreateMutation(AddUser);
[[@react.component]
let make = () => {
<AddUserMutation>
...{(mutation /* Mutation to call */, _ /* Result of your mutation */) => {
let addNewUserQuery = AddUser.make(~name="Bob", ());
<div>
<button
onClick={_mouseEvent =>
mutation(
~variables=addNewUserQuery##variables,
~refetchQueries=[|"getAllUsers"|],
(),
)
|> ignore
}>
{ReasonReact.string("Add User")}
</button>
</div>;
}}
</AddUserMutation>;
};
MySubscription.re
module UserAdded = [%graphql {|
subscription userAdded {
userAdded {
id
name
}
}
|}];
module UserAddedSubscription = ReasonApollo.CreateSubscription(UserAdded);
[@react.component]
let make = () => {
<UserAddedSubscription>
...{({result}) => {
switch (result) {
| Loading => <div> {ReasonReact.string("Loading")} </div>
| Error(error) => <div> {ReasonReact.string(error##message)} </div>
| Data(_response) =>
<audio autoPlay=true>
<source src="notification.ogg" type_="audio/ogg" />
<source src="notification.mp3" type_="audio/mpeg" />
</audio>
}
}}
</UserAddedSubscription>;
};
If you simply want to have access to the ApolloClient, you can use the ApolloConsumer
<ApolloConsumer>
...{apolloClient => {/* We have access to the client! */}}
</ApolloConsumer>;
If for this query
query {
user {
device {
brand {
name
}
}
}
}
you end up with that kind of code:
let deviceName =
switch (response##user) {
| None => ""
| Some(user) =>
switch (user##device) {
| None => ""
| Some(device) =>
switch (device##brand) {
| None => ""
| Some(brand) => brand##name
}
}
};
Belt
open Belt.Option;
let deviceName =
response##user
->flatMap(user => user##device)
->flatMap(device => device##brand)
->mapWithDefault("", brand => brand##name);
@bsRecord
The @bsRecord
modifier is an extension of the graphql syntax for BuckleScipt/ReasonML. It allows you to convert a reason object to a reason record and reap the benefits of pattern matching, but you need to defined the record by yourself.
type brand = {
name: string
};
type device = {
brand: option(brand)
};
type user = {
device: option(device)
};
type response = user;
query {
user @bsRecord {
device @bsRecord {
brand @bsRecord {
name
}
}
}
}
This time we can pattern match more precisely.
let deviceName =
switch (response##user) {
| Some({device: Some({brand: {name}})}) => name
| _ => ""
};
get_in_ppx
npm install get_in_ppx
and in bsconfig.json
"ppx-flags": ["get_in_ppx/ppx"]
you can write
let deviceName = response##user#??device#??brand#?name;
There's a blogpost from Jared Forsyth (author of this ppx) for more explanation.
You might find yourself consuming an API with field names like Field
. Currently, reason object field names are required to be camel case. Therefore if you have a request like this:
{
Object {
id
title
}
}
You will attempt to access the response object but it will throw an error:
response##Object; /* Does not work :( */
Instead, use an alias
to modify the response:
{
object: Object {
id
title
}
}
Then you can access the object like this:
response##object
You can create a generic error and Loading component and compose them like this example:
module QueryView = {
[@react.component]
let make =
(
~result: ReasonApolloTypes.queryResponse('a),
~accessData: 'a => option('b),
~render: ('b, 'c) => React.element,
~onLoadMore: ('b, 'unit) => unit=(_, ()) => (),
) => {
switch (result) {
| Error(error) => <Error />
| Loading => ReasonReact.null
| Data(response) =>
switch (accessData(response)) {
| Some(data) => render(data, onLoadMore(data))
| _ => <Error error="" />
}
};
};
};
In some cases, it seems like there are some differences between the provided send-introspection-query
and output from tools you might be using to download the schema (such as apollo-codegen
or graphql-cli
). If your build is failing, please make sure to try with the provided script. In your project root, run:
npx get-graphql-schema ENDPOINT_URL -j > graphql_schema.json
Author: apollographql
Source Code: https://github.com/apollographql/reason-apollo
License: MIT License
1651888800
This repository contains the Apollo Client Browser Devtools extension for Chrome & Firefox.
The Apollo Client Browser Devtools appear as an "Apollo" tab in your web browser inspector, alongside other tabs like "Elements" and "Console". The devtools currently have four main features:
You can install the extension via Firefox Browser Add-ons or the Chrome Webstore. If you want to install a local version of the extension instead, skip ahead to the Developing section.
While your application is in dev mode, the devtools will appear as an "Apollo" tab in your web browser inspector. To enable the devtools for your application in production, pass connectToDevTools: true
to the ApolloClient constructor in your application. Pass connectToDevTools: false
if want to manually disable this functionality.
The "Apollo" tab will appear in your web browser inspector if a global window.__APOLLO_CLIENT__
object exists in your application. Apollo Client adds this hook to the window automatically unless process.env.NODE_ENV === 'production'
. If you would like to use the devtools in production, manually attach your Apollo Client instance to window.__APOLLO_CLIENT__
or pass connectToDevTools: true
to the constructor.
If you are seeing the "Apollo" tab but are still having issues, skip ahead to the Debugging section.
After cloning this repo, install the required packages:
cd apollo-client-devtools
npm install
We provide a sample application to run when developing and testing the extension. To run it, install the required dependencies for both the client and server:
npm run install:dev
Then start the application:
npm run start:dev
Navigate to localhost:3000
to view the application. To view the API schema, navigate to localhost:4000
.
For cross-browser development, we rely on the web-ext command line tool and a modified version of the WebExtWebpackPlugin that hooks into the build process.
To develop with Firefox, run the following command:
npm run firefox
For Chrome, run the following command:
npm run chrome
Running either of these commands will:
webpack --watch
to watch source files for changeslocalhost:3000
(the sample application)Note that even though the extension is rebuilt and reloaded, a hard refresh is still required. Hot reloading is not an option for web extensions.
Defaults can be found and modified in the WebExtPlugin. You might want to do so if you'd like the targeted browser to open to a different address or to turn on lintOnBuild
.
We use Jest and the React Testing Library to write and run our tests.
To run tests for both src
and development
, run the following command:
npm run test
You can also run with --watch
to watch and re-run tests automatically:
npm run test:watch
There are two main pieces of the Apollo Client Browser Devtools: the extension itself and a React application. The extension is the code that communicates with the browser. It allows us to search an inspected window for an instance of Apollo Client and to create the Apollo tab in the browser's devtools panel. The React application powers the experience in the devtools panel.
The devtools folder structure mirrors this architecture. The source code for the extension can be found in src/extension
. The React application code can be found in src/application
.
For builds, we use the build
folder. After a build, all of the files needed to run the devtools can be found here. If these files are bundled for development, source maps are provided. When these files are bundled for production, source maps are not provided and the code is minified. We use the dist
folder for distributable zip files.
The Apollo Client Devtools project is split up by Screens. In the navigation of the Apollo Client Devtools you can select from Explorer, Queries, Mutations and Cache. Each of these Screens has their own React component and is wrapped in a Layout component.
The Explorer is an Embedded iframe that renders Apollo Studio's Explorer. The Explorer accepts post messages from the dev tools to populate the schema and to communicate network requests and responses. All network requests are done in this app via the parent page's Apollo Client instance. Documentation for all of the configurable properties of the Embedded Explorer can be found in the studio docs.
hook.ts
is where we hook into the Apollo Client instance of the parent page and execute operations. In initializeHook
we set up a communication between the client page and the Apollo Client Devtools tab via an instance of Relay.ts
using postMessage. The hook sends the tab information from the parent page, such as the queries, mutations & the cache info on this page (from the Apollo Client instance), responses that come back from Devtools-triggered network requests, and when the page is reloading.
tabRelay.ts
is injected into each tab via script tag. Any communication that needs to go from the client to the Apollo Client Devtools need to be forwarded in tabRelay.ts
.
devtools.ts
is the file where all Apollo Client Devtools communication happens. In this file, network communications for executed operations are forwarded to the Explorer. This is also the file where incoming client messages about the tab state are handled & acted on. Any communication that needs to go from the Apollo Client Devtools to the client needs to be forwarded in devtools.ts
.
explorerRelay.ts
is a file with a bunch of exported functions that are specific to the Explorer network communications for executed operations. devtools.ts
uses the functions as callbacks for its incoming messages, and Explorer.tsx
uses the functions to dispatch network requests & accept responses to display in the embedded Explorer.
When requests are triggered by the user from Explorer, sendExplorerRequest
in explorerRelay.ts
dispatches an EXPLORER_REQUEST
event which is picked up in devtools.ts
and forwarded to the client. In hook.ts
the EXPLORER_REQUEST
message is listened for, and an operation is executed. When a response for this network request is recieved by the client, EXPLORER_RESPONSE
is sent to the tab by the client in hook.ts
. This message is forwarded in tabRelay.ts
to the devtools, which calls sendResponseToExplorer
which is picked up by receiveExplorerResponses
called in Explorer.tsx
.
If there is an error in the devtools panel, you can inspect it just like you would inspect a normal webpage.
In Chrome, detach the inspector console from the window (if it's not already detached) by clicking the button with three vertical dots in the upper right corner of the console and selecting the detach option. With the detached console in focus, press opt-cmd-I
again to open an inspector for the detached console (inspector inception). In this new inspector you will be able to inspect elements in the first inspector, including the devtools panel.
In Firefox, go to about:debugging
, click on This Firefox
, find the Apollo Devtool extension and click Inspect
.
If you are using Apollo Client 2.0, make sure you are using at least version 2.0.5 of the devtools.
If you are using Apollo Client 3.0, make sure you are using at least version 2.3.5 of the devtools.
If you're seeing an error that's being caused by the devtools, please open an issue on this repository with a detailed explanation of the problem and steps that we can take to replicate the error.
Release process, for those with permission:
./package.json
and ./src/extension/manifest.json
version numbers.npm publish
in the root of the project. We're publishing to npm to allow other projects to have a dependency on devtools.npm run zip
to pack all of the builds for submission.chrome://extensions/
Load unpacked
.apollo-client-devtools/build
directory.Apollo Client Devtools
extension to update.Package
then Upload new package
../dist/chrome.zip
file for upload.about:debugging#/runtime/this-firefox
Load Temporary Add-on
.apollo-client-devtools/dist/apollo_client_developer_tools-X.X.X.zip
file.apollo-client-devtools/dist/apollo_client_developer_tools-X.X.X.zip
for upload and submit.This project is governed by the Apollo Code of Conduct.
Apollo builds open-source software and a graph platform to unify GraphQL across your apps and services. We help you ship faster with:
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.
Author: apollographql
Source Code: https://github.com/apollographql/apollo-client-devtools
License: MIT License
1651878000
Apollo Client Devtools bridge for Apollo iOS.
ApolloDeveloperKit is an iOS / macOS library which works as a bridge between Apollo iOS client and Apollo Client Developer tools.
This library adds an ability to watch the sent queries or mutations simultaneously, and also has the feature to request arbitrary operations from embedded GraphiQL console.
>= 12.0
>= 0.34.0
, < 0.38.0
~> 2.0
If your are using Apollo < 0.34.0
, use ApolloDeveloperKit <= 0.15.0
.
Add the following lines to your Podfile.
pod 'Apollo'
pod 'ApolloDeveloperKit', '~> 0.15.0', configurations: ['Debug']
Then run pod install
.
Add the following lines to your Cartfile.
github "apollographql/apollo-ios"
github "manicmaniac/ApolloDeveloperKit"
Then run carthage update --platform iOS --use-xcframeworks
or carthage update --platform Mac --use-xcframeworks
.
You just need to drag and drop ApolloDeveloperKit.xcframework
to your project.
Add https://github.com/manicmaniac/ApolloDeveloperKit
to your dependencies.
Since Xcode 12 has only limited support for resources installed via Swift Package Manager, I recommend to use Xcode 12.4 or newer for Swift Package Manager users.
First, you need to declare a long-lived variable where ApolloDebugServer
belongs to, because as soon as you release the server, it stops running.
The following code assumes you already have a procedure that instantiates ApolloClient
in AppDelegate
.
class AppDelegate: UIResponder, UIApplicationDelegate {
private var server: ApolloDebugServer!
private var client: ApolloClient!
}
In order to hook Apollo's cache and network layer, you need to use DebuggableRequestChainNetworkTransport
and DebuggableNormalizedCache
instead of usual RequestChainNetworkTransport
and NormalizedCache
.
So the second step is to declare ApolloStore
using DebuggableNormalizedCache
.
Normally it should be put in the beginning of application, like UIApplication.application(_:didFinishLaunchingWithOptions:)
.
let cache = DebuggableNormalizedCache(cache: InMemoryNormalizedCache())
let store = ApolloStore(cache: cache)
Third, configure network layer and instantiate ApolloClient
with debuggable ingredients.
let interceptorProvider = LegacyInterceptorProvider(store: store)
let networkTransport = DebuggableRequestChainNetworkTransport(interceptorProvider: interceptorProvider, endpointURL: url)
self.client = ApolloClient(networkTransport: networkTransport: store: store)
Finally, create ApolloDebugServer
and run.
self.server = ApolloDebugServer(networkTransport: networkTransport, cache: cache)
self.server.start(port: 8081)
See Example/{iOS,macOS}/AppDelegate.swift
for full examples.
If you don't have Apollo Client Developer Tools, install it before proceeding the following steps.
Currently ApolloDeveloperKit
supports only version 2.x of Apollo Client Developer Tools.
http://localhost:8081
).ApolloDebugServer is running!
on your browser's tab.localhost
but you can check what it is with ApolloDebugServer.serverURL
.Apollo
tab.GraphiQL
, Queries
, Mutations
on the left pane.All instructions in this section are written based on Flipboard/FLEX's way.
Since ApolloDeveloperKit is originally designed for debug use only, it should not be exposed to end-users.
Fortunately, it is easy to exclude ApolloDeveloperKit framework from Release builds. The strategies differ depending on how you integrated it in your project, and are described below.
Please make sure your code is properly excluding ApolloDeveloperKit with #if DEBUG
statements before starting these instructions. Otherwise it will be linked to your app unexpectedly. See Example/AppDelegate.swift
to see how to do it.
CocoaPods automatically excludes ApolloDeveloperKit from release builds if you only specify the Debug configuration for CocoaPods in your Podfile.
ApolloDeveloperKit.framework
to the embedded binaries of your target, as it would otherwise be included in all builds (therefore also in release ones).$(PROJECT_DIR)/Carthage/Build/iOS
or $(PROJECT_DIR)/Carthage/Build/Mac
to your target Framework Search Paths (this setting might already be present if you already included other frameworks with Carthage). This makes it possible to import the ApolloDeveloperKit framework from your source files. It does not harm if this setting is added for all configurations, but it should at least be added for the debug one.Link Binary with Libraries
phase, for example), and which will embed ApolloDeveloperKit.framework
in debug builds only:if [ "$CONFIGURATION" = Debug ]; then
/usr/local/bin/carthage copy-frameworks
fi
Finally, add $(SRCROOT)/Carthage/Build/iOS/ApolloDeveloperKit.framework
or $(SRCROOT)/Carthage/Build/Mac/ApolloDeveloperKit.framework
as input file of this script phase.
Now there's no easy way but you can exclude ApolloDeveloperKit by setting user defined build variable named EXCLUDED_SOURCE_FILE_NAMES
. The value for the variable is a space-separated list of each filenames in ApolloDeveloperKit. Sorry for the inconvenience.
ApolloDeveloperKit
supports console redirection. When it is enabled, all logs written in stdout (usually written with print()
) and stderr (written with NSLog()
) are redirected to the web browser's console as well.
This feature is disabled by default so you may want to enable it explicitly.
debugServer = ApolloDebugServer(networkTransport: networkTransport, cache: cache)
debugServer.enableConsoleRedirection = true
Then open the console in your browser's developer tools. You will see logs in your iPhone or simulator.
In the browser console, logs written in stdout are colored in blue-green and stderr are orange so that you can distinguish them from ordinary browser logs.
Auto-generated API documentation is here.
Since Example app is slightly modified version of apollographql/frontpage-ios-app, you need to start apollographql/frontpage-server before running the app.
http://localhost:8081
in your browser.Author: manicmaniac
Source Code: https://github.com/manicmaniac/ApolloDeveloperKit
License: MIT License
1651827600
[2022-02-16] Notice: This tracing format was designed to provide tracing data from graphs to the Apollo Engine
engineproxy
, a project which was retired in 2018. We learned that a trace format which describes resolvers with a flat list of paths (with no way to aggregate similar nodes or repeated path prefixes) was inefficient enough to have real impacts on server performance, and so we have not been actively developing consumers or producers of this format for several years. Apollo Server (as of v3) no longer ships with support for producing this format, andengineproxy
which consumed it is no longer supported. We suggest that people looking for formats for describing performance traces consider either the Apollo Studio protobuf-based trace format or a more generic format such as OpenTelemetry.
Apollo Tracing is a GraphQL extension for performance tracing.
Thanks to the community, Apollo Tracing already works with most popular GraphQL server libraries, including Node, Ruby, Scala, Java, Elixir, Go and .NET, and it enables you to easily get resolver-level performance information as part of a GraphQL response.
Apollo Tracing works by including data in the extensions field of the GraphQL response, which is reserved by the GraphQL spec for extra information that a server wants to return. That way, you have access to performance traces alongside the data returned by your query.
It’s already supported by Apollo Engine, and we’re excited to see what other kinds of integrations people can build on top of this format.
We think this format is broadly useful, and we’d love to work with you to add support for it to your tools of choice. If you’re looking for a first idea, we especially think it would be great to see support for Apollo Tracing in GraphiQL and the Apollo Client developer tools!
If you’re interested in working on support for other GraphQL servers, or integrations with more tools, please get in touch on the #apollo-tracing
channel on the Apollo Slack.
The GraphQL specification allows servers to include additional information as part of the response under an extensions
key:
The response map may also contain an entry with key
extensions
. This entry, if set, must have a map as its value. This entry is reserved for implementors to extend the protocol however they see fit, and hence there are no additional restrictions on its contents.
Apollo Tracing exposes trace data for an individual request under a tracing
key in extensions
:
{
"data": <>,
"errors": <>,
"extensions": {
"tracing": {
"version": 1,
"startTime": <>,
"endTime": <>,
"duration": <>,
"parsing": {
"startOffset": <>,
"duration": <>,
},
"validation": {
"startOffset": <>,
"duration": <>,
},
"execution": {
"resolvers": [
{
"path": [<>, ...],
"parentType": <>,
"fieldName": <>,
"returnType": <>,
"startOffset": <>,
"duration": <>,
},
...
]
}
}
}
}
startTime
and endTime
of the request are timestamps in RFC 3339 format with at least millisecond but up to nanosecond precision (depending on platform support).Some more details (adapted from the description of the JSON encoding of Protobuf's Timestamp type):
A timestamp is encoded as a string in the RFC 3339 format. That is, the format is "{year}-{month}-{day}T{hour}:{min}:{sec}[.{frac_sec}]Z" where {year} is always expressed using four digits while {month}, {day}, {hour}, {min}, and {sec} are zero-padded to two digits each. The fractional seconds, which can go up to 9 digits (i.e. up to 1 nanosecond resolution), are optional. The "Z" suffix indicates the timezone ("UTC"); the timezone is required, though only UTC (as indicated by "Z") is presently supported. For example, "2017-01-15T01:30:15.01Z" encodes 15.01 seconds past 01:30 UTC on January 15, 2017. In JavaScript, one can convert a Date object to this format using the standard
toISOString()
method. In Python, a standarddatetime.datetime
object can be converted to this format usingstrftime
with the time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one can use the Joda Time'sISODateTimeFormat.dateTime()
to obtain a formatter capable of generating timestamps in this format.
Resolver timings should be collected in nanoseconds using a monotonic clock like process.hrtime()
in Node.js or System.nanoTime()
in Java.
The limited precision of numbers in JavaScript is not an issue for our purposes, because
Number.MAX_SAFE_INTEGER
nanoseconds is about 104 days, which should be plenty even for long running requests!
The server should keep the start time of the request both as wall time, and as monotonic time to calculate startOffset
s and duration
s (for the request as a whole and for individual resolver calls, see below).
The duration
of a request is in nanoseconds, relative to the request start, as an integer.
The startOffset
of parsing, validation, or a resolver call is in nanoseconds, relative to the request start, as an integer.
The duration
of parsing, validation, or a resolver call is in nanoseconds, relative to the resolver call start, as an integer.
The end of a resolver call represents the return of a value for a field, but it does not include resolving subfields. If an asynchronous value such as a promise is returned from a resolver however, the resolver call isn't considered to have ended until the asynchronous value has been resolved.
The path
is the response path of the current resolver in a format similar to the error result format specified in the GraphQL specification:
This field should be a list of path segments starting at the root of the response and ending with the field associated with the error. Path segments that represent fields should be strings, and path segments that represent list indices should be 0‐indexed integers. If the error happens in an aliased field, the path to the error should use the aliased name, since it represents a path in the response, not in the query.
parentType
, fieldName
and returnType
are strings that reflect the runtime type information usually passed to resolvers (e.g. in the info
argument for graphql-js
).
query {
hero {
name
friends {
name
}
}
}
{
"data": {
"hero": {
"name": "R2-D2",
"friends": [
{
"name": "Luke Skywalker"
},
{
"name": "Han Solo"
},
{
"name": "Leia Organa"
}
]
}
},
"extensions": {
"tracing": {
"version": 1,
"startTime": "2017-07-28T14:20:32.106Z",
"endTime": "2017-07-28T14:20:32.109Z",
"duration": 2694443,
"parsing": {
"startOffset": 34953,
"duration": 351736,
},
"validation": {
"startOffset": 412349,
"duration": 670107,
},
"execution": {
"resolvers": [
{
"path": [
"hero"
],
"parentType": "Query",
"fieldName": "hero",
"returnType": "Character",
"startOffset": 1172456,
"duration": 215657
},
{
"path": [
"hero",
"name"
],
"parentType": "Droid",
"fieldName": "name",
"returnType": "String!",
"startOffset": 1903307,
"duration": 73098
},
{
"path": [
"hero",
"friends"
],
"parentType": "Droid",
"fieldName": "friends",
"returnType": "[Character]",
"startOffset": 1992644,
"duration": 522178
},
{
"path": [
"hero",
"friends",
0,
"name"
],
"parentType": "Human",
"fieldName": "name",
"returnType": "String!",
"startOffset": 2445097,
"duration": 18902
},
{
"path": [
"hero",
"friends",
1,
"name"
],
"parentType": "Human",
"fieldName": "name",
"returnType": "String!",
"startOffset": 2488750,
"duration": 2141
},
{
"path": [
"hero",
"friends",
2,
"name"
],
"parentType": "Human",
"fieldName": "name",
"returnType": "String!",
"startOffset": 2501461,
"duration": 1657
}
]
}
}
}
}
We recommend that people enable compression in their GraphQL server, because the tracing format adds to the response size, but compresses well.
Although we tried other approaches to make the tracing format more compact (including deduplication of keys, common items, and structure) this complicated generating and interpreting trace data, and didn't bring the size down as much as compressing the entire HTTP response body does.
In our tests on Node.js, the processing overhead of compression is less than the overhead of sending additional bytes for an uncompressed response. But more test results from different server environments are definitely welcome, so we can help people make an informed decision about this.
Author: apollographql
Source Code: https://github.com/apollographql/apollo-tracing
License:
1651824000
A GraphQL client shard for the Crystal language.
Installing
Just add this to your shards.yml file:
dependencies:
crystal-gql:
github: itsezc/crystal-gql
Then run:
shards install
Initializing
require "crystal-gql"
# Define the client
api = GraphQLClient.new "https://countries.trevorblades.com"
Querying
# useQuery
data, error, loading = api.useQuery(GQL {
"continents" => [
"code",
"name",
{
"countries" => [
"name",
"capital",
{
"languages" => [
"name"
]
}
]
}
]
})
# or traditional queries
data, error, loading = api.query("{
continents {
code
name
countries {
name
capital
languages {
name
}
}
}
}")
# Print data
print data
Querying
With authentication:
api.add_header("Authorization", "Bearer: TOKEN")
# useQuery
data, error, loading = api.useQuery(GQL {
"continents" => [
"code",
"name",
{
"countries" => [
"name",
"capital",
{
"languages" => [
"name"
]
}
]
}
]
})
Author: itsezc
Source Code: https://github.com/itsezc/crystal-gql
License: MIT License
1651716762
In this tutorial, you will learn how to connect to GraphQL APIs in your Vue application. You will use a really great library called Apollo for Vue which works well with Vue 3.
In this post, we are going to take a look at how we can make use of the GraphQL API within our Vue.JS based application.
In order for our app to communicate with our Strapi GraphQL API, we are going to add some additional packages to our Vue.JS Application. The package we are going to is the Apollo client and the Additional Vue-Apollo
Apollo is a set of tools and community effort to help you use GraphQL in your apps. It’s well known for its client and its server
Apollo Client brings a tool to front-end development to make GraphQL queries/mutations easier. It acts as an HTTP client that connects to a GraphQL API and provides caching, error handling, and even state management capabilities.
We need to install a number of packages to our application, so using whichever package manager you prefer install the following dependencies. In my case I will use npm
npm install apollo-client apollo-link-http apollo-cache-inmemory apollo-link-error vue-apollo graphql graphql-tag
We are making use of environment variables in our Vue.JS application, so we are going to add an additional variable to both our env.development
and env.production
files which will contain the link to our Development and Production URL’s to our API.
Our Development environment will look something similar too
VUE_APP_SOURCELINK_API_URL='https://localhost:1337/graphql'
We can start to implement our Apollo configuration, in order to do so we will create a new folder in ~/src folder and call it graphql, you can name this folder whatever you want, but I am going to call it graphql as it just defines what it’s purpose is.
In the folder we’ll create a new JavaScript file and cunningly name it apollo.js , then we’ll add the following code
import Vue from 'vue';
import { ApolloClient } from 'apollo-client';
import { HttpLink } from 'apollo-link-http';
import { onError } from 'apollo-link-error';
import { InMemoryCache } from 'apollo-cache-inmemory';
import VueApollo from 'vue-apollo';
const httpLink = new HttpLink({
uri: process.env.VUE_APP_SOURCELINK_API_URL,
});
// Error Handling
const errorLink = onError(({ graphQLErrors, networkError }) => {
if (graphQLErrors) {
graphQLErrors.map(({ message, locations, path }) => console.log(
<code data-enlighter-language="generic" class="EnlighterJSRAW">[GraphQL error]: Message: ${message}, Location: ${locations}, Path: ${path}</code>,
));
}
if (networkError) console.log(<code data-enlighter-language="generic" class="EnlighterJSRAW">[Network error]: ${networkError}</code>);
});
// Create the apollo client
export const apolloClient = new ApolloClient({
link: errorLink.concat(httpLink),
cache: new InMemoryCache(),
connectToDevTools: true,
});
Vue.use(VueApollo);
export const apolloProvider = new VueApollo({
defaultClient: apolloClient,
});
There is quite a bit to explain in the code, but essentially HttpLink
is an object that requires a uri
property, which refers to the GraphQL endpoint from the API being used. Ex: localhost:1337/graphql
A new ApolloClient
instance needs to be created, where the link, cache instance, and further options can be set.
We wrap our ApolloClient
inside a VueApollo
instance so we can use its hooks inside our Vue components.
We have started to add the capability to introduce some error handling and logging using the errorLink
, for now we are simply going to log this to console window, but in future will implement a more robust set of utilities.
We will also now need edit our main.js
to import our ApolloProvider and add it to our Vue instance.
import 'bootstrap-css-only/css/bootstrap.min.css';
import 'mdbvue/build/css/mdb.css';
import Vue from 'vue';
import { firestorePlugin } from 'vuefire';
import App from './App.vue';
import router from './router';
import store from './store';
import './registerServiceWorker';
import { apolloProvider } from './graphql/apollo';
Vue.config.productionTip = false;
Vue.use(firestorePlugin);
new Vue({
router,
store,
apolloProvider,
render: h => h(App),
}).$mount('#app');
We are now going to create a folder to contain all our GraphQL queries. In our particular application we will not be using mutations and our app will only be using our GraphQL API to access read-only reference data at this stage. Therefore we will only be adding one folder name queries.
In the queries folder we’ll create a new JavaScript file name skillQueries.js
which will use to add all our Skill Specific queries. Add the following code
import gql from 'graphql-tag';
// eslint-disable-next-line import/prefer-default-export
export const GET_LANGUAGES_QUERY = gql<code data-enlighter-language="generic" class="EnlighterJSRAW">\n query getLanguages {\n languages( where: { Active: true } ) {\n nameWe\n } \n}</code>;
You may notice the query from Creating Reference Data API with Strapi and using GraphQL, we have deliberately kept it simple at this stage, so we don’t get bogged down in the complexities of GraphQL and we are just interested in getting this example to work.
All our configuration work is now done and we are now ready to consume our API in our application. In our Application we have created Skill.vue file which will be used to enable users to select their appropriate skills.
This is where we are going contact the API when the view loads and populate an Autocomplete text box with the values. We make use of MDB Vue Pro Material Component Framework to help to quickly create good looking UI.
In our example we are going to keep the UI as simple as possible so as not to distract from the implementation. We will use a Select List to display the items from the API and enable the user to select items to add to another List Item.
template>
<mdb-container class="mt-5 p-5">
<h1>Skills</h1>
<mdb-row class="mt-3 p-3">
<mdb-col>
<mdb-card>
<mdb-card-body>
<mdb-card-title class="section-title">Programming Languages</mdb-card-title>
<mdb-row>
<mdb-col>
<mdb-select search v-model="languages"
id="language"
label="Language"
@getvalue="selectedLanguage"/>
</mdb-col>
<mdb-col>
<mdb-btn @click="addLanguage">
<mdb-icon icon="plus"></mdb-icon>
</mdb-btn>
</mdb-col>
</mdb-row>
<mdb-row>
<mdb-col>
<mdb-list-group>
<mdb-list-group-item v-for="language in selLanguage"
v-bind:key="language">{{ language }}
</mdb-list-group-item>
</mdb-list-group>
</mdb-col>
</mdb-row>
</mdb-card-body>
</mdb-card>
</mdb-col>
<mdb-col></mdb-col>
</mdb-row>
</mdb-container>
</template>
Our application will look similar to this, with just enough to illustrate the functionality.
We are going to make a call to our Reference Data API to get the values to populate our List box with making use of our Apollo implementation we defined earlier.
We are going to mark our mounted
method as async
so we don’t slow down view loading.
data() {
return {
languages: [],
selectedLanguages: [],
};
},
async mounted() {
this.$apollo.query({ query: GET_LANGUAGES_QUERY })
.then((response) => {
response.data.languages.forEach((language) => {
this.languages.push({ text: language.name, value: language.name });
});
});
this.languages.sort();
},
If you start the application now, and ensure that your API is available. Your page will now load and the values will now be loaded in the select box.
We will now complete our example, with an implementation to select items from the list to populate our list of selected programming skills.
This is just rudimentary code, to implement an initial set of functionality. In forthcoming tutorials we are going to completely refactor this code, to enable other Vue.JS specific functionality and neaten up the UI a lot more.
methods: {
addLanguage() {
const selected = this.selectedLanguage();
if (selected !== undefined && !this.selectedLanguages.includes(selected)) {
this.selectedLanguages.push(selected);
this.selectedLanguages.sort();
}
},
selectedLanguage() {
const language = this.languages.find(option => option.selected === true);
if (language) {
return language.value;
}
},
},
For the purpose of our Demonstration and topic of this specific tutorial we are now complete.
In this tutorial, we have focused on how to configure our Vue.JS application to start to access a Strapi Reference Data API using GraphQL and the Apollo client.
This is a very basic implementation and we will now continue to build on this implementation over the course of a number of tutorials detailing how we will be building an Web and Mobile application for a software developer community website.
#apollo #vue #graphql #api #vue3
1651662000
apollo-gateway
powered by apollo server 3.x.Since it is a managed federation gateway, the mocked schema is the supergraph from Apollos Schema Registry
subgraph
has been published to the schema registry for the below mentioned has been published for the APOLLO_KEY
and APOLLO_GRAPH_REF
paircp .env.template .env
.env
and set a valid APOLLO_KEY
and APOLLO_GRAPH_REF
pairnpm install && npm run dev
Author: setchy
Source Code: https://github.com/setchy/apollo-server-3-mocked-federation
License:
1651626000
Apollo React example for Github GraphQL API with create-react-app
git clone https://github.com/katopz/react-apollo-graphql-github-example.git
cd react-apollo-graphql-github-example
npm i
config.default.js
into a file called config.js
, and replace xxx
with your username and passwordGITHUB_CLIENT_ID
and GITHUB_CLIENT_SECRET
with your credential.npm start
For
VSCode
you can pressF5
to run :)
Author: katopz
Source Code: https://github.com/katopz/react-apollo-graphql-github-example
License: MIT License
1650510251
Many developers use tools such as Apollo Client to generate TypeScript types from their GraphQL schemas. Let's go over how those tools read from standard GraphQL endpoints to introspect your APIs and generate TypeScript types for you.
#graphql #apollo #typescript
1648627200
Apollo Server is a community-maintained open-source GraphQL server. It works with many Node.js HTTP server frameworks, or can run on its own with a built-in Express server. Apollo Server works with any GraphQL schema built with GraphQL.js--or define a schema's type definitions using schema definition language (SDL).
Read the documentation for information on getting started and many other use cases and follow the CHANGELOG for updates.
Apollo Server is built with the following principles in mind:
Anyone is welcome to contribute to Apollo Server, just read CONTRIBUTING.md, take a look at the roadmap and make your first PR!
To get started with Apollo Server:
npm install apollo-server-<integration> graphql
There are two ways to install Apollo Server:
apollo-server
package.express
, koa
, hapi
, etc.), use the appropriate Apollo Server integration package.For more info, please refer to the Apollo Server docs.
In a new project, install the apollo-server
and graphql
dependencies using:
npm install apollo-server graphql
Then, create an index.js
which defines the schema and its functionality (i.e. resolvers):
const { ApolloServer, gql } = require('apollo-server');
// The GraphQL schema
const typeDefs = gql`
type Query {
"A simple type for getting started!"
hello: String
}
`;
// A map of functions which return data for the schema.
const resolvers = {
Query: {
hello: () => 'world',
},
};
const server = new ApolloServer({
typeDefs,
resolvers,
});
server.listen().then(({ url }) => {
console.log(`🚀 Server ready at ${url}`);
});
Due to its human-readability, we recommend using schema-definition language (SDL) to define a GraphQL schema--a
GraphQLSchema
object fromgraphql-js
can also be specified instead oftypeDefs
andresolvers
using theschema
property:const server = new ApolloServer({ schema: ... });
Finally, start the server using node index.js
and go to the URL returned on the console.
For more details, check out the Apollo Server Getting Started guide and the fullstack tutorial.
For questions, the Apollo community forum is a great place to get help.
While the standalone installation above can be used without making a decision about which web framework to use, the Apollo Server integration packages are paired with specific web frameworks (e.g. Express, Koa, hapi).
The following web frameworks have Apollo Server integrations, and each of these linked integrations has its own installation instructions and examples on its package README.md
:
A request context is available for each request. When context
is defined as a function, it will be called on each request and will receive an object containing a req
property, which represents the request itself.
By returning an object from the context
function, it will be available as the third positional parameter of the resolvers:
new ApolloServer({
typeDefs,
resolvers: {
Query: {
books: (parent, args, context, info) => {
console.log(context.myProperty); // Will be `true`!
return books;
},
}
},
context: async ({ req }) => {
return {
myProperty: true
};
},
})
The Apollo Server documentation contains additional details on how to get started with GraphQL and Apollo Server.
The raw Markdown source of the documentation is available within the docs/
directory of this monorepo--to contribute, please use the Edit on GitHub buttons at the bottom of each page.
If you wish to develop or contribute to Apollo Server, we suggest the following:
Fork this repository
Install Direnv (a tool that automatically sets up environment variables in project directories) or nvm. We use nvm to ensure we're running the expected version of Node (and we use Direnv to install and run nvm automatically).
Install the Apollo Server project on your computer
git clone https://github.com/[your-user]/apollo-server
cd apollo-server
direnv allow # sets up nvm for you; if you installed nvm yourself, try `nvm install` instead
npm install
npm test
npm run pretest && npx jest packages/apollo-server-foo/src/__tests__/bar.test.ts
. Note that you do need to re-compile TypeScript before each time you run a test, or changes across packages may not be picked up. Instead of running npm run pretest
from scratch before each test run, you can also run tsc --build tsconfig.json --watch
in another shell, or use the VSCode Run Build Task
to run that for you.Are you stuck? Want to contribute? Come visit us in the Apollo community forum!
Apollo builds open-source software and a graph platform to unify GraphQL across your apps and services. We help you ship faster with:
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.
Author: apollographql
Source Code: https://github.com/apollographql/apollo-server
License: MIT License
1648562400
Use @apollo/client and GraphQL from your Ember app.
This addon is battle tested: it has been used to build several large apps. As such, we've solved real-world problems such as reliable testing and preventing resource leaks by unsubscribing from watch queries.
ember install ember-apollo-client
This should also automatically install ember-fetch
and graphql
.
Install the Apollo Client Developer tools for Chrome for a great GraphQL developer experience!
For compatibility with Ember versions below 3.4, use version 1.x. For compatibility with Apollo Client v1 or v2, use version 1.x or 2.x of this addon.
In your app's config/environment.js
, configure the URL for the GraphQL API.
let ENV = {
...
apollo: {
apiURL: 'https://test.example/graphql',
// Optionally, set the credentials property of the Fetch Request interface
// to control when a cookie is sent:
// requestCredentials: 'same-origin', // other choices: 'include', 'omit'
},
...
}
Additional configuration of the ApolloClient can be done by extending the Apollo service and overriding the clientOptions
property. See the Apollo Service API for more info.
In your app's ember-cli-build.js
, you can set build time options for broccoli-graphql-filter to keep or remove file extensions in .graphql
files.
module.exports = function(defaults) {
let app = new EmberApp(defaults, {
emberApolloClient: {
keepGraphqlFileExtension: false
}
});
return app.toTree();
};
keepGraphqlFileExtension = true
, defaults to true
– If false
, creates files called my-query.js
instead of my-query.graphql.js
, so that you can import them as ./my-query
instead of ./my-query.graphql
.
Example:
import myQuery from 'my-app/queries/my-query.graphql';
This addon uses ember-auto-import to import dependencies.
This addon does not exposes any dependencies directly to your application, so if you desire any additional graphql or apollo dependencies, install them with npm/yarn and import as desired.
Here are some useful packages:
Make sure to use ember-auto-import in your application to import these additional packages.
This addon has a peer dependency of:
GraphQL queries should be placed in external files, which are automatically made available for import:
app/gql/queries/human.graphql
query human($id: String!) {
human(id: $id) {
name
}
}
You can also use the graphql-tag
package to write your queries within your JS file:
import gql from "graphql-tag";
const query = gql`
query human($id: String!) {
human(id: $id) {
name
}
}
`;
Note: Inline queries like the one above are compiled at runtime. This is both slower than external files (which are precompiled) and involves shipping extra dependencies in your vendor.js. For the time being, we recommend using external files for your queries.
If you are looking for an opportunity to contribute, enabling precompilation of inline queries would be a fantastic feature to work on.
Within your routes, you can query for data using the queryManager
computed macro and watchQuery
:
app/routes/some-route.js
import Route from "@ember/routing/route";
import { queryManager } from "ember-apollo-client";
import query from "my-app/gql/queries/human.graphql";
export default Route.extend({
apollo: queryManager(),
model(params) {
let variables = { id: params.id };
return this.apollo.watchQuery({ query, variables }, "human");
}
});
This performs a watchQuery
on the ApolloClient. The resulting object is a POJO.
If a subsequent query (such as a mutation) happens to fetch the same data while this query's subscription is still active, the object will immediately receive the latest attributes (just like ember-data).
Please note that when using watchQuery
, you must unsubscribe when you're done with the query data. You should only have to worry about this if you're using the Apollo service directly. If you use the queryManager
computed macro in your routes, or in your data-loading components or class that extend Ember.Object
, all active watch queries are tracked and unsubscribed when the route is exited or the component and Ember.Object is destroyed.
You can instead use query
if you just want a single query with a POJO response and no watch updates.
If you need to access the Apollo Client ObservableQuery, such as for pagination, you can retrieve it from a watchQuery
result using getObservable
:
import Route from "@ember/routing/route";
import { getObservable, queryManager} from "ember-apollo-client";
export default Route.extend({
apollo: queryManager(),
model() {
let result = this.apollo.watchQuery(...);
let observable = getObservable(result);
observable.fetchMore(...) // utilize the ObservableQuery
...
}
});
See the detailed query manager docs for more details on usage, or the Apollo service API if you need to use the service directly.
GQL Subscriptions allow a client to subscribe to specific queries they are interested in tracking. The syntax for doing this is similar to query
/ watchQuery
, but there are a few main differences:
subscription
(versus a query
or mutation
)link
accordinglyapp/gql/subscriptions/new-human.graphql
subscription {
newHuman() {
name
}
}
app/routes/some-route.js
import Route from '@ember/routing/route';
import { queryManager } from 'ember-apollo-client';
import query from 'app/gql/subscriptions/new-human';
import { addListener, removeListener } from '@ember/object/events';
const handleEvent = event => alert(`${event.name} was just born!`);
export default Route.extend({
apollo: queryManager(),
model() {
return this.get('apollo').subscribe({ query }, 'human');
},
setupController(controller, model) {
addListener(model, 'event', handleEvent);
},
resetController(controller, isExiting, transition) {
if (isExiting) {
removeListener(controller.model, 'event', handleEvent);
}
}
});
The big advantage of using the queryManager
is that when you navigate away from this route, all subscriptions created will be terminated. That said, if you want to manually unsubscribe (or are not using the queryManager
) subscription.unsubscribe()
will do the trick.
Enabling Websockets
While this library should work w/ any back-end implementation, here's an example with Authenticated Phoenix + Absinthe:
my-app/services/apollo.js
import ApolloService from 'ember-apollo-client/services/apollo';
import { inject as service } from '@ember/service';
import { Socket } from 'phoenix';
import { createAbsintheSocketLink } from '@absinthe/socket-apollo-link';
import AbsintheSocket from '@absinthe/socket';
class OverriddenApollo extends ApolloService {
@service
session;
link() {
const socket = new Socket("ws://socket-url", {
params: { token: this.get('session.token') },
});
const absintheSocket = AbsintheSocket.create(socket);
return createAbsintheSocketLink(absintheSocket);
}
}
Note: This will switch all gql communication to use websockets versus http
. If you want to conditionally use websockets for only subscriptions (a common pattern) this is where Apollo Link Composition comes in. Specifically, the split
function is what we're after (note we are using apollo-utilities, a helpful npm
package):
my-app/services/apollo.js
import ApolloService from 'ember-apollo-client/services/apollo';
import { inject as service } from '@ember/service';
import { Socket } from 'phoenix';
import { split } from '@apollo/client';
import { getMainDefinition } from '@apollo/client/utilities';
import { createAbsintheSocketLink } from '@absinthe/socket-apollo-link';
import AbsintheSocket from '@absinthe/socket';
class OverriddenApollo extends ApolloService {
@service
session;
link() {
let httpLink = super.link();
const socket = new Socket("ws://socket-url", {
params: { token: this.get('session.token') },
});
const socketLink = createAbsintheSocketLink(AbsintheSocket.create(socket));
return split(
({ query }) => {
const { kind, operation } = getMainDefinition(query);
return kind === 'OperationDefinition' && operation === 'subscription';
},
socketLink,
httpLink
);
}
}
Note: You will need to add the following dependencies to your project:
yarn add -D @apollo/client
yarn add -D @absinthe/socket
yarn add -D @absinthe/socket-apollo-link
You can perform a mutation using the mutate
method. You can also use GraphQL fragments in your queries. This is especially useful if you want to ensure that you refetch the same attributes in a subsequent query or mutation involving the same model(s).
The following example shows both mutations and fragments in action:
app/gql/fragments/review-fragment.graphql
fragment ReviewFragment on Human {
stars
commentary
}
app/gql/mutations/create-review.graphql
#import ReviewFragment from 'my-app/gql/fragments/review-fragment.graphql'
mutation createReview($ep: Episode!, $review: ReviewInput!) {
createReview(episode: $ep, review: $review) {
review {
...ReviewFragment
}
}
}
app/routes/my-route.js
import Route from "@ember/routing/route";
import { inject as service } from "@ember/service";
import mutation from "my-app/gql/mutations/create-review.graphql";
export default Route.extend({
apollo: service(),
actions: {
createReview(ep, review) {
let variables = { ep, review };
return this.get("apollo").mutate({ mutation, variables }, "review");
}
}
});
watchQuery(options, resultKey)
: This calls the ApolloClient.watchQuery
method. It returns a promise that resolves with a POJO. That object will be updated whenever the watchQuery
subscription resolves with new data. As before, the resultKey
can be used to resolve beneath the root.
The query manager will automatically unsubscribe from this object.
subscribe(options, resultKey)
: This calls the ApolloClient.subscribe
method. It returns a promise that resolves with an EmberApolloSubscription
. You can use this object in a few ways to keep track of your subscription:
//import { addListener, removeListener } from '@ember/object/events';
const result = await this.apollo.subscribe(
{
subscription: mySubscription,
}
);
const handleEvent = event => {
console.log('event received', event)
};
// Add listener to new data
addListener(result, 'event', handleEvent);
// Remove the listener from new data
removeListener(result, 'event', handleEvent);
query(options, resultKey)
: This calls the ApolloClient.query
method. It returns a promise that resolves with the raw POJO data that the query returns. If you provide a resultKey
, the resolved data is grabbed from that key in the result.
mutate(options, resultKey)
: This calls the ApolloClient.mutate
method. It returns a promise that resolves with the raw POJO data that the mutation returns. As with the query methods, the resultKey
can be used to resolve beneath the root.
You should not need to use the Apollo service directly for most regular usage, instead utilizing the queryManager
computed macro. However, you will probably need to customize options on the apollo
service, and might need to query it directly for some use cases (such as loading data from a service rather than a route or component).
The apollo
service has the following public API:
clientOptions
: This function should return the options hash that will be passed to the ApolloClient
constructor. You can override this function to configure the client this service uses:
class OverriddenApolloService extends ApolloService {
clientOptions() {
return {
link: this.link(),
cache: this.cache(),
};
}
}
link
: This function provides a list of middlewares and afterwares to the Apollo Link the interface for fetching and modifying control flow of GraphQL requests. To create your middlewares/afterwares:
link() {
let httpLink = super.link()
// Middleware
let authMiddleware = setContext(async(request, context) => {
if (!token) {
token = await localStorage.getItem('token') || null;
}
Object.assign(context.headers, {
headers: {
authorization: token
}
});
return context;
});
// Afterware
const resetToken = onError(({ networkError }) => {
if (networkError && networkError.statusCode === 401) {
// remove cached token on 401 from the server
token = undefined;
}
});
const authFlowLink = authMiddleware.concat(resetToken);
return authFlowLink.concat(httpLink);
}
Example with ember-simple-auth:
import ApolloService from 'ember-apollo-client/services/apollo';
import { inject as service } from '@ember/service';
import { setContext } from '@apollo/client/link/context';
import { Promise } from 'rsvp';
class OverriddenApollo extends ApolloService {
@service
session;
link() {
let httpLink = super.link();
let authLink = setContext((request, context) => {
return this._runAuthorize(request, context);
});
return authLink.concat(httpLink);
}
_runAuthorize() {
if (!this.get('session.isAuthenticated')) {
return {};
}
return new Promise(success => {
let headers = {};
let token = this.get('session.data.authenticated.token');
headers['Authorization'] = `Bearer ${token}`;
success({ headers });
});
}
}
Note: You will need to add the following dependencies to your project:
yarn add -D @apollo/client
watchQuery(options, resultKey)
: This calls the ApolloClient.watchQuery
method. It returns a promise that resolves with a POJO. That object will be updated whenever the watchQuery
subscription resolves with new data. As before, the resultKey
can be used to resolve beneath the root.
When using this method, it is important to unsubscribe from the query when you're done with it.
query(options, resultKey)
: This calls the ApolloClient.query
method. It returns a promise that resolves with the raw POJO data that the query returns. If you provide a resultKey
, the resolved data is grabbed from that key in the result.
mutate(options, resultKey)
: This calls the ApolloClient.mutate
method. It returns a promise that resolves with the raw POJO data that the mutation returns. As with the query methods, the resultKey
can be used to resolve beneath the root.
Apollo Client's watchQuery
will continue to update the query with new data whenever the store is updated with new data about the resolved objects. This happens until you explicitly unsubscribe from it.
In ember-apollo-client
, most unsubscriptions are handled automatically by the queryManager
computed macro, so long as you use it.
If you're fetching data elsewhere, such as in an Ember Service, or if you use the Apollo service directly, you are responsible for unsubscribing from watchQuery
results when you're done with them, you can use unsubscribe
:
import Service from "@ember/service";
import { unsubscribe } from "ember-apollo-client";
import { inject as service } from '@ember/service';
export default Service.extend( {
apollo: service(),
result: null,
init() {
this._super(...arguments);
this.result = this.apollo.watchQuery(...);
},
willDestroy() {
unsubscribe(this.result)
}
});
The queryManager
computed macro can be used as a decorator when using Ember v3.10.0 or above.
import Route from '@ember/routing/route';
import { queryManager } from 'ember-apollo-client'
import query from 'my-app/gql/queries/human.graphql';
export default class MyAwesomeRoute extends Route {
@queryManager apollo;
model({ id }) {
let variables = { id };
return this.apollo.watchQuery({ query, variables });
}
}
The queryManager
computed macro can accept an options hash with the name of the service to use as apollo. If your application has a custom apollo service or multiple apollo services that extends from ember-apollo-client/services/apollo
, you can use this option to specify which apollo service to use.
// imports ...
export default class MyAwesomeRoute extends Route {
@queryManager({ service: 'my-custom-apollo-service' }) apollo;
// ...
}
Ember Apollo Client works with FastBoot out of the box as long that SSR is enabled. In order to enable SSR, define it on apollo service:
Example:
class OverriddenApolloService extends ApolloService {
clientOptions() {
const opts = super.clientOptions();
return {...opts, ssrMode: true };
}
}
Since you only want to fetch each query result once, pass the ssrMode: true
option to the Apollo Client constructor to avoid repeated force-fetching.
If you want to intentionally skip a query during SSR, you can pass ssr: false
in the query options. Typically, this will mean the component will get rendered in its loading state on the server. For example:
actions: {
refetchModel() {
this.get('apollo').query({
query,
variables,
// Don't run this query on the server
ssr: false
});
}
}
When using TypeScript (with ember-cli-typescript in your Ember app) you will quickly run into an error like:
Cannot find module './users.graphql'.
This error happens when you import a *.graphql
file, e.g. import query from './users.graphql';
. The quick solution is to use // @ts-ignore
, but that is only a patch for the one place you've used the import.
To define basic types for those imports, you need to add the following to types/global.d.ts
:
// Apollo GraphQL imports
declare module '*.graphql' {
const doc: import('graphql').DocumentNode;
export default doc;
}
Note: The graphql
module above is included when you ember install ember-apollo-client
.
This addon is test-ready! All promises from the apollo service are tracked with Ember.Test.registerWaiter
, so your tests should be completely deterministic.
The dummy app contains example routes for mutations and queries:
The tests also contain a sample Star Wars GraphQL schema with an pretender setup for mock data.
git clone https://github.com/ember-graphql/ember-apollo-client
this repositorycd ember-apollo-client
yarn install
yarn run lint:hbs
yarn run lint:js
yarn run lint:js --fix
ember test
– Runs the test suite on the current Ember versionember test --server
– Runs the test suite in "watch mode"ember try:each
– Runs the test suite against multiple Ember versionsember serve
For more information on using ember-cli, visit https://ember-cli.com/.
A special thanks to the following contributors:
See the Contributing guide for details.
Author: ember-graphql
Source Code: https://github.com/ember-graphql/ember-apollo-client
License: MIT License
1648555200
Svelte integration for Apollo GraphQL.
The following simple example shows how to run a simple query with svelte-apollo.
<!-- App.svelte -->
<Books />
<script>
import { ApolloClient } from "@apollo/client";
import { setClient } from "svelte-apollo";
import Books from "./Books.svelte";
// 1. Create an Apollo client and pass it to all child components
// (uses svelte's built-in context)
const client = new ApolloClient({
/* ... */
});
setClient(client);
</script>
<!-- Books.svelte -->
<script>
import { query } from "svelte-apollo";
import { GET_BOOKS } from "./queries";
// 2. Execute the GET_BOOKS GraphQL query using the Apollo client
// -> Returns a svelte store of promises that resolve as values come in
const books = query(GET_BOOKS);
</script>
<!-- 3. Use $books (note the "$"), to subscribe to query values -->
{#if $books.loading}
Loading...
{:else if $books.error}
Error: {$books.error.message}
{:else}
{#each $books.data.books as book}
{book.title} by {book.author.name}
{/each}
{/if}
# query(document[, options])
Query an Apollo client, returning a readable store of result values. Uses Apollo's watchQuery
, for fetching from the network and watching the local cache for changes. If the client is hydrating after SSR, it attempts a readQuery
to synchronously check the cache for values.
<script>
import { query } from "svelte-apollo";
import { GET_BOOKS } from "./queries";
const books = query(GET_BOOKS, {
// variables, fetchPolicy, errorPolicy, and others
});
function reload() {
books.refetch();
}
</script>
<ul>
{#if $books.loading}
<li>Loading...</li>
{:else if $books.error}
<li>ERROR: {$books.error.message}</li>
{:else}
{#each $books.data.books as book (book.id)}
<li>{book.title} by {book.author.name}</li>
{/each}
{/if}
</ul>
<button on:click="{reload}">Reload</button>
Reactive variables are supported with refetch
:
<script>
import { query } from "svelte-apollo";
import { SEARCH_BY_AUTHOR } from "./queries";
export let author;
let search = "";
const books = query(SEARCH_BY_AUTHOR, {
variables: { author, search },
});
// `books` is refetched when author or search change
$: books.refetch({ author, search });
</script>
Author: {author}
<label>Search <input type="text" bind:value="{search}" /></label>
<ul>
{#if $books.loading}
<li>Loading...</li>
{:else if $books.error}
<li>ERROR: {$books.error.message}</li>
{:else if $books.data}
{#each $books.data.books as book (book.id)}
<li>{book.title}</li>
{/each}
{:else}
<li>No books found</li>
{/if}
</ul>
# mutation(document[, options])
Prepare a GraphQL mutation with the Apollo client, using Apollo's mutate
.
<script>
import { mutation } from "svelte-apollo";
import { ADD_BOOK } from "./queries";
const addBook = mutation(ADD_BOOK);
let title = "";
let author = "";
async function handleSubmit() {
try {
await addBook({ variables: { title, author } });
} catch (error) {
// TODO
}
}
</script>
<form on:submit|preventDefault="{handleSubmit}">
<label for="book-author">Author</label>
<input type="text" id="book-author" bind:value="{author}" />
<label for="book-title">Title</label>
<input type="text" id="book-title" bind:value="{title}" />
<button type="submit">Add Book</button>
</form>
# subscribe(document[, options])
Subscribe using an Apollo client, returning a store that is compatible with {#await $...}
. Uses Apollo's subscribe
.
<script>
import { subscribe } from "svelte-apollo";
import { NEW_BOOKS } from "./queries";
const newBooks = subscribe(NEW_BOOKS);
</script>
{#if $newBooks.loading}
Waiting for new books...
{:else if $newBooks.data}
New Book: {$newBooks.data.book}
{/if}
# restore(document, options)
Restore a previously executed query (e.g. via preload) into the Apollo cache.
<script context="module">
import client from "./client";
import { GET_BOOKS } from "./queries";
export async function preload() {
return {
preloaded: await client.query({ query: GET_BOOKS }),
};
}
</script>
<script>
import { restore } from "svelte-apollo";
export let preloaded;
// Load preloaded values into client's cache
restore(GET_BOOKS, preloaded);
</script>
# setClient(client)
Set an Apollo client for the current component's and all child components' contexts.
<!-- Parent.svelte -->
<script>
import { setClient } from "svelte-apollo";
import client from "./client";
setClient(client);
</script>
# getClient()
Get an Apollo client from the current component's context.
<!-- Child.svelte -->
<script>
import { getClient } from "svelte-apollo";
const client = getClient();
</script>
Author: timhall
Source Code: https://github.com/timhall/svelte-apollo
License: MIT License
1648548000
Apollo Angular allows you to fetch data from your GraphQL server and use it in building complex and reactive UIs using the Angular framework. Apollo Angular may be used in any context that Angular may be used. In the browser, in NativeScript, or in Node.js when you want to do server-side rendering.
Apollo Angular requires no complex build setup to get up and running. As long as you have a GraphQL server you can get started building out your application with Angular immediately. Apollo Angular works out of the box with both Angular CLI (ng add apollo-angular
) and NativeScript with a single install.
Apollo Angular is:
Get started today on the app you’ve been dreaming of, and let Apollo Angular take you to the moon!
It is simple to install Apollo Angular and related libraries
# installing Apollo Angular in Angular CLI
ng add apollo-angular
# installing each piece independently
yarn add @apollo/client apollo-angular graphql
That’s it! You may now use Apollo Angular in any of your Angular environments.
For an amazing developer experience you may also install the Apollo Client Developer tools for Chrome which will give you inspectability into your Apollo Angular data.
apollo-angular@v3
If you are using Apollo-Client v2, please make sure to use
apollo-angular@v1
(and for Angular 10 support, make sure to usev1.10.0
)
Now you may create components that are connected to your GraphQL API.
Finally, to demonstrate the power of Apollo Angular in building interactive UIs let us connect one of your components to your GraphQL server using the Apollo
service:
import {Component, OnInit} from '@angular/core';
import {Apollo, gql} from 'apollo-angular';
const GET_DOGS = gql`
{
dogs {
id
breed
}
}
`;
@Component({
selector: 'dogs',
template: `
<ul>
<li *ngFor="let dog of dogs | async">
{{dog.breed}}
</li>
</ul>
`,
})
export class DogsComponent implements OnInit {
dogs: Observable<any>;
constructor(private apollo: Apollo) {}
ngOnInit() {
this.dogs = this.apollo
.watchQuery({
query: GET_DOGS,
})
.valueChanges.pipe(map(result => result.data && result.data.dogs));
}
}
To learn more about querying with Apollo Angular be sure to start reading the documentation article on queries.
All of the documentation for Apollo Angular including usage articles and helpful recipes lives on: https://www.apollo-angular.com/
Read the Apollo Contributor Guidelines.
This project uses Lerna.
Bootstraping:
yarn install
Running tests locally:
yarn test
Formatting code with prettier:
yarn prettier
This project uses TypeScript for static typing. You can get it built into your editor with no configuration by opening this project in Visual Studio Code, an open source IDE which is available for free on all platforms.
Author: kamilkisiela
Source Code: https://github.com/kamilkisiela/apollo-angular
License: MIT License
1648540800
📖 Documentation for Vue 3 | for Vue 2
In this monorepository:
Package | Description |
---|---|
@vue/apollo-composable | Composition API |
@vue/apollo-option | Options API |
@vue/apollo-components | Components with slots |
@vue/apollo-ssr | Server-Side Rendering Utils |
@vue/apollo-util | Other Utils |
Author: vuejs
Source Code: https://github.com/vuejs/apollo
License: MIT License
1648512000
Apollo Client is a fully-featured caching GraphQL client with integrations for React, Angular, and more. It allows you to easily build UI components that fetch data via GraphQL.
All Apollo Client documentation, including React integration articles and helpful recipes, can be found at:
https://www.apollographql.com/docs/react/
The Apollo Client API reference can be found at:
https://www.apollographql.com/docs/react/api/apollo-client/
Learn how to use Apollo Client with self-paced hands-on training on Odyssey, Apollo's official learning platform:
https://odyssey.apollographql.com/
Apollo builds open-source software and a graph platform to unify GraphQL across your apps and services. We help you ship faster with:
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.
Author: apollographql
Source Code: https://github.com/apollographql/apollo-client
License: MIT License