{"id":19526014,"url":"https://github.com/marvelapp/graphql-relay-py","last_synced_at":"2026-04-15T20:04:00.760Z","repository":{"id":203853799,"uuid":"315975128","full_name":"marvelapp/graphql-relay-py","owner":"marvelapp","description":"fork of graphql-python/graphql-relay-py to fix hasPreviousPage","archived":false,"fork":false,"pushed_at":"2020-11-25T15:47:48.000Z","size":96,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":7,"default_branch":"master","last_synced_at":"2025-01-08T15:28:32.959Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/marvelapp.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2020-11-25T15:10:55.000Z","updated_at":"2023-10-26T22:42:03.000Z","dependencies_parsed_at":null,"dependency_job_id":"f51533cc-7d57-45f6-a804-8c3742da6abf","html_url":"https://github.com/marvelapp/graphql-relay-py","commit_stats":null,"previous_names":["marvelapp/graphql-relay-py"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marvelapp%2Fgraphql-relay-py","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marvelapp%2Fgraphql-relay-py/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marvelapp%2Fgraphql-relay-py/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marvelapp%2Fgraphql-relay-py/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/marvelapp","download_url":"https://codeload.github.com/marvelapp/graphql-relay-py/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":240777554,"owners_count":19855856,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-11T01:07:58.374Z","updated_at":"2026-04-15T20:03:55.727Z","avatar_url":"https://github.com/marvelapp.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Relay Library for GraphQL Python\n\nThis is a library to allow the easy creation of Relay-compliant servers using\nthe [GraphQL Python](https://github.com/graphql-python/graphql-core) reference implementation\nof a GraphQL server.\n\n*Note: The code is a __exact__ port of the original [graphql-relay js implementation](https://github.com/graphql/graphql-relay-js)\nfrom Facebook*\n\n[![PyPI version](https://badge.fury.io/py/graphql-relay.svg)](https://badge.fury.io/py/graphql-relay)\n[![Build Status](https://travis-ci.org/graphql-python/graphql-relay-py.svg?branch=master)](https://travis-ci.org/graphql-python/graphql-relay-py)\n[![Coverage Status](https://coveralls.io/repos/graphql-python/graphql-relay-py/badge.svg?branch=master\u0026service=github)](https://coveralls.io/github/graphql-python/graphql-relay-py?branch=master)\n\n## Getting Started\n\nA basic understanding of GraphQL and of the GraphQL Python implementation is needed\nto provide context for this library.\n\nAn overview of GraphQL in general is available in the\n[README](https://github.com/graphql-python/graphql-core/blob/master/README.md) for the\n[Specification for GraphQL](https://github.com/graphql-python/graphql-core).\n\nThis library is designed to work with the \nthe [GraphQL Python](https://github.com/graphql-python/graphql-core) reference implementation\nof a GraphQL server.\n\nAn overview of the functionality that a Relay-compliant GraphQL server should\nprovide is in the [GraphQL Relay Specification](https://facebook.github.io/relay/docs/graphql-relay-specification.html)\non the [Relay website](https://facebook.github.io/relay/). That overview\ndescribes a simple set of examples that exist as [tests](tests) in this\nrepository. A good way to get started with this repository is to walk through\nthat documentation and the corresponding tests in this library together.\n\n## Using Relay Library for GraphQL Python (graphql-core)\n\nInstall Relay Library for GraphQL Python\n\n```sh\npip install graphql-core --pre # Last version of graphql-core\npip install graphql-relay\n```\n\nWhen building a schema for [GraphQL](https://github.com/graphql-python/graphql-core),\nthe provided library functions can be used to simplify the creation of Relay\npatterns.\n\n### Connections \n\nHelper functions are provided for both building the GraphQL types\nfor connections and for implementing the `resolver` method for fields\nreturning those types.\n\n - `connection_args` returns the arguments that fields should provide when\nthey return a connection type.\n - `connection_definitions` returns a `connection_type` and its associated\n`edgeType`, given a name and a node type.\n - `connection_from_list` is a helper method that takes an array and the\narguments from `connection_args`, does pagination and filtering, and returns\nan object in the shape expected by a `connection_type`'s `resolver` function.\n - `connection_from_promised_list` is similar to `connection_from_list`, but\nit takes a promise that resolves to an array, and returns a promise that\nresolves to the expected shape by `connection_type`.\n - `cursor_for_object_in_connection` is a helper method that takes an array and a\nmember object, and returns a cursor for use in the mutation payload.\n\nAn example usage of these methods from the [test schema](tests/starwars/schema.py):\n\n```python\nship_edge, ship_connection = connection_definitions('Ship', shipType)\n\nfactionType = GraphQLObjectType(\n    name= 'Faction',\n    description= 'A faction in the Star Wars saga',\n    fields= lambda: {\n        'id': global_id_field('Faction'),\n        'name': GraphQLField(\n            GraphQLString,\n            description='The name of the faction.',\n        ),\n        'ships': GraphQLField(\n            shipConnection,\n            description= 'The ships used by the faction.',\n            args= connection_args,\n            resolver= lambda faction, args, *_: connection_from_list(\n                map(getShip, faction.ships),\n                args\n            ),\n        )\n    },\n    interfaces= [node_interface]\n)\n```\n\nThis shows adding a `ships` field to the `Faction` object that is a connection.\nIt uses `connection_definitions({name: 'Ship', nodeType: shipType})` to create\nthe connection type, adds `connection_args` as arguments on this function, and\nthen implements the resolver function by passing the array of ships and the\narguments to `connection_from_list`.\n\n### Object Identification\n\nHelper functions are provided for both building the GraphQL types\nfor nodes and for implementing global IDs around local IDs.\n\n - `node_definitions` returns the `Node` interface that objects can implement,\nand returns the `node` root field to include on the query type. To implement\nthis, it takes a function to resolve an ID to an object, and to determine\nthe type of a given object.\n - `to_global_id` takes a type name and an ID specific to that type name,\nand returns a \"global ID\" that is unique among all types.\n - `from_global_id` takes the \"global ID\" created by `toGlobalID`, and retuns\nthe type name and ID used to create it.\n - `global_id_field` creates the configuration for an `id` field on a node.\n - `plural_identifying_root_field` creates a field that accepts a list of\nnon-ID identifiers (like a username) and maps then to their corresponding\nobjects.\n\nAn example usage of these methods from the [test schema](tests/starwars/schema.py):\n\n```python\ndef get_node(global_id, context, info):\n    resolvedGlobalId = from_global_id(global_id)\n    _type, _id = resolvedGlobalId.type, resolvedGlobalId.id\n    if _type == 'Faction':\n        return getFaction(_id)\n    elif _type == 'Ship':\n        return getShip(_id)\n    else:\n        return None\n\ndef get_node_type(obj, context, info):\n    if isinstance(obj, Faction):\n        return factionType\n    else:\n        return shipType\n\nnode_interface, node_field = node_definitions(get_node, get_node_type)\n\nfactionType = GraphQLObjectType(\n    name= 'Faction',\n    description= 'A faction in the Star Wars saga',\n    fields= lambda: {\n        'id': global_id_field('Faction'),\n    },\n    interfaces= [node_interface]\n)\n\nqueryType = GraphQLObjectType(\n    name= 'Query',\n    fields= lambda: {\n        'node': node_field\n    }\n)\n```\n\nThis uses `node_definitions` to construct the `Node` interface and the `node`\nfield; it uses `from_global_id` to resolve the IDs passed in in the implementation\nof the function mapping ID to object. It then uses the `global_id_field` method to\ncreate the `id` field on `Faction`, which also ensures implements the\n`node_interface`. Finally, it adds the `node` field to the query type, using the\n`node_field` returned by `node_definitions`.\n\n### Mutations\n\nA helper function is provided for building mutations with\nsingle inputs and client mutation IDs.\n\n - `mutation_with_client_mutation_id` takes a name, input fields, output fields,\nand a mutation method to map from the input fields to the output fields,\nperforming the mutation along the way. It then creates and returns a field\nconfiguration that can be used as a top-level field on the mutation type.\n\nAn example usage of these methods from the [test schema](tests/starwars/schema.py):\n\n```python\nclass IntroduceShipMutation(object):\n    def __init__(self, shipId, factionId, clientMutationId=None):\n        self.shipId = shipId\n        self.factionId = factionId\n        self.clientMutationId = None\n\ndef mutate_and_get_payload(data, *_):\n    shipName = data.get('shipName')\n    factionId = data.get('factionId')\n    newShip = createShip(shipName, factionId)\n    return IntroduceShipMutation(\n        shipId=newShip.id,\n        factionId=factionId,\n    )\n\nshipMutation = mutation_with_client_mutation_id(\n    'IntroduceShip',\n    input_fields={\n        'shipName': GraphQLField(\n            GraphQLNonNull(GraphQLString)\n        ),\n        'factionId': GraphQLField(\n            GraphQLNonNull(GraphQLID)\n        )\n    },\n    output_fields= {\n        'ship': GraphQLField(\n            shipType,\n            resolver= lambda payload, *_: getShip(payload.shipId)\n        ),\n        'faction': GraphQLField(\n            factionType,\n            resolver= lambda payload, *_: getFaction(payload.factionId)\n        )\n    },\n    mutate_and_get_payload=mutate_and_get_payload\n)\n\nmutationType = GraphQLObjectType(\n    'Mutation',\n    fields= lambda: {\n        'introduceShip': shipMutation\n    }\n)\n```\n\nThis code creates a mutation named `IntroduceShip`, which takes a faction\nID and a ship name as input. It outputs the `Faction` and the `Ship` in\nquestion. `mutate_and_get_payload` then gets an object with a property for\neach input field, performs the mutation by constructing the new ship, then\nreturns an object that will be resolved by the output fields.\n\nOur mutation type then creates the `introduceShip` field using the return\nvalue of `mutation_with_client_mutation_id`.\n\n## Contributing\n\nAfter cloning this repo, ensure dependencies are installed by running:\n\n```sh\npython setup.py install\n```\n\nAfter developing, the full test suite can be evaluated by running:\n\n```sh\npython setup.py test # Use --pytest-args=\"-v -s\" for verbose mode\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmarvelapp%2Fgraphql-relay-py","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmarvelapp%2Fgraphql-relay-py","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmarvelapp%2Fgraphql-relay-py/lists"}