├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── examples ├── digitransit.dot ├── digitransit.json ├── digitransit.png └── digitransit.svg ├── project.clj ├── resources └── introspection.query └── src └── graphqlviz └── core.clj /.gitignore: -------------------------------------------------------------------------------- 1 | deps 2 | .nrepl-port 3 | /target 4 | /classes 5 | /checkouts 6 | pom.xml 7 | pom.xml.asc 8 | *.class 9 | /.lein-* 10 | /.nrepl-port 11 | .hgignore 12 | .hg/ 13 | *~ 14 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: clojure 2 | lein: lein2 3 | script: lein2 do clean, test 4 | jdk: 5 | - openjdk6 6 | - openjdk7 7 | - oraclejdk7 8 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC 2 | LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM 3 | CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. 4 | 5 | 1. DEFINITIONS 6 | 7 | "Contribution" means: 8 | 9 | a) in the case of the initial Contributor, the initial code and 10 | documentation distributed under this Agreement, and 11 | 12 | b) in the case of each subsequent Contributor: 13 | 14 | i) changes to the Program, and 15 | 16 | ii) additions to the Program; 17 | 18 | where such changes and/or additions to the Program originate from and are 19 | distributed by that particular Contributor. A Contribution 'originates' from 20 | a Contributor if it was added to the Program by such Contributor itself or 21 | anyone acting on such Contributor's behalf. Contributions do not include 22 | additions to the Program which: (i) are separate modules of software 23 | distributed in conjunction with the Program under their own license 24 | agreement, and (ii) are not derivative works of the Program. 25 | 26 | "Contributor" means any person or entity that distributes the Program. 27 | 28 | "Licensed Patents" mean patent claims licensable by a Contributor which are 29 | necessarily infringed by the use or sale of its Contribution alone or when 30 | combined with the Program. 31 | 32 | "Program" means the Contributions distributed in accordance with this 33 | Agreement. 34 | 35 | "Recipient" means anyone who receives the Program under this Agreement, 36 | including all Contributors. 37 | 38 | 2. GRANT OF RIGHTS 39 | 40 | a) Subject to the terms of this Agreement, each Contributor hereby grants 41 | Recipient a non-exclusive, worldwide, royalty-free copyright license to 42 | reproduce, prepare derivative works of, publicly display, publicly perform, 43 | distribute and sublicense the Contribution of such Contributor, if any, and 44 | such derivative works, in source code and object code form. 45 | 46 | b) Subject to the terms of this Agreement, each Contributor hereby grants 47 | Recipient a non-exclusive, worldwide, royalty-free patent license under 48 | Licensed Patents to make, use, sell, offer to sell, import and otherwise 49 | transfer the Contribution of such Contributor, if any, in source code and 50 | object code form. This patent license shall apply to the combination of the 51 | Contribution and the Program if, at the time the Contribution is added by the 52 | Contributor, such addition of the Contribution causes such combination to be 53 | covered by the Licensed Patents. The patent license shall not apply to any 54 | other combinations which include the Contribution. No hardware per se is 55 | licensed hereunder. 56 | 57 | c) Recipient understands that although each Contributor grants the licenses 58 | to its Contributions set forth herein, no assurances are provided by any 59 | Contributor that the Program does not infringe the patent or other 60 | intellectual property rights of any other entity. Each Contributor disclaims 61 | any liability to Recipient for claims brought by any other entity based on 62 | infringement of intellectual property rights or otherwise. As a condition to 63 | exercising the rights and licenses granted hereunder, each Recipient hereby 64 | assumes sole responsibility to secure any other intellectual property rights 65 | needed, if any. For example, if a third party patent license is required to 66 | allow Recipient to distribute the Program, it is Recipient's responsibility 67 | to acquire that license before distributing the Program. 68 | 69 | d) Each Contributor represents that to its knowledge it has sufficient 70 | copyright rights in its Contribution, if any, to grant the copyright license 71 | set forth in this Agreement. 72 | 73 | 3. REQUIREMENTS 74 | 75 | A Contributor may choose to distribute the Program in object code form under 76 | its own license agreement, provided that: 77 | 78 | a) it complies with the terms and conditions of this Agreement; and 79 | 80 | b) its license agreement: 81 | 82 | i) effectively disclaims on behalf of all Contributors all warranties and 83 | conditions, express and implied, including warranties or conditions of title 84 | and non-infringement, and implied warranties or conditions of merchantability 85 | and fitness for a particular purpose; 86 | 87 | ii) effectively excludes on behalf of all Contributors all liability for 88 | damages, including direct, indirect, special, incidental and consequential 89 | damages, such as lost profits; 90 | 91 | iii) states that any provisions which differ from this Agreement are offered 92 | by that Contributor alone and not by any other party; and 93 | 94 | iv) states that source code for the Program is available from such 95 | Contributor, and informs licensees how to obtain it in a reasonable manner on 96 | or through a medium customarily used for software exchange. 97 | 98 | When the Program is made available in source code form: 99 | 100 | a) it must be made available under this Agreement; and 101 | 102 | b) a copy of this Agreement must be included with each copy of the Program. 103 | 104 | Contributors may not remove or alter any copyright notices contained within 105 | the Program. 106 | 107 | Each Contributor must identify itself as the originator of its Contribution, 108 | if any, in a manner that reasonably allows subsequent Recipients to identify 109 | the originator of the Contribution. 110 | 111 | 4. COMMERCIAL DISTRIBUTION 112 | 113 | Commercial distributors of software may accept certain responsibilities with 114 | respect to end users, business partners and the like. While this license is 115 | intended to facilitate the commercial use of the Program, the Contributor who 116 | includes the Program in a commercial product offering should do so in a 117 | manner which does not create potential liability for other Contributors. 118 | Therefore, if a Contributor includes the Program in a commercial product 119 | offering, such Contributor ("Commercial Contributor") hereby agrees to defend 120 | and indemnify every other Contributor ("Indemnified Contributor") against any 121 | losses, damages and costs (collectively "Losses") arising from claims, 122 | lawsuits and other legal actions brought by a third party against the 123 | Indemnified Contributor to the extent caused by the acts or omissions of such 124 | Commercial Contributor in connection with its distribution of the Program in 125 | a commercial product offering. The obligations in this section do not apply 126 | to any claims or Losses relating to any actual or alleged intellectual 127 | property infringement. In order to qualify, an Indemnified Contributor must: 128 | a) promptly notify the Commercial Contributor in writing of such claim, and 129 | b) allow the Commercial Contributor tocontrol, and cooperate with the 130 | Commercial Contributor in, the defense and any related settlement 131 | negotiations. The Indemnified Contributor may participate in any such claim 132 | at its own expense. 133 | 134 | For example, a Contributor might include the Program in a commercial product 135 | offering, Product X. That Contributor is then a Commercial Contributor. If 136 | that Commercial Contributor then makes performance claims, or offers 137 | warranties related to Product X, those performance claims and warranties are 138 | such Commercial Contributor's responsibility alone. Under this section, the 139 | Commercial Contributor would have to defend claims against the other 140 | Contributors related to those performance claims and warranties, and if a 141 | court requires any other Contributor to pay any damages as a result, the 142 | Commercial Contributor must pay those damages. 143 | 144 | 5. NO WARRANTY 145 | 146 | EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON 147 | AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER 148 | EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR 149 | CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A 150 | PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the 151 | appropriateness of using and distributing the Program and assumes all risks 152 | associated with its exercise of rights under this Agreement , including but 153 | not limited to the risks and costs of program errors, compliance with 154 | applicable laws, damage to or loss of data, programs or equipment, and 155 | unavailability or interruption of operations. 156 | 157 | 6. DISCLAIMER OF LIABILITY 158 | 159 | EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY 160 | CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, 161 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION 162 | LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 163 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 164 | ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE 165 | EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY 166 | OF SUCH DAMAGES. 167 | 168 | 7. GENERAL 169 | 170 | If any provision of this Agreement is invalid or unenforceable under 171 | applicable law, it shall not affect the validity or enforceability of the 172 | remainder of the terms of this Agreement, and without further action by the 173 | parties hereto, such provision shall be reformed to the minimum extent 174 | necessary to make such provision valid and enforceable. 175 | 176 | If Recipient institutes patent litigation against any entity (including a 177 | cross-claim or counterclaim in a lawsuit) alleging that the Program itself 178 | (excluding combinations of the Program with other software or hardware) 179 | infringes such Recipient's patent(s), then such Recipient's rights granted 180 | under Section 2(b) shall terminate as of the date such litigation is filed. 181 | 182 | All Recipient's rights under this Agreement shall terminate if it fails to 183 | comply with any of the material terms or conditions of this Agreement and 184 | does not cure such failure in a reasonable period of time after becoming 185 | aware of such noncompliance. If all Recipient's rights under this Agreement 186 | terminate, Recipient agrees to cease use and distribution of the Program as 187 | soon as reasonably practicable. However, Recipient's obligations under this 188 | Agreement and any licenses granted by Recipient relating to the Program shall 189 | continue and survive. 190 | 191 | Everyone is permitted to copy and distribute copies of this Agreement, but in 192 | order to avoid inconsistency the Agreement is copyrighted and may only be 193 | modified in the following manner. The Agreement Steward reserves the right to 194 | publish new versions (including revisions) of this Agreement from time to 195 | time. No one other than the Agreement Steward has the right to modify this 196 | Agreement. The Eclipse Foundation is the initial Agreement Steward. The 197 | Eclipse Foundation may assign the responsibility to serve as the Agreement 198 | Steward to a suitable separate entity. Each new version of the Agreement will 199 | be given a distinguishing version number. The Program (including 200 | Contributions) may always be distributed subject to the version of the 201 | Agreement under which it was received. In addition, after a new version of 202 | the Agreement is published, Contributor may elect to distribute the Program 203 | (including its Contributions) under the new version. Except as expressly 204 | stated in Sections 2(a) and 2(b) above, Recipient receives no rights or 205 | licenses to the intellectual property of any Contributor under this 206 | Agreement, whether expressly, by implication, estoppel or otherwise. All 207 | rights in the Program not expressly granted under this Agreement are 208 | reserved. 209 | 210 | This Agreement is governed by the laws of the State of New York and the 211 | intellectual property laws of the United States of America. No party to this 212 | Agreement will bring a legal action under this Agreement more than one year 213 | after the cause of action arose. Each party waives its rights to a jury trial 214 | in any resulting litigation. 215 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # GraphQLviz [![Build Status](https://travis-ci.org/Macroz/GraphQLviz.svg?branch=master)](https://travis-ci.org/Macroz/GraphQLViz) 2 | 3 | GraphQLviz marries GraphQL (schemas) with Graphviz. 4 | 5 | It's a tool to show you what your schema really looks like. At the moment, it's mostly useful as a complement to [GraphiQL](https://github.com/graphql/graphiql), like printing a huge poster size version to facilitate team discussions. 6 | 7 | ## Quick Usage 8 | 9 | Requires [Graphviz](http://www.graphviz.org) and [Java Virtual Machine](http://openjdk.java.net/). 10 | 11 | There is a convenient uberjar release available to download from the [release page](https://github.com/Macroz/GraphQLviz/releases). 12 | 13 | Once you have Graphviz, Java and the uberjar, then you can use GraphQLviz like a regular Java app like so: 14 | 15 | ``` 16 | java -jar graphqlviz.jar https://api.digitransit.fi/routing/v1/routers/finland/index/graphql digitransit 17 | ``` 18 | 19 | [Example schema](examples/digitransit.json?raw=true) (from [Digitransit](http://digitransit.fi)) 20 | 21 | ![Example graph](https://rawgit.com/Macroz/GraphQLviz/master/examples/digitransit.svg) 22 | 23 | Run `java -jar graphqlviz.jar --help` for more options or read the Full Usage. 24 | 25 | ## Full Usage 26 | 27 | You must have Graphviz executable from command-line. Download and install it using your package manager or go to [Graphviz](http://www.graphviz.org). 28 | 29 | You also need [Leiningen](http://leiningen.org). Leiningen is the [Clojure](http://clojure.org) build tool that runs on the Java Virtual Machine. This means you also need Java. 30 | 31 | If you like to use Leiningen, you can run like this: 32 | ``` 33 | lein run https://api.digitransit.fi/routing/v1/routers/finland/index/graphql digitransit 34 | ``` 35 | 36 | There is a prepackaged jar in [Clojars](https://clojars.org/macroz/graphqlviz) so you don't have to build GraphQLviz yourself. 37 | 38 | Also there is a convenient uberjar release available to download from the [release page](https://github.com/Macroz/GraphQLviz/releases). 39 | 40 | With these JAR files you can run like this: 41 | 42 | ``` 43 | java -jar graphqlviz.jar https://api.digitransit.fi/routing/v1/routers/finland/index/graphql digitransit 44 | ``` 45 | 46 | If you want to use the code from Clojure, perhaps from your own program, add to your project.clj: 47 | 48 | [![Clojars Project](http://clojars.org/macroz/graphqlviz/latest-version.svg)](http://clojars.org/macroz/graphqlviz) 49 | 50 | ### Separate introspection 51 | 52 | Instead of running against a live GraphQL server, you can use a downloaded result of an introspection query like this: 53 | 54 | ``` 55 | java -jar graphqlviz.jar examples/digitransit.json digitransit 56 | ``` 57 | 58 | Otherwise, in the case of a URL, the introspection query is executed against the GraphQL endpoint and the results visualized. 59 | 60 | ### Authentication 61 | 62 | Since 0.4.0, you can pass options for authenticating with the server for the introspection query (`-a` or `--auth`). 63 | 64 | The supported authentication types are `basic`, `digest` (with user and password) as well as `oauth2` (with oauth token) See also `-h` for help. 65 | 66 | ``` 67 | java -jar graphqlviz.jar http://secret.example.com/graphql secret-schema-name -abasic -utester -ppassword 68 | ``` 69 | 70 | Or with password prompt `-pp` or `--password-prompt` (since 0.5.0). 71 | 72 | ``` 73 | java -jar graphqlviz.jar http://secret.example.com/graphql secret-schema-name -abasic -utester --password-prompt 74 | ``` 75 | 76 | ## Backlog 77 | 78 | - Use dynamic graph features as in [archi](https://github.com/Macroz/archi) 79 | - Develop a complete JavaScript solution of the same idea 80 | 81 | ## License 82 | 83 | Copyright © 2015-2017 Markku Rontu 84 | 85 | Distributed under the Eclipse Public License either version 1.0 or (at 86 | your option) any later version. 87 | -------------------------------------------------------------------------------- /examples/digitransit.dot: -------------------------------------------------------------------------------- 1 | digraph "digitransit" { 2 | graph[dpi=100, rankdir=LR, label="digitransit"] 3 | node[shape=none, margin=0] 4 | "QueryType"[label=<
QueryType

>] 5 | "Node"[label=<
Node

id: ID!
>] 6 | "Agency"[label=<
Agency

id: ID!
gtfsId: String!
name: String!
url: String!
timezone: String!
lang: String
phone: String
fareUrl: String
>] 7 | "Route"[label=<
Route

id: ID!
gtfsId: String!
shortName: String
longName: String
type: String
desc: String
url: String
color: String
textColor: String
>] 8 | "BikesAllowed"[label=<
BikesAllowed

«enum»
NO_INFORMATION
ALLOWED
NOT_ALLOWED
>] 9 | "Pattern"[label=<
Pattern

id: ID!
directionId: Int
name: String
code: String!
headsign: String
semanticHash: String
>] 10 | "Trip"[label=<
Trip

id: ID!
gtfsId: String!
serviceId: String
tripShortName: String
tripHeadsign: String
routeShortName: String
directionId: String
blockId: String
shapeId: String
geometry: String
>] 11 | "WheelchairBoarding"[label=<
WheelchairBoarding

«enum»
NO_INFORMATION
POSSIBLE
NOT_POSSIBLE
>] 12 | "Stop"[label=<
Stop

id: ID!
gtfsId: String!
name: String!
lat: Float!
lon: Float!
code: String
desc: String
zoneId: String
url: String
direction: String
timezone: String
vehicleType: Int
platformCode: String
>] 13 | "LocationType"[label=<
LocationType

«enum»
STOP
STATION
ENTRANCE
>] 14 | "Cluster"[label=<
Cluster

id: ID!
gtfsId: String!
name: String!
lat: Float!
lon: Float!
>] 15 | "stopAtDistance"[label=<
stopAtDistance

distance: Int
>] 16 | "StoptimesInPattern"[label=<
StoptimesInPattern

>] 17 | "Stoptime"[label=<
Stoptime

scheduledArrival: Int
realtimeArrival: Int
arrivalDelay: Int
scheduledDeparture: Int
realtimeDeparture: Int
departureDelay: Int
timepoint: Boolean
realtime: Boolean
serviceDay: Long
>] 18 | "Coordinates"[label=<
Coordinates

lat: Float
lon: Float
>] 19 | "stopAtDistanceConnection"[label=<
stopAtDistanceConnection

>] 20 | "stopAtDistanceEdge"[label=<
stopAtDistanceEdge

cursor: String!
>] 21 | "PageInfo"[label=<
PageInfo

hasNextPage: Boolean!
hasPreviousPage: Boolean!
startCursor: String
endCursor: String
>] 22 | 23 | "QueryType" -> "Node"[label="node(...)", labeltooltip="Fetches an object given its ID"] 24 | "QueryType" -> "Agency"[label="agencies", labeltooltip="Get all agencies for the specified graph"] 25 | "QueryType" -> "Agency"[label="agency(...)", labeltooltip="Get a single agency based on agency ID"] 26 | "QueryType" -> "Stop"[label="stops(...)", labeltooltip="Get all stops for the specified graph"] 27 | "QueryType" -> "Stop"[label="stopsByBbox(...)", labeltooltip="Get all stops within the specified bounding box"] 28 | "QueryType" -> "stopAtDistanceConnection"[label="stopsByRadius(...)", labeltooltip="Get all stops within the specified radius from a location. The returned type has two fields stop and distance"] 29 | "QueryType" -> "Stop"[label="stop(...)", labeltooltip="Get a single stop based on its id (format is Agency\:StopId)"] 30 | "QueryType" -> "Route"[label="routes(...)", labeltooltip="Get all routes for the specified graph"] 31 | "QueryType" -> "Route"[label="route(...)", labeltooltip="Get a single route based on its id (format is Agency\:RouteId)"] 32 | "QueryType" -> "Trip"[label="trips", labeltooltip="Get all trips for the specified graph"] 33 | "QueryType" -> "Trip"[label="trip(...)", labeltooltip="Get a single trip based on its id (format is Agency\:TripId)"] 34 | "QueryType" -> "Trip"[label="fuzzyTrip(...)", labeltooltip=""] 35 | "QueryType" -> "Pattern"[label="patterns", labeltooltip="Get all patterns for the specified graph"] 36 | "QueryType" -> "Pattern"[label="pattern(...)", labeltooltip="Get a single pattern based on its id"] 37 | "QueryType" -> "Cluster"[label="clusters", labeltooltip="Get all clusters for the specified graph"] 38 | "QueryType" -> "Cluster"[label="cluster(...)", labeltooltip="Get a single cluster based on its id"] 39 | "QueryType" -> "QueryType"[label="viewer", labeltooltip="Needed until https\://github.com/facebook/relay/issues/112 is resolved"] 40 | "Agency" -> "Route"[label="routes", labeltooltip=""] 41 | "Route" -> "Agency"[label="agency", labeltooltip=""] 42 | "Route" -> "BikesAllowed"[label="bikesAllowed", labeltooltip=""] 43 | "Route" -> "Pattern"[label="patterns", labeltooltip=""] 44 | "Route" -> "Stop"[label="stops", labeltooltip=""] 45 | "Route" -> "Trip"[label="trips", labeltooltip=""] 46 | "Pattern" -> "Route"[label="route", labeltooltip=""] 47 | "Pattern" -> "Trip"[label="trips", labeltooltip=""] 48 | "Pattern" -> "Stop"[label="stops", labeltooltip=""] 49 | "Pattern" -> "Coordinates"[label="geometry", labeltooltip=""] 50 | "Trip" -> "Route"[label="route", labeltooltip=""] 51 | "Trip" -> "WheelchairBoarding"[label="wheelchairAccessible", labeltooltip=""] 52 | "Trip" -> "BikesAllowed"[label="bikesAllowed", labeltooltip=""] 53 | "Trip" -> "Pattern"[label="pattern", labeltooltip=""] 54 | "Trip" -> "Stop"[label="stops", labeltooltip=""] 55 | "Trip" -> "Stop"[label="semanticHash", labeltooltip=""] 56 | "Trip" -> "Stoptime"[label="stoptimes", labeltooltip=""] 57 | "Trip" -> "Stoptime"[label="stoptimesForDate(...)", labeltooltip=""] 58 | "Stop" -> "LocationType"[label="locationType", labeltooltip=""] 59 | "Stop" -> "Stop"[label="parentStation", labeltooltip=""] 60 | "Stop" -> "WheelchairBoarding"[label="wheelchairBoarding", labeltooltip=""] 61 | "Stop" -> "Cluster"[label="cluster", labeltooltip=""] 62 | "Stop" -> "Route"[label="routes", labeltooltip=""] 63 | "Stop" -> "Pattern"[label="patterns", labeltooltip=""] 64 | "Stop" -> "stopAtDistance"[label="transfers", labeltooltip=""] 65 | "Stop" -> "StoptimesInPattern"[label="stoptimesForServiceDate(...)", labeltooltip=""] 66 | "Stop" -> "StoptimesInPattern"[label="stoptimesForPatterns(...)", labeltooltip=""] 67 | "Stop" -> "Stoptime"[label="stoptimesWithoutPatterns(...)", labeltooltip=""] 68 | "Cluster" -> "Stop"[label="stops", labeltooltip=""] 69 | "stopAtDistance" -> "Stop"[label="stop", labeltooltip=""] 70 | "StoptimesInPattern" -> "Pattern"[label="pattern", labeltooltip=""] 71 | "StoptimesInPattern" -> "Stoptime"[label="stoptimes", labeltooltip=""] 72 | "Stoptime" -> "Stop"[label="stop", labeltooltip=""] 73 | "Stoptime" -> "Trip"[label="trip", labeltooltip=""] 74 | "stopAtDistanceConnection" -> "stopAtDistanceEdge"[label="edges", labeltooltip=""] 75 | "stopAtDistanceConnection" -> "PageInfo"[label="pageInfo", labeltooltip=""] 76 | "stopAtDistanceEdge" -> "stopAtDistance"[label="node", labeltooltip="The item at the end of the edge"] 77 | } 78 | -------------------------------------------------------------------------------- /examples/digitransit.json: -------------------------------------------------------------------------------- 1 | {"__schema":{"queryType":{"name":"QueryType"},"mutationType":null,"types":[{"kind":"OBJECT","name":"QueryType","description":null,"fields":[{"name":"node","description":"Fetches an object given its ID","args":[{"name":"id","description":"The ID of an object","type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"ID","ofType":null}},"defaultValue":null}],"type":{"kind":"INTERFACE","name":"Node","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"agencies","description":"Get all agencies for the specified graph","args":[],"type":{"kind":"LIST","name":null,"ofType":{"kind":"OBJECT","name":"Agency","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"agency","description":"Get a single agency based on agency ID","args":[{"name":"id","description":null,"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"String","ofType":null}},"defaultValue":null}],"type":{"kind":"OBJECT","name":"Agency","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"stops","description":"Get all stops for the specified graph","args":[{"name":"ids","description":null,"type":{"kind":"LIST","name":null,"ofType":{"kind":"SCALAR","name":"String","ofType":null}},"defaultValue":null}],"type":{"kind":"LIST","name":null,"ofType":{"kind":"OBJECT","name":"Stop","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"stopsByBbox","description":"Get all stops within the specified bounding box","args":[{"name":"minLat","description":null,"type":{"kind":"SCALAR","name":"Float","ofType":null},"defaultValue":null},{"name":"minLon","description":null,"type":{"kind":"SCALAR","name":"Float","ofType":null},"defaultValue":null},{"name":"maxLat","description":null,"type":{"kind":"SCALAR","name":"Float","ofType":null},"defaultValue":null},{"name":"maxLon","description":null,"type":{"kind":"SCALAR","name":"Float","ofType":null},"defaultValue":null},{"name":"agency","description":null,"type":{"kind":"SCALAR","name":"String","ofType":null},"defaultValue":null}],"type":{"kind":"LIST","name":null,"ofType":{"kind":"OBJECT","name":"Stop","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"stopsByRadius","description":"Get all stops within the specified radius from a location. The returned type has two fields stop and distance","args":[{"name":"lat","description":"Latitude of the location","type":{"kind":"SCALAR","name":"Float","ofType":null},"defaultValue":null},{"name":"lon","description":"Longitude of the location","type":{"kind":"SCALAR","name":"Float","ofType":null},"defaultValue":null},{"name":"radius","description":"Radius (in meters) to search for from the specidied location","type":{"kind":"SCALAR","name":"Int","ofType":null},"defaultValue":null},{"name":"agency","description":null,"type":{"kind":"SCALAR","name":"String","ofType":null},"defaultValue":null},{"name":"before","description":null,"type":{"kind":"SCALAR","name":"String","ofType":null},"defaultValue":null},{"name":"after","description":null,"type":{"kind":"SCALAR","name":"String","ofType":null},"defaultValue":null},{"name":"first","description":null,"type":{"kind":"SCALAR","name":"Int","ofType":null},"defaultValue":null},{"name":"last","description":null,"type":{"kind":"SCALAR","name":"Int","ofType":null},"defaultValue":null}],"type":{"kind":"OBJECT","name":"stopAtDistanceConnection","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"stop","description":"Get a single stop based on its id (format is Agency:StopId)","args":[{"name":"id","description":null,"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"String","ofType":null}},"defaultValue":null}],"type":{"kind":"OBJECT","name":"Stop","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"routes","description":"Get all routes for the specified graph","args":[{"name":"ids","description":null,"type":{"kind":"LIST","name":null,"ofType":{"kind":"SCALAR","name":"String","ofType":null}},"defaultValue":null}],"type":{"kind":"LIST","name":null,"ofType":{"kind":"OBJECT","name":"Route","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"route","description":"Get a single route based on its id (format is Agency:RouteId)","args":[{"name":"id","description":null,"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"String","ofType":null}},"defaultValue":null}],"type":{"kind":"OBJECT","name":"Route","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"trips","description":"Get all trips for the specified graph","args":[],"type":{"kind":"LIST","name":null,"ofType":{"kind":"OBJECT","name":"Trip","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"trip","description":"Get a single trip based on its id (format is Agency:TripId)","args":[{"name":"id","description":null,"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"String","ofType":null}},"defaultValue":null}],"type":{"kind":"OBJECT","name":"Trip","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"fuzzyTrip","description":null,"args":[{"name":"route","description":null,"type":{"kind":"SCALAR","name":"String","ofType":null},"defaultValue":null},{"name":"direction","description":null,"type":{"kind":"SCALAR","name":"Int","ofType":null},"defaultValue":null},{"name":"date","description":null,"type":{"kind":"SCALAR","name":"String","ofType":null},"defaultValue":null},{"name":"time","description":null,"type":{"kind":"SCALAR","name":"Int","ofType":null},"defaultValue":null}],"type":{"kind":"OBJECT","name":"Trip","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"patterns","description":"Get all patterns for the specified graph","args":[],"type":{"kind":"LIST","name":null,"ofType":{"kind":"OBJECT","name":"Pattern","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"pattern","description":"Get a single pattern based on its id","args":[{"name":"id","description":null,"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"String","ofType":null}},"defaultValue":null}],"type":{"kind":"OBJECT","name":"Pattern","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"clusters","description":"Get all clusters for the specified graph","args":[],"type":{"kind":"LIST","name":null,"ofType":{"kind":"OBJECT","name":"Cluster","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"cluster","description":"Get a single cluster based on its id","args":[{"name":"id","description":null,"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"String","ofType":null}},"defaultValue":null}],"type":{"kind":"OBJECT","name":"Cluster","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"viewer","description":"Needed until https:\/\/github.com\/facebook\/relay\/issues\/112 is resolved","args":[],"type":{"kind":"OBJECT","name":"QueryType","ofType":null},"isDeprecated":false,"deprecationReason":null}],"inputFields":null,"interfaces":[],"enumValues":null,"possibleTypes":null},{"kind":"INTERFACE","name":"Node","description":"An object with an ID","fields":[{"name":"id","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"ID","ofType":null}},"isDeprecated":false,"deprecationReason":null}],"inputFields":null,"interfaces":null,"enumValues":null,"possibleTypes":[{"kind":"OBJECT","name":"Agency","ofType":null},{"kind":"OBJECT","name":"Route","ofType":null},{"kind":"OBJECT","name":"Pattern","ofType":null},{"kind":"OBJECT","name":"Trip","ofType":null},{"kind":"OBJECT","name":"Stop","ofType":null},{"kind":"OBJECT","name":"Cluster","ofType":null}]},{"kind":"SCALAR","name":"ID","description":"Built-in ID","fields":null,"inputFields":null,"interfaces":null,"enumValues":null,"possibleTypes":null},{"kind":"OBJECT","name":"Agency","description":"Agency in the graph","fields":[{"name":"id","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"ID","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"gtfsId","description":"Agency id","args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"String","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"name","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"String","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"url","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"String","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"timezone","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"String","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"lang","description":null,"args":[],"type":{"kind":"SCALAR","name":"String","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"phone","description":null,"args":[],"type":{"kind":"SCALAR","name":"String","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"fareUrl","description":null,"args":[],"type":{"kind":"SCALAR","name":"String","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"routes","description":null,"args":[],"type":{"kind":"LIST","name":null,"ofType":{"kind":"OBJECT","name":"Route","ofType":null}},"isDeprecated":false,"deprecationReason":null}],"inputFields":null,"interfaces":[{"kind":"INTERFACE","name":"Node","ofType":null}],"enumValues":null,"possibleTypes":null},{"kind":"SCALAR","name":"String","description":"Built-in String","fields":null,"inputFields":null,"interfaces":null,"enumValues":null,"possibleTypes":null},{"kind":"OBJECT","name":"Route","description":null,"fields":[{"name":"id","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"ID","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"gtfsId","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"String","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"agency","description":null,"args":[],"type":{"kind":"OBJECT","name":"Agency","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"shortName","description":null,"args":[],"type":{"kind":"SCALAR","name":"String","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"longName","description":null,"args":[],"type":{"kind":"SCALAR","name":"String","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"type","description":null,"args":[],"type":{"kind":"SCALAR","name":"String","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"desc","description":null,"args":[],"type":{"kind":"SCALAR","name":"String","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"url","description":null,"args":[],"type":{"kind":"SCALAR","name":"String","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"color","description":null,"args":[],"type":{"kind":"SCALAR","name":"String","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"textColor","description":null,"args":[],"type":{"kind":"SCALAR","name":"String","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"bikesAllowed","description":null,"args":[],"type":{"kind":"ENUM","name":"BikesAllowed","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"patterns","description":null,"args":[],"type":{"kind":"LIST","name":null,"ofType":{"kind":"OBJECT","name":"Pattern","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"stops","description":null,"args":[],"type":{"kind":"LIST","name":null,"ofType":{"kind":"OBJECT","name":"Stop","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"trips","description":null,"args":[],"type":{"kind":"LIST","name":null,"ofType":{"kind":"OBJECT","name":"Trip","ofType":null}},"isDeprecated":false,"deprecationReason":null}],"inputFields":null,"interfaces":[{"kind":"INTERFACE","name":"Node","ofType":null}],"enumValues":null,"possibleTypes":null},{"kind":"ENUM","name":"BikesAllowed","description":null,"fields":null,"inputFields":null,"interfaces":null,"enumValues":[{"name":"NO_INFORMATION","description":"There is no bike information for the trip.","isDeprecated":false,"deprecationReason":null},{"name":"ALLOWED","description":"The vehicle being used on this particular trip can accommodate at least one bicycle.","isDeprecated":false,"deprecationReason":null},{"name":"NOT_ALLOWED","description":"No bicycles are allowed on this trip.","isDeprecated":false,"deprecationReason":null}],"possibleTypes":null},{"kind":"OBJECT","name":"Pattern","description":null,"fields":[{"name":"id","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"ID","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"route","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"OBJECT","name":"Route","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"directionId","description":null,"args":[],"type":{"kind":"SCALAR","name":"Int","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"name","description":null,"args":[],"type":{"kind":"SCALAR","name":"String","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"code","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"String","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"headsign","description":null,"args":[],"type":{"kind":"SCALAR","name":"String","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"trips","description":null,"args":[],"type":{"kind":"LIST","name":null,"ofType":{"kind":"NON_NULL","name":null,"ofType":{"kind":"OBJECT","name":"Trip","ofType":null}}},"isDeprecated":false,"deprecationReason":null},{"name":"stops","description":null,"args":[],"type":{"kind":"LIST","name":null,"ofType":{"kind":"NON_NULL","name":null,"ofType":{"kind":"OBJECT","name":"Stop","ofType":null}}},"isDeprecated":false,"deprecationReason":null},{"name":"geometry","description":null,"args":[],"type":{"kind":"LIST","name":null,"ofType":{"kind":"OBJECT","name":"Coordinates","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"semanticHash","description":null,"args":[],"type":{"kind":"SCALAR","name":"String","ofType":null},"isDeprecated":false,"deprecationReason":null}],"inputFields":null,"interfaces":[{"kind":"INTERFACE","name":"Node","ofType":null}],"enumValues":null,"possibleTypes":null},{"kind":"SCALAR","name":"Int","description":"Built-in Int","fields":null,"inputFields":null,"interfaces":null,"enumValues":null,"possibleTypes":null},{"kind":"OBJECT","name":"Trip","description":null,"fields":[{"name":"id","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"ID","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"gtfsId","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"String","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"route","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"OBJECT","name":"Route","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"serviceId","description":null,"args":[],"type":{"kind":"SCALAR","name":"String","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"tripShortName","description":null,"args":[],"type":{"kind":"SCALAR","name":"String","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"tripHeadsign","description":null,"args":[],"type":{"kind":"SCALAR","name":"String","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"routeShortName","description":null,"args":[],"type":{"kind":"SCALAR","name":"String","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"directionId","description":null,"args":[],"type":{"kind":"SCALAR","name":"String","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"blockId","description":null,"args":[],"type":{"kind":"SCALAR","name":"String","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"shapeId","description":null,"args":[],"type":{"kind":"SCALAR","name":"String","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"wheelchairAccessible","description":null,"args":[],"type":{"kind":"ENUM","name":"WheelchairBoarding","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"bikesAllowed","description":null,"args":[],"type":{"kind":"ENUM","name":"BikesAllowed","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"pattern","description":null,"args":[],"type":{"kind":"OBJECT","name":"Pattern","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"stops","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"LIST","name":null,"ofType":{"kind":"NON_NULL","name":null,"ofType":{"kind":"OBJECT","name":"Stop"}}}},"isDeprecated":false,"deprecationReason":null},{"name":"semanticHash","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"LIST","name":null,"ofType":{"kind":"NON_NULL","name":null,"ofType":{"kind":"OBJECT","name":"Stop"}}}},"isDeprecated":false,"deprecationReason":null},{"name":"stoptimes","description":null,"args":[],"type":{"kind":"LIST","name":null,"ofType":{"kind":"OBJECT","name":"Stoptime","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"stoptimesForDate","description":null,"args":[{"name":"serviceDay","description":null,"type":{"kind":"SCALAR","name":"String","ofType":null},"defaultValue":null}],"type":{"kind":"LIST","name":null,"ofType":{"kind":"OBJECT","name":"Stoptime","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"geometry","description":null,"args":[],"type":{"kind":"SCALAR","name":"String","ofType":null},"isDeprecated":false,"deprecationReason":null}],"inputFields":null,"interfaces":[{"kind":"INTERFACE","name":"Node","ofType":null}],"enumValues":null,"possibleTypes":null},{"kind":"ENUM","name":"WheelchairBoarding","description":null,"fields":null,"inputFields":null,"interfaces":null,"enumValues":[{"name":"NO_INFORMATION","description":"There is no accessibility information for the stop.","isDeprecated":false,"deprecationReason":null},{"name":"POSSIBLE","description":"At least some vehicles at this stop can be boarded by a rider in a wheelchair.","isDeprecated":false,"deprecationReason":null},{"name":"NOT_POSSIBLE","description":"Wheelchair boarding is not possible at this stop.","isDeprecated":false,"deprecationReason":null}],"possibleTypes":null},{"kind":"OBJECT","name":"Stop","description":null,"fields":[{"name":"id","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"ID","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"gtfsId","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"String","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"name","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"String","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"lat","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"Float","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"lon","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"Float","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"code","description":null,"args":[],"type":{"kind":"SCALAR","name":"String","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"desc","description":null,"args":[],"type":{"kind":"SCALAR","name":"String","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"zoneId","description":null,"args":[],"type":{"kind":"SCALAR","name":"String","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"url","description":null,"args":[],"type":{"kind":"SCALAR","name":"String","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"locationType","description":null,"args":[],"type":{"kind":"ENUM","name":"LocationType","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"parentStation","description":null,"args":[],"type":{"kind":"OBJECT","name":"Stop","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"wheelchairBoarding","description":null,"args":[],"type":{"kind":"ENUM","name":"WheelchairBoarding","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"direction","description":null,"args":[],"type":{"kind":"SCALAR","name":"String","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"timezone","description":null,"args":[],"type":{"kind":"SCALAR","name":"String","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"vehicleType","description":null,"args":[],"type":{"kind":"SCALAR","name":"Int","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"platformCode","description":null,"args":[],"type":{"kind":"SCALAR","name":"String","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"cluster","description":null,"args":[],"type":{"kind":"OBJECT","name":"Cluster","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"routes","description":null,"args":[],"type":{"kind":"LIST","name":null,"ofType":{"kind":"NON_NULL","name":null,"ofType":{"kind":"OBJECT","name":"Route","ofType":null}}},"isDeprecated":false,"deprecationReason":null},{"name":"patterns","description":null,"args":[],"type":{"kind":"LIST","name":null,"ofType":{"kind":"OBJECT","name":"Pattern","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"transfers","description":null,"args":[],"type":{"kind":"LIST","name":null,"ofType":{"kind":"OBJECT","name":"stopAtDistance","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"stoptimesForServiceDate","description":null,"args":[{"name":"date","description":null,"type":{"kind":"SCALAR","name":"String","ofType":null},"defaultValue":null}],"type":{"kind":"LIST","name":null,"ofType":{"kind":"OBJECT","name":"StoptimesInPattern","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"stoptimesForPatterns","description":null,"args":[{"name":"startTime","description":null,"type":{"kind":"SCALAR","name":"String","ofType":null},"defaultValue":"0"},{"name":"timeRange","description":null,"type":{"kind":"SCALAR","name":"Int","ofType":null},"defaultValue":"86400"},{"name":"numberOfDepartures","description":null,"type":{"kind":"SCALAR","name":"Int","ofType":null},"defaultValue":"5"}],"type":{"kind":"LIST","name":null,"ofType":{"kind":"OBJECT","name":"StoptimesInPattern","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"stoptimesWithoutPatterns","description":null,"args":[{"name":"startTime","description":null,"type":{"kind":"SCALAR","name":"String","ofType":null},"defaultValue":"0"},{"name":"timeRange","description":null,"type":{"kind":"SCALAR","name":"Int","ofType":null},"defaultValue":"86400"},{"name":"numberOfDepartures","description":null,"type":{"kind":"SCALAR","name":"Int","ofType":null},"defaultValue":"5"}],"type":{"kind":"LIST","name":null,"ofType":{"kind":"OBJECT","name":"Stoptime","ofType":null}},"isDeprecated":false,"deprecationReason":null}],"inputFields":null,"interfaces":[{"kind":"INTERFACE","name":"Node","ofType":null}],"enumValues":null,"possibleTypes":null},{"kind":"SCALAR","name":"Float","description":"Built-in Float","fields":null,"inputFields":null,"interfaces":null,"enumValues":null,"possibleTypes":null},{"kind":"ENUM","name":"LocationType","description":"Identifies whether this stop represents a stop or station.","fields":null,"inputFields":null,"interfaces":null,"enumValues":[{"name":"STOP","description":"A location where passengers board or disembark from a transit vehicle.","isDeprecated":false,"deprecationReason":null},{"name":"STATION","description":"A physical structure or area that contains one or more stop.","isDeprecated":false,"deprecationReason":null},{"name":"ENTRANCE","description":null,"isDeprecated":false,"deprecationReason":null}],"possibleTypes":null},{"kind":"OBJECT","name":"Cluster","description":null,"fields":[{"name":"id","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"ID","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"gtfsId","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"String","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"name","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"String","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"lat","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"Float","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"lon","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"Float","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"stops","description":null,"args":[],"type":{"kind":"LIST","name":null,"ofType":{"kind":"NON_NULL","name":null,"ofType":{"kind":"OBJECT","name":"Stop","ofType":null}}},"isDeprecated":false,"deprecationReason":null}],"inputFields":null,"interfaces":[{"kind":"INTERFACE","name":"Node","ofType":null}],"enumValues":null,"possibleTypes":null},{"kind":"OBJECT","name":"stopAtDistance","description":null,"fields":[{"name":"stop","description":null,"args":[],"type":{"kind":"OBJECT","name":"Stop","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"distance","description":null,"args":[],"type":{"kind":"SCALAR","name":"Int","ofType":null},"isDeprecated":false,"deprecationReason":null}],"inputFields":null,"interfaces":[],"enumValues":null,"possibleTypes":null},{"kind":"OBJECT","name":"StoptimesInPattern","description":null,"fields":[{"name":"pattern","description":null,"args":[],"type":{"kind":"OBJECT","name":"Pattern","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"stoptimes","description":null,"args":[],"type":{"kind":"LIST","name":null,"ofType":{"kind":"OBJECT","name":"Stoptime","ofType":null}},"isDeprecated":false,"deprecationReason":null}],"inputFields":null,"interfaces":[],"enumValues":null,"possibleTypes":null},{"kind":"OBJECT","name":"Stoptime","description":null,"fields":[{"name":"stop","description":null,"args":[],"type":{"kind":"OBJECT","name":"Stop","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"scheduledArrival","description":null,"args":[],"type":{"kind":"SCALAR","name":"Int","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"realtimeArrival","description":null,"args":[],"type":{"kind":"SCALAR","name":"Int","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"arrivalDelay","description":null,"args":[],"type":{"kind":"SCALAR","name":"Int","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"scheduledDeparture","description":null,"args":[],"type":{"kind":"SCALAR","name":"Int","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"realtimeDeparture","description":null,"args":[],"type":{"kind":"SCALAR","name":"Int","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"departureDelay","description":null,"args":[],"type":{"kind":"SCALAR","name":"Int","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"timepoint","description":null,"args":[],"type":{"kind":"SCALAR","name":"Boolean","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"realtime","description":null,"args":[],"type":{"kind":"SCALAR","name":"Boolean","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"serviceDay","description":null,"args":[],"type":{"kind":"SCALAR","name":"Long","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"trip","description":null,"args":[],"type":{"kind":"OBJECT","name":"Trip","ofType":null},"isDeprecated":false,"deprecationReason":null}],"inputFields":null,"interfaces":[],"enumValues":null,"possibleTypes":null},{"kind":"SCALAR","name":"Boolean","description":"Built-in Boolean","fields":null,"inputFields":null,"interfaces":null,"enumValues":null,"possibleTypes":null},{"kind":"SCALAR","name":"Long","description":"Long type","fields":null,"inputFields":null,"interfaces":null,"enumValues":null,"possibleTypes":null},{"kind":"OBJECT","name":"Coordinates","description":null,"fields":[{"name":"lat","description":null,"args":[],"type":{"kind":"SCALAR","name":"Float","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"lon","description":null,"args":[],"type":{"kind":"SCALAR","name":"Float","ofType":null},"isDeprecated":false,"deprecationReason":null}],"inputFields":null,"interfaces":[],"enumValues":null,"possibleTypes":null},{"kind":"OBJECT","name":"stopAtDistanceConnection","description":"A connection to a list of items.","fields":[{"name":"edges","description":null,"args":[],"type":{"kind":"LIST","name":null,"ofType":{"kind":"OBJECT","name":"stopAtDistanceEdge","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"pageInfo","description":null,"args":[],"type":{"kind":"OBJECT","name":"PageInfo","ofType":null},"isDeprecated":false,"deprecationReason":null}],"inputFields":null,"interfaces":[],"enumValues":null,"possibleTypes":null},{"kind":"OBJECT","name":"stopAtDistanceEdge","description":"An edge in a connection.","fields":[{"name":"node","description":"The item at the end of the edge","args":[],"type":{"kind":"OBJECT","name":"stopAtDistance","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"cursor","description":"","args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"String","ofType":null}},"isDeprecated":false,"deprecationReason":null}],"inputFields":null,"interfaces":[],"enumValues":null,"possibleTypes":null},{"kind":"OBJECT","name":"PageInfo","description":"Information about pagination in a connection.","fields":[{"name":"hasNextPage","description":"When paginating forwards, are there more items?","args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"Boolean","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"hasPreviousPage","description":"When paginating backwards, are there more items?","args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"Boolean","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"startCursor","description":"When paginating backwards, the cursor to continue.","args":[],"type":{"kind":"SCALAR","name":"String","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"endCursor","description":"When paginating forwards, the cursor to continue.","args":[],"type":{"kind":"SCALAR","name":"String","ofType":null},"isDeprecated":false,"deprecationReason":null}],"inputFields":null,"interfaces":[],"enumValues":null,"possibleTypes":null},{"kind":"OBJECT","name":"__Schema","description":"A GraphQL Introspection defines the capabilities of a GraphQL server. It exposes all available types and directives on 'the server, as well as the entry points for query and 'mutation operations.","fields":[{"name":"types","description":"A list of all types supported by this server.","args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"LIST","name":null,"ofType":{"kind":"NON_NULL","name":null,"ofType":{"kind":"OBJECT","name":"__Type"}}}},"isDeprecated":false,"deprecationReason":null},{"name":"queryType","description":"The type that query operations will be rooted at.","args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"OBJECT","name":"__Type","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"mutationType","description":"If this server supports mutation, the type that mutation operations will be rooted at.","args":[],"type":{"kind":"OBJECT","name":"__Type","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"directives","description":"'A list of all directives supported by this server.","args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"LIST","name":null,"ofType":{"kind":"NON_NULL","name":null,"ofType":{"kind":"OBJECT","name":"__Directive"}}}},"isDeprecated":false,"deprecationReason":null}],"inputFields":null,"interfaces":[],"enumValues":null,"possibleTypes":null},{"kind":"OBJECT","name":"__Type","description":null,"fields":[{"name":"kind","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"ENUM","name":"__TypeKind","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"name","description":null,"args":[],"type":{"kind":"SCALAR","name":"String","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"description","description":null,"args":[],"type":{"kind":"SCALAR","name":"String","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"fields","description":null,"args":[{"name":"includeDeprecated","description":null,"type":{"kind":"SCALAR","name":"Boolean","ofType":null},"defaultValue":"false"}],"type":{"kind":"LIST","name":null,"ofType":{"kind":"NON_NULL","name":null,"ofType":{"kind":"OBJECT","name":"__Field","ofType":null}}},"isDeprecated":false,"deprecationReason":null},{"name":"interfaces","description":null,"args":[],"type":{"kind":"LIST","name":null,"ofType":{"kind":"NON_NULL","name":null,"ofType":{"kind":"OBJECT","name":"__Type","ofType":null}}},"isDeprecated":false,"deprecationReason":null},{"name":"possibleTypes","description":null,"args":[],"type":{"kind":"LIST","name":null,"ofType":{"kind":"NON_NULL","name":null,"ofType":{"kind":"OBJECT","name":"__Type","ofType":null}}},"isDeprecated":false,"deprecationReason":null},{"name":"enumValues","description":null,"args":[{"name":"includeDeprecated","description":null,"type":{"kind":"SCALAR","name":"Boolean","ofType":null},"defaultValue":"false"}],"type":{"kind":"LIST","name":null,"ofType":{"kind":"NON_NULL","name":null,"ofType":{"kind":"OBJECT","name":"__EnumValue","ofType":null}}},"isDeprecated":false,"deprecationReason":null},{"name":"inputFields","description":null,"args":[],"type":{"kind":"LIST","name":null,"ofType":{"kind":"NON_NULL","name":null,"ofType":{"kind":"OBJECT","name":"__InputValue","ofType":null}}},"isDeprecated":false,"deprecationReason":null},{"name":"ofType","description":null,"args":[],"type":{"kind":"OBJECT","name":"__Type","ofType":null},"isDeprecated":false,"deprecationReason":null}],"inputFields":null,"interfaces":[],"enumValues":null,"possibleTypes":null},{"kind":"ENUM","name":"__TypeKind","description":"An enum describing what kind of type a given __Type is","fields":null,"inputFields":null,"interfaces":null,"enumValues":[{"name":"SCALAR","description":"Indicates this type is a scalar.","isDeprecated":false,"deprecationReason":null},{"name":"OBJECT","description":"Indicates this type is an object. `fields` and `interfaces` are valid fields.","isDeprecated":false,"deprecationReason":null},{"name":"INTERFACE","description":"Indicates this type is an interface. `fields` and `possibleTypes` are valid fields.","isDeprecated":false,"deprecationReason":null},{"name":"UNION","description":"Indicates this type is a union. `possibleTypes` is a valid field.","isDeprecated":false,"deprecationReason":null},{"name":"ENUM","description":"Indicates this type is an enum. `enumValues` is a valid field.","isDeprecated":false,"deprecationReason":null},{"name":"INPUT_OBJECT","description":"Indicates this type is an input object. `inputFields` is a valid field.","isDeprecated":false,"deprecationReason":null},{"name":"LIST","description":"Indicates this type is a list. `ofType` is a valid field.","isDeprecated":false,"deprecationReason":null},{"name":"NON_NULL","description":"Indicates this type is a non-null. `ofType` is a valid field.","isDeprecated":false,"deprecationReason":null}],"possibleTypes":null},{"kind":"OBJECT","name":"__Field","description":null,"fields":[{"name":"name","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"String","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"description","description":null,"args":[],"type":{"kind":"SCALAR","name":"String","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"args","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"LIST","name":null,"ofType":{"kind":"NON_NULL","name":null,"ofType":{"kind":"OBJECT","name":"__InputValue"}}}},"isDeprecated":false,"deprecationReason":null},{"name":"type","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"OBJECT","name":"__Type","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"isDeprecated","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"Boolean","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"deprecationReason","description":null,"args":[],"type":{"kind":"SCALAR","name":"String","ofType":null},"isDeprecated":false,"deprecationReason":null}],"inputFields":null,"interfaces":[],"enumValues":null,"possibleTypes":null},{"kind":"OBJECT","name":"__InputValue","description":null,"fields":[{"name":"name","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"String","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"description","description":null,"args":[],"type":{"kind":"SCALAR","name":"String","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"type","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"OBJECT","name":"__Type","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"defaultValue","description":null,"args":[],"type":{"kind":"SCALAR","name":"String","ofType":null},"isDeprecated":false,"deprecationReason":null}],"inputFields":null,"interfaces":[],"enumValues":null,"possibleTypes":null},{"kind":"OBJECT","name":"__EnumValue","description":null,"fields":[{"name":"name","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"String","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"description","description":null,"args":[],"type":{"kind":"SCALAR","name":"String","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"isDeprecated","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"Boolean","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"deprecationReason","description":null,"args":[],"type":{"kind":"SCALAR","name":"String","ofType":null},"isDeprecated":false,"deprecationReason":null}],"inputFields":null,"interfaces":[],"enumValues":null,"possibleTypes":null},{"kind":"OBJECT","name":"__Directive","description":null,"fields":[{"name":"name","description":null,"args":[],"type":{"kind":"SCALAR","name":"String","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"description","description":null,"args":[],"type":{"kind":"SCALAR","name":"String","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"args","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"LIST","name":null,"ofType":{"kind":"NON_NULL","name":null,"ofType":{"kind":"OBJECT","name":"__InputValue"}}}},"isDeprecated":false,"deprecationReason":null},{"name":"onOperation","description":null,"args":[],"type":{"kind":"SCALAR","name":"Boolean","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"onFragment","description":null,"args":[],"type":{"kind":"SCALAR","name":"Boolean","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"onField","description":null,"args":[],"type":{"kind":"SCALAR","name":"Boolean","ofType":null},"isDeprecated":false,"deprecationReason":null}],"inputFields":null,"interfaces":[],"enumValues":null,"possibleTypes":null}],"directives":[{"name":"include","description":"Directs the executor to include this field or fragment only when the `if` argument is true","args":[{"name":"if","description":"Included when true.","type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"Boolean","ofType":null}},"defaultValue":null}],"onOperation":false,"onFragment":true,"onField":true},{"name":"skip","description":"Directs the executor to skip this field or fragment when the `if`'argument is true.","args":[{"name":"skip","description":"Skipped when true.","type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"Boolean","ofType":null}},"defaultValue":null}],"onOperation":false,"onFragment":true,"onField":true}]}} -------------------------------------------------------------------------------- /examples/digitransit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Macroz/GraphQLviz/6df0713ae51d7cfea489a9183c59b42d1987ab09/examples/digitransit.png -------------------------------------------------------------------------------- /examples/digitransit.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | digitransit 11 | 12 | digitransit 13 | 14 | QueryType 15 | 16 | 17 | QueryType 18 | 19 | 20 | 21 | QueryType->QueryType 22 | 23 | 24 | 25 | viewer 26 | 27 | 28 | 29 | 30 | Node 31 | 32 | 33 | Node 34 | id: ID! 35 | 36 | 37 | 38 | QueryType->Node 39 | 40 | 41 | 42 | node(...) 43 | 44 | 45 | 46 | 47 | Agency 48 | 49 | 50 | Agency 51 | id: ID! 52 | gtfsId: String! 53 | name: String! 54 | url: String! 55 | timezone: String! 56 | lang: String 57 | phone: String 58 | fareUrl: String 59 | 60 | 61 | 62 | QueryType->Agency 63 | 64 | 65 | 66 | agencies 67 | 68 | 69 | 70 | 71 | QueryType->Agency 72 | 73 | 74 | 75 | agency(...) 76 | 77 | 78 | 79 | 80 | Route 81 | 82 | 83 | Route 84 | id: ID! 85 | gtfsId: String! 86 | shortName: String 87 | longName: String 88 | type: String 89 | desc: String 90 | url: String 91 | color: String 92 | textColor: String 93 | 94 | 95 | 96 | QueryType->Route 97 | 98 | 99 | 100 | routes(...) 101 | 102 | 103 | 104 | 105 | QueryType->Route 106 | 107 | 108 | 109 | route(...) 110 | 111 | 112 | 113 | 114 | Pattern 115 | 116 | 117 | Pattern 118 | id: ID! 119 | directionId: Int 120 | name: String 121 | code: String! 122 | headsign: String 123 | semanticHash: String 124 | 125 | 126 | 127 | QueryType->Pattern 128 | 129 | 130 | 131 | patterns 132 | 133 | 134 | 135 | 136 | QueryType->Pattern 137 | 138 | 139 | 140 | pattern(...) 141 | 142 | 143 | 144 | 145 | Trip 146 | 147 | 148 | Trip 149 | id: ID! 150 | gtfsId: String! 151 | serviceId: String 152 | tripShortName: String 153 | tripHeadsign: String 154 | routeShortName: String 155 | directionId: String 156 | blockId: String 157 | shapeId: String 158 | geometry: String 159 | 160 | 161 | 162 | QueryType->Trip 163 | 164 | 165 | 166 | trips 167 | 168 | 169 | 170 | 171 | QueryType->Trip 172 | 173 | 174 | 175 | trip(...) 176 | 177 | 178 | 179 | 180 | QueryType->Trip 181 | 182 | 183 | fuzzyTrip(...) 184 | 185 | 186 | Stop 187 | 188 | 189 | Stop 190 | id: ID! 191 | gtfsId: String! 192 | name: String! 193 | lat: Float! 194 | lon: Float! 195 | code: String 196 | desc: String 197 | zoneId: String 198 | url: String 199 | direction: String 200 | timezone: String 201 | vehicleType: Int 202 | platformCode: String 203 | 204 | 205 | 206 | QueryType->Stop 207 | 208 | 209 | 210 | stops(...) 211 | 212 | 213 | 214 | 215 | QueryType->Stop 216 | 217 | 218 | 219 | stopsByBbox(...) 220 | 221 | 222 | 223 | 224 | QueryType->Stop 225 | 226 | 227 | 228 | stop(...) 229 | 230 | 231 | 232 | 233 | Cluster 234 | 235 | 236 | Cluster 237 | id: ID! 238 | gtfsId: String! 239 | name: String! 240 | lat: Float! 241 | lon: Float! 242 | 243 | 244 | 245 | QueryType->Cluster 246 | 247 | 248 | 249 | clusters 250 | 251 | 252 | 253 | 254 | QueryType->Cluster 255 | 256 | 257 | 258 | cluster(...) 259 | 260 | 261 | 262 | 263 | stopAtDistanceConnection 264 | 265 | 266 | stopAtDistanceConnection 267 | 268 | 269 | 270 | QueryType->stopAtDistanceConnection 271 | 272 | 273 | 274 | stopsByRadius(...) 275 | 276 | 277 | 278 | 279 | Agency->Route 280 | 281 | 282 | routes 283 | 284 | 285 | Route->Agency 286 | 287 | 288 | agency 289 | 290 | 291 | BikesAllowed 292 | 293 | 294 | BikesAllowed 295 | «enum» 296 | NO_INFORMATION 297 | ALLOWED 298 | NOT_ALLOWED 299 | 300 | 301 | 302 | Route->BikesAllowed 303 | 304 | 305 | bikesAllowed 306 | 307 | 308 | Route->Pattern 309 | 310 | 311 | patterns 312 | 313 | 314 | Route->Trip 315 | 316 | 317 | trips 318 | 319 | 320 | Route->Stop 321 | 322 | 323 | stops 324 | 325 | 326 | Pattern->Route 327 | 328 | 329 | route 330 | 331 | 332 | Pattern->Trip 333 | 334 | 335 | trips 336 | 337 | 338 | Pattern->Stop 339 | 340 | 341 | stops 342 | 343 | 344 | Coordinates 345 | 346 | 347 | Coordinates 348 | lat: Float 349 | lon: Float 350 | 351 | 352 | 353 | Pattern->Coordinates 354 | 355 | 356 | geometry 357 | 358 | 359 | Trip->Route 360 | 361 | 362 | route 363 | 364 | 365 | Trip->BikesAllowed 366 | 367 | 368 | bikesAllowed 369 | 370 | 371 | Trip->Pattern 372 | 373 | 374 | pattern 375 | 376 | 377 | WheelchairBoarding 378 | 379 | 380 | WheelchairBoarding 381 | «enum» 382 | NO_INFORMATION 383 | POSSIBLE 384 | NOT_POSSIBLE 385 | 386 | 387 | 388 | Trip->WheelchairBoarding 389 | 390 | 391 | wheelchairAccessible 392 | 393 | 394 | Trip->Stop 395 | 396 | 397 | stops 398 | 399 | 400 | Trip->Stop 401 | 402 | 403 | semanticHash 404 | 405 | 406 | Stoptime 407 | 408 | 409 | Stoptime 410 | scheduledArrival: Int 411 | realtimeArrival: Int 412 | arrivalDelay: Int 413 | scheduledDeparture: Int 414 | realtimeDeparture: Int 415 | departureDelay: Int 416 | timepoint: Boolean 417 | realtime: Boolean 418 | serviceDay: Long 419 | 420 | 421 | 422 | Trip->Stoptime 423 | 424 | 425 | stoptimes 426 | 427 | 428 | Trip->Stoptime 429 | 430 | 431 | stoptimesForDate(...) 432 | 433 | 434 | Stop->Route 435 | 436 | 437 | routes 438 | 439 | 440 | Stop->Pattern 441 | 442 | 443 | patterns 444 | 445 | 446 | Stop->WheelchairBoarding 447 | 448 | 449 | wheelchairBoarding 450 | 451 | 452 | Stop->Stop 453 | 454 | 455 | parentStation 456 | 457 | 458 | LocationType 459 | 460 | 461 | LocationType 462 | «enum» 463 | STOP 464 | STATION 465 | ENTRANCE 466 | 467 | 468 | 469 | Stop->LocationType 470 | 471 | 472 | locationType 473 | 474 | 475 | Stop->Cluster 476 | 477 | 478 | cluster 479 | 480 | 481 | stopAtDistance 482 | 483 | 484 | stopAtDistance 485 | distance: Int 486 | 487 | 488 | 489 | Stop->stopAtDistance 490 | 491 | 492 | transfers 493 | 494 | 495 | StoptimesInPattern 496 | 497 | 498 | StoptimesInPattern 499 | 500 | 501 | 502 | Stop->StoptimesInPattern 503 | 504 | 505 | stoptimesForServiceDate(...) 506 | 507 | 508 | Stop->StoptimesInPattern 509 | 510 | 511 | stoptimesForPatterns(...) 512 | 513 | 514 | Stop->Stoptime 515 | 516 | 517 | stoptimesWithoutPatterns(...) 518 | 519 | 520 | Cluster->Stop 521 | 522 | 523 | stops 524 | 525 | 526 | stopAtDistance->Stop 527 | 528 | 529 | stop 530 | 531 | 532 | StoptimesInPattern->Pattern 533 | 534 | 535 | pattern 536 | 537 | 538 | StoptimesInPattern->Stoptime 539 | 540 | 541 | stoptimes 542 | 543 | 544 | Stoptime->Trip 545 | 546 | 547 | trip 548 | 549 | 550 | Stoptime->Stop 551 | 552 | 553 | stop 554 | 555 | 556 | stopAtDistanceEdge 557 | 558 | 559 | stopAtDistanceEdge 560 | cursor: String! 561 | 562 | 563 | 564 | stopAtDistanceConnection->stopAtDistanceEdge 565 | 566 | 567 | edges 568 | 569 | 570 | PageInfo 571 | 572 | 573 | PageInfo 574 | hasNextPage: Boolean! 575 | hasPreviousPage: Boolean! 576 | startCursor: String 577 | endCursor: String 578 | 579 | 580 | 581 | stopAtDistanceConnection->PageInfo 582 | 583 | 584 | pageInfo 585 | 586 | 587 | stopAtDistanceEdge->stopAtDistance 588 | 589 | 590 | 591 | node 592 | 593 | 594 | 595 | 596 | 597 | -------------------------------------------------------------------------------- /project.clj: -------------------------------------------------------------------------------- 1 | (defproject macroz/graphqlviz "0.5.0" 2 | :description "Visualize GraphQL schemas using Graphviz" 3 | :url "https://github.com/Macroz/graphqlviz" 4 | :license {:name "Eclipse Public License" 5 | :url "http://www.eclipse.org/legal/epl-v10.html"} 6 | :dependencies [[org.clojure/clojure "1.8.0"] 7 | [macroz/tangle "0.1.8"] 8 | [org.clojure/data.json "0.2.6"] 9 | [clj-http "2.1.0"] 10 | [org.clojure/tools.cli "0.3.3"]] 11 | :main graphqlviz.core 12 | :aot :all 13 | ) 14 | -------------------------------------------------------------------------------- /resources/introspection.query: -------------------------------------------------------------------------------- 1 | query IntrospectionQuery { 2 | __schema { 3 | queryType { name } 4 | mutationType { name } 5 | types { 6 | ...FullType 7 | } 8 | directives { 9 | name 10 | description 11 | args { 12 | ...InputValue 13 | } 14 | onOperation 15 | onFragment 16 | onField 17 | } 18 | } 19 | } 20 | 21 | fragment FullType on __Type { 22 | kind 23 | name 24 | description 25 | fields { 26 | name 27 | description 28 | args { 29 | ...InputValue 30 | } 31 | type { 32 | ...TypeRef 33 | } 34 | isDeprecated 35 | deprecationReason 36 | } 37 | inputFields { 38 | ...InputValue 39 | } 40 | interfaces { 41 | ...TypeRef 42 | } 43 | enumValues { 44 | name 45 | description 46 | isDeprecated 47 | deprecationReason 48 | } 49 | possibleTypes { 50 | ...TypeRef 51 | } 52 | } 53 | 54 | fragment InputValue on __InputValue { 55 | name 56 | description 57 | type { ...TypeRef } 58 | defaultValue 59 | } 60 | 61 | fragment TypeRef on __Type { 62 | kind 63 | name 64 | ofType { 65 | kind 66 | name 67 | ofType { 68 | kind 69 | name 70 | ofType { 71 | kind 72 | name 73 | } 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/graphqlviz/core.clj: -------------------------------------------------------------------------------- 1 | (ns graphqlviz.core 2 | (:require [clojure.data.json :as json] 3 | [tangle.core :refer :all] 4 | [clj-http.client :as http] 5 | [clojure.java.io :as io] 6 | [clojure.string :as string] 7 | [clojure.tools.cli :refer [parse-opts]]) 8 | (:gen-class)) 9 | 10 | ;;; GraphQL 11 | 12 | (defn internal-type? [t] 13 | (let [name (:name t)] 14 | (or (and name (.startsWith name "__")) 15 | #_(= "QueryType" name)))) 16 | 17 | (defn scalar? [t] 18 | (= "SCALAR" (:kind t))) 19 | 20 | (defn enum? [t] 21 | (= "ENUM" (:kind t))) 22 | 23 | (defn enum-values [t] 24 | (:enumValues t)) 25 | 26 | (defn terminal-type [t] 27 | (if (:ofType t) 28 | (recur (:ofType t)) 29 | t)) 30 | 31 | (defn introspection-query [] 32 | {:query (slurp (io/resource "introspection.query"))}) 33 | 34 | 35 | 36 | ;;; Configuration 37 | 38 | (def config (atom {:expand-args false 39 | :expand-arg-types false})) 40 | 41 | 42 | ;;; Visualization 43 | 44 | (defn relation-field? [f] 45 | (not (scalar? (terminal-type (:type f))))) 46 | 47 | (defn type->id [t] 48 | (:name t)) 49 | 50 | (defn describe-field-type [t] 51 | (case (:kind t) 52 | "NON_NULL" (str (describe-field-type (:ofType t)) "!") 53 | "LIST" (str "[" (describe-field-type (:ofType t)) "]") 54 | (:name t))) 55 | 56 | (defn arg->str [a] 57 | (str (:name a) 58 | (if (:expand-arg-types @config) 59 | (str ": " (describe-field-type (:type a))) 60 | ""))) 61 | 62 | (defn format-args [args] 63 | (if (:expand-args @config) 64 | (apply str (interpose ", " (map arg->str args))) 65 | "...")) 66 | 67 | (defn get-field-label [field] 68 | (let [{:keys [type name description args]} field] 69 | (str name 70 | (if-not (empty? args) 71 | (str "(" (format-args args) ")") 72 | "") 73 | ": " 74 | (describe-field-type type)))) 75 | 76 | (defn field-to-edge [t field] 77 | (let [{:keys [type name description]} field] 78 | [(:name t) (:name (terminal-type type)) {:label (get-field-label field) 79 | :labeltooltip (str description)}])) 80 | 81 | (defn type->edges [t] 82 | (->> (:fields t) 83 | (filter relation-field?) 84 | (map (partial field-to-edge t)))) 85 | 86 | (defn field->str [t f] 87 | (let [target (str "<" (:name t) "_" (:name f) ">")] 88 | (str (:name f) ": " (describe-field-type (:type f))))) 89 | 90 | (defn edge-matches? [e s] 91 | (>= (.indexOf (second e) s) 0)) 92 | 93 | (defn relates-to? [t name] 94 | (some #(edge-matches? % name) (:edges t))) 95 | 96 | (defn connection-type? [t] 97 | (let [pointed-to-type-name (string/replace (:name t) "Connection" "")] 98 | (and (string/ends-with? (:name t) "Connection") 99 | (or (relates-to? t pointed-to-type-name) 100 | (relates-to? t "PageInfo"))))) 101 | 102 | (defn edge-type? [t] 103 | (let [pointed-to-type-name (string/replace (:name t) "Edge" "")] 104 | (and (string/ends-with? (:name t) "Edge") 105 | (relates-to? t pointed-to-type-name)))) 106 | 107 | (defn page-info-type? [t] 108 | (string/ends-with? (:name t) "PageInfo")) 109 | 110 | (defn stereotype [t] 111 | (cond (enum? t) "«enum»" 112 | (connection-type? t) "«connection»" 113 | (edge-type? t) "«edge»" 114 | (page-info-type? t) "«page info»" 115 | :else "")) 116 | 117 | (defn type-description [t] 118 | [[:TR [:TD {:BGCOLOR "#E535AB" :COLSPAN 2} [:FONT {:COLOR "white"} [:B (:name t)] [:BR] (stereotype t)]]]]) 119 | 120 | (defn scalar-field-description [t f] 121 | [:TR [:TD {:ALIGN "left" :BORDER 0} (:name f) ": " (describe-field-type (:type f))]]) 122 | 123 | (defn enum-value-description [v] 124 | [:TR [:TD {:ALIGN "left" :BORDER 0 :COLSPAN 2} (:name v)]]) 125 | 126 | (defn type->descriptor [t] 127 | (let [scalar-fields (remove relation-field? (:fields t))] 128 | {:label (into [:TABLE {:CELLSPACING 0 :BORDER 1}] 129 | (concat (type-description t) 130 | (map (partial scalar-field-description t) scalar-fields) 131 | (map enum-value-description (enum-values t))))})) 132 | 133 | (defn render [nodes edges filename] 134 | (println "Generating graph from" (count nodes) "nodes and" (count edges) "edges") 135 | (let [dot (graph->dot nodes edges {:node {:shape :none :margin 0} 136 | :graph {:label filename :rankdir :LR} 137 | :directed? true 138 | :node->id type->id 139 | :node->descriptor type->descriptor})] 140 | (println "Writing DOT" (str filename ".dot")) 141 | (spit (str filename ".dot") dot) 142 | (println "Writing SVG" (str filename ".svg")) 143 | (spit (str filename ".svg") (dot->svg dot)) 144 | )) 145 | 146 | (defn slurp-json [filename] 147 | (-> filename 148 | (slurp) 149 | (json/read-str :key-fn keyword))) 150 | 151 | (defn add-edge-info [node edges] 152 | (assoc node :edges edges)) 153 | 154 | (defn assoc-nodes-edges [nodes edges-by-name] 155 | (vec (for [node nodes] 156 | (assoc node :edges (edges-by-name (:name node)))))) 157 | 158 | (defn interesting-node? [n] 159 | (not (or (scalar? n) 160 | (page-info-type? n) 161 | (edge-type? n) 162 | (connection-type? n)))) 163 | 164 | (defn interesting-edge? [e nodes-by-name] 165 | (let [from-node (first (nodes-by-name (first e))) 166 | to-node (first (nodes-by-name (second e)))] 167 | (and (interesting-node? from-node) 168 | (interesting-node? to-node)))) 169 | 170 | (defn add-simplified-connection-edges [nodes edges nodes-by-name] 171 | (concat edges 172 | (mapcat (fn [[from-node-name to-node-name {:keys [label labeltooltip]} :as e]] 173 | (let [to-node (first (nodes-by-name to-node-name))] 174 | (if (connection-type? to-node) 175 | (let [real-to-node-name (string/replace (:name to-node) "Connection" "") 176 | new-edge [from-node-name real-to-node-name 177 | {:label (str label "\n«connection»") 178 | :labeltooltip labeltooltip}]] 179 | [new-edge] 180 | )))) 181 | (mapcat :edges nodes)))) 182 | 183 | (defn add-synthetic-edges [nodes edges nodes-by-name] 184 | (add-simplified-connection-edges nodes edges nodes-by-name)) 185 | 186 | (defn load-schema [filename] 187 | (let [schema (slurp-json filename) 188 | types (:types (:__schema (:data schema))) 189 | nodes (remove internal-type? types) 190 | edges (mapcat type->edges nodes) 191 | edges-by-name (group-by first edges) 192 | nodes (assoc-nodes-edges nodes edges-by-name) 193 | nodes-by-name (group-by :name nodes) 194 | nodes (filter interesting-node? nodes) 195 | edges (filter #(interesting-edge? % nodes-by-name) edges) 196 | edges (add-synthetic-edges nodes edges nodes-by-name) 197 | ] 198 | [nodes edges])) 199 | 200 | (defn fetch-schema [input output] 201 | (if (.startsWith input "http") 202 | (let [options (merge {:content-type "application/json" 203 | :body (json/write-str (introspection-query))} 204 | (:auth @config))] 205 | (println "Fetching schema from" input) 206 | (let [response (http/post input options)] 207 | (spit (str output ".json") (-> response 208 | (:body) 209 | (json/read-str :key-fn keyword) 210 | (json/write-str))))) 211 | (do (println "Loading schema from" input) 212 | (spit (str output ".json") (slurp input))))) 213 | 214 | (defn process-schema [output] 215 | (let [[nodes edges] (load-schema (str output ".json"))] 216 | (render nodes edges output))) 217 | 218 | (defn read-password [] 219 | (String/valueOf (.readPassword (System/console) "Password:" nil))) 220 | 221 | (def cli-options 222 | [["-a" "--auth AUTH" "Type of auth: basic, digest or oauth2" 223 | :parse-fn (comp keyword string/trim)] 224 | ["-u" "--user USERNAME" "Username for authentication"] 225 | ["-p" "--password PASSWORD" "Password for authentication"] 226 | ["-pp" "--password-prompt" "Prompt password for authentication"] 227 | ["-o" "--oauth TOKEN" "oAuth2 token for authentication"] 228 | ["-h" "--help"]]) 229 | 230 | (defn -main [& args] 231 | (let [parsed-options (parse-opts args cli-options) 232 | options (:options parsed-options) 233 | args (:arguments parsed-options) 234 | options (if (:password-prompt options) 235 | (assoc options :password (read-password)) 236 | options) 237 | auth-config (case (:auth options) 238 | :basic {:auth {:basic-auth [(:username options) (:password options)]}} 239 | :digest {:auth {:digest-auth [(:username options) (:password options)]}} 240 | :oauth {:auth {:oauth-token (:oauth-token options)}} 241 | {})] 242 | (swap! config merge auth-config) 243 | (if (= (count args) 2) 244 | (let [input (first args) 245 | output (second args)] 246 | (fetch-schema input output) 247 | (process-schema output) 248 | (println "Done!") 249 | (shutdown-agents)) 250 | (if (:help options) 251 | (do (println "Usage:") 252 | (println " graphqlviz ") 253 | (println "\nOptions:") 254 | (println (:summary parsed-options))) 255 | (println (:errors parsed-options)))))) 256 | --------------------------------------------------------------------------------