├── unittest.cfg ├── doc ├── graphiql.png ├── data_model.png ├── architecture.png ├── data_model.xml └── architecture.xml ├── requirements.txt ├── example ├── utils.py ├── api.py ├── database │ ├── base.py │ ├── model_people.py │ ├── model_planet.py │ └── data │ │ ├── planet.json │ │ └── people.json ├── schema.py ├── setup.py ├── schema_people.py └── schema_planet.py ├── test ├── junit │ └── test-results.xml └── test_api.py ├── .gitignore ├── README.md ├── .circleci └── config.yml └── LICENSE /unittest.cfg: -------------------------------------------------------------------------------- 1 | [junit-xml] 2 | path = test/junit/test-results.xml 3 | -------------------------------------------------------------------------------- /doc/graphiql.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexisrolland/flask-graphene-sqlalchemy/HEAD/doc/graphiql.png -------------------------------------------------------------------------------- /doc/data_model.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexisrolland/flask-graphene-sqlalchemy/HEAD/doc/data_model.png -------------------------------------------------------------------------------- /doc/architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexisrolland/flask-graphene-sqlalchemy/HEAD/doc/architecture.png -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | flask>=1.0.0 2 | flask-graphql==1.4.1 3 | graphene==2.0.0 4 | graphene-sqlalchemy==2.0.0 5 | nose2==0.7.4 6 | requests==2.20.0 7 | sqlalchemy==1.3.0 8 | -------------------------------------------------------------------------------- /example/utils.py: -------------------------------------------------------------------------------- 1 | from graphql_relay.node.node import from_global_id 2 | 3 | 4 | def input_to_dictionary(input): 5 | """Method to convert Graphene inputs into dictionary.""" 6 | dictionary = {} 7 | for key in input: 8 | # Convert GraphQL global id to database id 9 | if key[-2:] == 'id' and input[key] != 'unknown': 10 | input[key] = from_global_id(input[key])[1] 11 | dictionary[key] = input[key] 12 | return dictionary 13 | -------------------------------------------------------------------------------- /example/api.py: -------------------------------------------------------------------------------- 1 | from database.base import db_session 2 | from flask import Flask 3 | from flask_graphql import GraphQLView 4 | from schema import schema 5 | 6 | app = Flask(__name__) 7 | app.add_url_rule( 8 | '/graphql', 9 | view_func=GraphQLView.as_view('graphql', schema=schema, graphiql=True)) 10 | 11 | 12 | @app.teardown_appcontext 13 | def shutdown_session(exception=None): 14 | db_session.remove() 15 | 16 | 17 | if __name__ == '__main__': 18 | app.run(threaded=True) # debug=True 19 | -------------------------------------------------------------------------------- /example/database/base.py: -------------------------------------------------------------------------------- 1 | from sqlalchemy import create_engine 2 | from sqlalchemy.ext.declarative import declarative_base 3 | from sqlalchemy.orm import scoped_session, sessionmaker 4 | import os 5 | 6 | # Create database engine 7 | db_name = 'database.db' 8 | db_path = os.path.join(os.path.dirname(__file__), db_name) 9 | db_uri = 'sqlite:///{}'.format(db_path) 10 | engine = create_engine(db_uri, convert_unicode=True) 11 | 12 | # Declarative base model to create database tables and classes 13 | Base = declarative_base() 14 | Base.metadata.bind = engine # Bind engine to metadata of the base class 15 | 16 | # Create database session object 17 | db_session = scoped_session(sessionmaker(bind=engine, expire_on_commit=False)) 18 | Base.query = db_session.query_property() # Used by graphql to execute queries 19 | -------------------------------------------------------------------------------- /example/schema.py: -------------------------------------------------------------------------------- 1 | from graphene_sqlalchemy import SQLAlchemyConnectionField 2 | import graphene 3 | import schema_planet 4 | import schema_people 5 | 6 | 7 | class Query(graphene.ObjectType): 8 | """Nodes which can be queried by this API.""" 9 | node = graphene.relay.Node.Field() 10 | 11 | # People 12 | people = graphene.relay.Node.Field(schema_people.People) 13 | peopleList = SQLAlchemyConnectionField(schema_people.People) 14 | 15 | # Planet 16 | planet = graphene.relay.Node.Field(schema_planet.Planet) 17 | planetList = SQLAlchemyConnectionField(schema_planet.Planet) 18 | 19 | 20 | class Mutation(graphene.ObjectType): 21 | """Mutations which can be performed by this API.""" 22 | # Person mutation 23 | createPerson = schema_people.CreatePerson.Field() 24 | updatePerson = schema_people.UpdatePerson.Field() 25 | 26 | # Planet mutations 27 | createPlanet = schema_planet.CreatePlanet.Field() 28 | updatePlanet = schema_planet.UpdatePlanet.Field() 29 | 30 | 31 | schema = graphene.Schema(query=Query, mutation=Mutation) 32 | -------------------------------------------------------------------------------- /test/junit/test-results.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /example/setup.py: -------------------------------------------------------------------------------- 1 | from ast import literal_eval 2 | from database.model_people import ModelPeople 3 | from database.model_planet import ModelPlanet 4 | from database import base 5 | import logging 6 | import sys 7 | 8 | # Load logging configuration 9 | log = logging.getLogger(__name__) 10 | logging.basicConfig( 11 | stream=sys.stdout, 12 | level=logging.INFO, 13 | format='%(asctime)s - %(name)s - %(levelname)s - %(message)s') 14 | 15 | 16 | if __name__ == '__main__': 17 | log.info('Create database {}'.format(base.db_name)) 18 | base.Base.metadata.create_all(base.engine) 19 | 20 | log.info('Insert Planet data in database') 21 | with open('database/data/planet.json', 'r') as file: 22 | data = literal_eval(file.read()) 23 | for record in data: 24 | planet = ModelPlanet(**record) 25 | base.db_session.add(planet) 26 | base.db_session.commit() 27 | 28 | log.info('Insert People data in database') 29 | with open('database/data/people.json', 'r') as file: 30 | data = literal_eval(file.read()) 31 | for record in data: 32 | planet = ModelPeople(**record) 33 | base.db_session.add(planet) 34 | base.db_session.commit() 35 | -------------------------------------------------------------------------------- /example/database/model_people.py: -------------------------------------------------------------------------------- 1 | from .base import Base 2 | from sqlalchemy import Column, ForeignKey, Integer, String 3 | 4 | 5 | class ModelPeople(Base): 6 | """People model.""" 7 | 8 | __tablename__ = 'people' 9 | 10 | id = Column('id', Integer, primary_key=True, doc="Id of the person.") 11 | name = Column('name', String, doc="Name of the person.") 12 | height = Column('height', String, doc="Height of the person.") 13 | mass = Column('mass', String, doc="Mass of the person.") 14 | hair_color = Column('hair_color', String, doc="Hair color of the person.") 15 | skin_color = Column('skin_color', String, doc="Skin color of the person.") 16 | eye_color = Column('eye_color', String, doc="Eye color of the person.") 17 | birth_year = Column('birth_year', String, doc="Birth year of the person.") 18 | gender = Column('gender', String, doc="Gender of the person.") 19 | planet_id = Column('planet_id', Integer, ForeignKey('planet.id'), doc="Id of the planet from which the person comes from.") 20 | created = Column('created', String, doc="Record created date.") 21 | edited = Column('edited', String, doc="Record last updated date.") 22 | url = Column('url', String, doc="URL of the person in the Star Wars API.") 23 | -------------------------------------------------------------------------------- /example/database/model_planet.py: -------------------------------------------------------------------------------- 1 | from .base import Base 2 | from .model_people import ModelPeople 3 | from sqlalchemy import Column, Integer, String 4 | from sqlalchemy.orm import relationship 5 | 6 | 7 | class ModelPlanet(Base): 8 | """Planet model.""" 9 | 10 | __tablename__ = 'planet' 11 | 12 | id = Column('id', Integer, primary_key=True, doc="Id of the person.") 13 | name = Column('name', String, doc="Name of the planet.") 14 | rotation_period = Column('rotation_period', String, doc="Rotation period of the planet.") 15 | orbital_period = Column('orbital_period', String, doc="Orbital period of the planet.") 16 | diameter = Column('diameter', String, doc="Diameter of the planet.") 17 | climate = Column('climate', String, doc="Climate period of the planet.") 18 | gravity = Column('gravity', String, doc="Gravity of the planet.") 19 | terrain = Column('terrain', String, doc="Terrain of the planet.") 20 | surface_water = Column('surface_water', String, doc="Surface water of the planet.") 21 | population = Column('population', String, doc="Population of the planet.") 22 | created = Column('created', String, doc="Record created date.") 23 | edited = Column('edited', String, doc="Record last updated date.") 24 | url = Column('url', String, doc="URL of the planet in the Star Wars API.") 25 | 26 | peopleList = relationship(ModelPeople, backref='planet') 27 | -------------------------------------------------------------------------------- /doc/data_model.xml: -------------------------------------------------------------------------------- 1 | 7Vltb5swEP41+ZiJQJJlH9u06aSpWrVOW/cpMvgAq8Zmxnnrr98ZzFtI2lSqWraVSgU/d/Y9vgPzxAy8ebK9UiSNryUFPnAduh14FwPXHY3dKZ4MsiuQ2exTAUSKUetUA7fsASzoWHTFKGQtRy0l1yxtg4EUAgLdwohSctN2CyVvR01JBB3gNiC8i/5kVMcWHTlObfgMLIpt6NnEGnwS3EdKroSNN3C9MD8Kc0LKsax/FhMqNw3Iuxx4cyWlLq6S7Ry4yW2ZtqLf4oi14q1A6FM6uEA9F0LHJR/DMc5jaEdYE76CcgpTjmOdU7Y2hPXOJmn6e2VYnvtyO8zYAxPRwDszKZCKghoijA204/9NkUNjzVM4qSzNfBkz5gvG5q/ySAml1dhuuq0D41VkziknAnRJE+eaMy1sJaqJj7QP0T/OLZRCm5mBtULSjO0EmMmKXGNAt+OVpSTY93K686i4+hKfm31QdRBaIjdfGpOv4a4jo486GrAb5pHAJeJ3fJ4gIkgCPaGipCaaSbFMQTFJnznO6/GUymea8L7TpAxLq0H1lmCkyJrpXU/YYKYUYaInbLKVCkkAyw1pVPCNOaUyXfH8Ce0JoUABpqcvKylQ1h8yK8Wfz8SAh954Bi/e2iXutl7g7hqUZqjZzjiLBEJapuhGbItDmC+b6BXyXGKFDKWPdx7rBE8Xo4FZ+1F4gJFC5pVfaTHTCGTCAnvNiQ/8vFIqc8mlQpOQAkw3reQ9lCAKGCc/KkspIE1AQ6HhaaUh4ig1FiRh3OjlH6AoEcTCVhyPXNs+FKir+koZhymCbQOyKvAKJK7SCnPuWOvYClIr2Es9u2mo35nF4obwrfoRq7ijauRadeKFFZ4nilD3LxShIFPe1DTvIvT/FaFPBLYPUD+ykJAse2bn1yMXE6aWQb7i9ZVids9EzynCDtoM35iPz5SOlzsgfSEUAcqAFyazOHU9LLYvlr1ZFt/17bu+/ff0rTdrC9zxqQJ3+hIC94Ce3Ss2rkBnZuMaW5ffHkDJ7/KaiF27np1STPPDPCYCKd3ZeuaNX6bxYWKaW6bv7AjmurZkmii9H/arrTqaFvkdVXQUtNE6WpBMrlQAj+8t48gR6CM+NjNAWxv03bI26jY5ULYSU2D2Dtbtbf1DpbQRbiTDGVV3zXDUvmuqDxTlEMV8ba/mPvveQHs/r0b7d1WRk844+Y1VzfrQvYbN+mtB4V5/kvEu/wA= -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | env/ 12 | build/ 13 | develop-eggs/ 14 | dist/ 15 | downloads/ 16 | eggs/ 17 | .eggs/ 18 | lib/ 19 | lib64/ 20 | parts/ 21 | sdist/ 22 | var/ 23 | wheels/ 24 | *.egg-info/ 25 | .installed.cfg 26 | *.egg 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a template 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .coverage 42 | .coverage.* 43 | .cache 44 | nosetests.xml 45 | coverage.xml 46 | *.cover 47 | .hypothesis/ 48 | 49 | # Translations 50 | *.mo 51 | *.pot 52 | 53 | # Django stuff: 54 | *.log 55 | local_settings.py 56 | 57 | # Flask stuff: 58 | instance/ 59 | .webassets-cache 60 | 61 | # Scrapy stuff: 62 | .scrapy 63 | 64 | # Sphinx documentation 65 | docs/_build/ 66 | 67 | # PyBuilder 68 | target/ 69 | 70 | # Jupyter Notebook 71 | .ipynb_checkpoints 72 | 73 | # pyenv 74 | .python-version 75 | 76 | # celery beat schedule file 77 | celerybeat-schedule 78 | 79 | # SageMath parsed files 80 | *.sage.py 81 | 82 | # dotenv 83 | .env 84 | 85 | # virtualenv 86 | .venv 87 | venv/ 88 | ENV/ 89 | 90 | # Spyder project settings 91 | .spyderproject 92 | .spyproject 93 | 94 | # Rope project settings 95 | .ropeproject 96 | 97 | # mkdocs documentation 98 | /site 99 | 100 | # mypy 101 | .mypy_cache/ 102 | 103 | # sqlite 104 | *.db 105 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | > Remark: 2 | > Although Graphene is pretty cool, do yourself a favor and check the following tutorial instead of this repository. It allows to generate a feature complete GraphQL API from a PostgreSQL database... in minutes (almost). You'll thank me later: [Docker-PostgreSQL-PostGraphile](https://github.com/alexisrolland/docker-postgresql-postgraphile/wiki) 3 | 4 | # Flask-Graphene-SQLAlchemy 5 | The purpose of this repository is to provide a project template to build a **GraphQL API in Python**. Its content has been largely inspired by the references below but code has been modified and enriched to provide a more complete API and a more scalable architecture. 6 | 7 | # Tutorial 8 | The [Github Wiki](https://github.com/alexisrolland/flask-graphene-sqlalchemy/wiki) provides detailed design intentions in a step by step tutorial. 9 | 10 | # References 11 | * [Graphene-SQLAlchemy](http://docs.graphene-python.org/projects/sqlalchemy/en/latest) 12 | * [Flask-Graphene-SQLAlchemy](https://github.com/Getmrahul/Flask-Graphene-SQLAlchemy) 13 | * [Star Wars API](https://swapi.co) 14 | 15 | # Requirements 16 | This project has been developed on **Linux Ubuntu** with **Python 3.5**. It is using the following third party packages. To install them, open a terminal window, change directory to the project folder and execute the following command: 17 | 18 | `$ pip3 install -r requirements.txt` 19 | 20 | The following Python packages will be installed: 21 | * [flask](http://flask.pocoo.org) (0.12.3) 22 | * [flask-graphql](https://pypi.python.org/pypi/Flask-GraphQL) (1.4.1) 23 | * [graphene](http://graphene-python.org) (2.0.0) 24 | * [graphene-sqlalchemy](https://pypi.python.org/pypi/graphene-sqlalchemy/2.0.0) (2.0.0) 25 | * [nose2](http://nose2.readthedocs.io/en/latest/) (0.7.4) - Used for running tests 26 | * [requests](http://docs.python-requests.org/en/master/) (2.20.0) - Used for running tests 27 | * [sqlalchemy](https://www.sqlalchemy.org) (1.3.0) 28 | 29 | # Run Test Cases 30 | To execute all test cases, change directory to the project root folder and execute the following command: 31 | 32 | $ nose2 -v 33 | -------------------------------------------------------------------------------- /doc/architecture.xml: -------------------------------------------------------------------------------- 1 | 7ZvPc6M2FMf/Gh+bMRIQfMwm2e2hnelMDu2eOjLIhl2MWJATu399JZAwSMIhjiCsW+dg+yE/xPt+9PQzC3i/O3wpUB7/TiKcLsAyOizgwwIAxwU+e+OWY2259Ve1YVskkSh0Mjwl/2BhXArrPolw2SlICUlpkneNIckyHNKODRUFeekW25C0e9ccbbFmeApRqlv/TCIaC6uzXJ4u/IqTbSxuHXjiwhqF37cF2WfifgsAN9WrvrxD0pcoX8YoIi8tE3xcwPuCEFp/2h3uccpjK8NW/+5zz9Wm3gXO6JAfuLD+xTNK91hW2Ue7fAE/ZeuSv+ED+8oCA/yUufwUJc+83vQoYuX/2PPKfqL4QH9BabLNFvCOlUjxhp6usk9b8d5xzpXBhfTN6lm5l2VB506giivmNV+yyy9xQvFTjkJ+9YVxyGwx3aXsm8M+PuOCJkzRu7pKD5TwAqKCD1Xt2O2TNL0nKSmYKSMZrmqUUWli6vnVi9lLWpDv2HQlQmVc1cppKt0WQGjC64MPLZMQ5AsmO0yLIysirkLBhmg7Eq2XE4i+L2xxi0HPFUYk4N82nk8AsA+CATMP8PZVHiJE0RqVXSDM6pb7tWh942jclo+3NI//6Sr3S2eGpA8B20K7XaGha1DaNSgNbCgNTEK/qYWH7MkrXfU2Xvkpc5RJm4TmJlq3QGiXGMgHS5g5/xge0yTjWL0Kybom6rd1DzURwsEmbFEjnsvETRjg9caO+GDpddR3A119xzOoH1gQPzCIrwQaZ9Ed70l5QFJUlknYDWt/o8KHhP7FG/CNJ759Fc351Li5Bxa74tgqyL9+ldci1h+LypCCxmRLMpQ+nqz9EpRkX4TiIYDo3igqtli2HjEU4bc4K1RLCJMO0lbgFNHkuTtyMIkj7vAHSViNGw4c0OUArlZdF/XziF+1u3LVUeB0HS0VUOogaI4qVprHHoTPalR8zmExFC1L+Pg6PrJ3ngk+LrSED5wOHznKH52f2zMAgWkICmafgJo5wE+UgBzZ3Y5NEDhD0O2HETSzHASd4OfLQd40BLXxqXsthZLeHs0WPysDP2BW/KiJQ5vfDOWnWVaRjpZgNH78SfhxPpwfmWtmzI+aNi7mB7oqP95o/JgWWiYZQw/lZxgd8yKhmRwfZSu9NJOojlSkLJIw7mT8TCZptG8rb8gxw/oZ00gXzosOZaTrepeOdP1XHFmkY6K5dj8dzmh0+LOiQx3FXkwHXL3iyB4dQN++2fHNuL9zTPIU3+RHDZb3LLB/0FKp383FzfSivVIKDGCoyf+iZXJ9nCcinKIM0yuJsDbxmjTEegdYbRVcR2jVOcm0odV7jzKM8Q6NlSA8HETuoBgHYA2rPsh+ggCGjbTRQiznR4YQj5MhPibEvXOsSWIMemJ8JcFVc4TjuxMG19WCi/LkSiNr2mQdLbB6vxZTmlcj1R97XFItwHyH/dzQXR5R0U+taFFVTzbskiiqFn1MsnWF7Tv+YEMOZbcK6HKsTAcebKgx6kSqL2bm5RXua9hhks5ai2knQDTemcyhlPUz/9Lll5Xix1H82JtBuW/bSRLN7X1MZNHnhFeoam0lexaqU1eZRbGzhMxEeV+RfnWh8n5w3o9F5fUdoGSXk+I/mJZV8Xw9LRvPoVlIy65pH0U/cPj/YcP3auwpx0qh4VypY1TZisz6dkeJ6T63PczcBCEOh03y14Hnemc3Ot4QXHXjaMrZkauPM8Xs/ltJMrvh3WzAwPBG/tr3LOUnNbzD11DO9GODw6sPHMXM/lrD666G0mshvDINtcK7p0laXukEdNLM4E1zTOr1QwqXH0WY88E5VdrbC8e8jrrBMd50xwOTEPGO7URLx1akxjM+NtfwItOu3Ot9Mz+KI6iO2C7mh309/S9aXfz0D3/w8V8= -------------------------------------------------------------------------------- /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | # Python CircleCI 2.0 configuration file 2 | # 3 | # Check https://circleci.com/docs/2.0/language-python/ for more details 4 | # 5 | version: 2 6 | jobs: 7 | build: 8 | docker: 9 | # specify the version you desire here 10 | # use `-browsers` prefix for selenium tests, e.g. `3.6.1-browsers` 11 | - image: circleci/python:3.6.1 12 | 13 | # Specify service dependencies here if necessary 14 | # CircleCI maintains a library of pre-built images 15 | # documented at https://circleci.com/docs/2.0/circleci-images/ 16 | # - image: circleci/postgres:9.4 17 | 18 | working_directory: ~/repo 19 | 20 | steps: 21 | - checkout 22 | 23 | # Download and cache dependencies 24 | - restore_cache: 25 | keys: 26 | - v1-dependencies-{{ checksum "requirements.txt" }} 27 | # fallback to using the latest cache if no exact match is found 28 | - v1-dependencies- 29 | 30 | - run: 31 | name: Create Virtual Environment 32 | command: | 33 | python3 -m venv gql 34 | 35 | - run: 36 | name: Install Dependencies 37 | command: | 38 | . gql/bin/activate 39 | pip3 install --upgrade pip 40 | pip3 install -r requirements.txt 41 | 42 | - save_cache: 43 | paths: 44 | - ./gql 45 | key: v1-dependencies-{{ checksum "requirements.txt" }} 46 | 47 | - run: 48 | name: Setup Instance 49 | command: | 50 | . gql/bin/activate 51 | cd example 52 | python3 setup.py 53 | 54 | - run: 55 | name: Start API 56 | command: | 57 | . gql/bin/activate 58 | cd example 59 | python3 api.py 60 | background: true 61 | 62 | - run: 63 | name: Run Tests 64 | command: | 65 | . gql/bin/activate 66 | sleep 10 67 | nose2 --plugin nose2.plugins.junitxml --junit-xml -v 68 | 69 | - store_artifacts: 70 | path: test/junit/test-results.xml 71 | destination: test-results 72 | 73 | - store_test_results: 74 | path: test 75 | -------------------------------------------------------------------------------- /example/schema_people.py: -------------------------------------------------------------------------------- 1 | from datetime import datetime 2 | from graphene_sqlalchemy import SQLAlchemyObjectType 3 | from database.base import db_session 4 | from database.model_people import ModelPeople 5 | import graphene 6 | import utils 7 | 8 | 9 | # Create a generic class to mutualize description of people attributes for both queries and mutations 10 | class PeopleAttribute: 11 | name = graphene.String(description="Name of the person.") 12 | height = graphene.String(description="Height of the person.") 13 | mass = graphene.String(description="Mass of the person.") 14 | hair_color = graphene.String(description="Hair color of the person.") 15 | skin_color = graphene.String(description="Skin color of the person.") 16 | eye_color = graphene.String(description="Eye color of the person.") 17 | birth_year = graphene.String(description="Birth year of the person.") 18 | gender = graphene.String(description="Gender of the person.") 19 | planet_id = graphene.ID(description="Global Id of the planet from which the person comes from.") 20 | url = graphene.String(description="URL of the person in the Star Wars API.") 21 | 22 | 23 | class People(SQLAlchemyObjectType): 24 | """People node.""" 25 | 26 | class Meta: 27 | model = ModelPeople 28 | interfaces = (graphene.relay.Node,) 29 | 30 | 31 | class CreatePersonInput(graphene.InputObjectType, PeopleAttribute): 32 | """Arguments to create a person.""" 33 | pass 34 | 35 | 36 | class CreatePerson(graphene.Mutation): 37 | """Mutation to create a person.""" 38 | person = graphene.Field(lambda: People, description="Person created by this mutation.") 39 | 40 | class Arguments: 41 | input = CreatePersonInput(required=True) 42 | 43 | def mutate(self, info, input): 44 | data = utils.input_to_dictionary(input) 45 | data['created'] = datetime.utcnow() 46 | data['edited'] = datetime.utcnow() 47 | 48 | person = ModelPeople(**data) 49 | db_session.add(person) 50 | db_session.commit() 51 | 52 | return CreatePerson(person=person) 53 | 54 | 55 | class UpdatePersonInput(graphene.InputObjectType, PeopleAttribute): 56 | """Arguments to update a person.""" 57 | id = graphene.ID(required=True, description="Global Id of the person.") 58 | 59 | 60 | class UpdatePerson(graphene.Mutation): 61 | """Update a person.""" 62 | person = graphene.Field(lambda: People, description="Person updated by this mutation.") 63 | 64 | class Arguments: 65 | input = UpdatePersonInput(required=True) 66 | 67 | def mutate(self, info, input): 68 | data = utils.input_to_dictionary(input) 69 | data['edited'] = datetime.utcnow() 70 | 71 | person = db_session.query(ModelPeople).filter_by(id=data['id']) 72 | person.update(data) 73 | db_session.commit() 74 | person = db_session.query(ModelPeople).filter_by(id=data['id']).first() 75 | 76 | return UpdatePerson(person=person) 77 | -------------------------------------------------------------------------------- /example/schema_planet.py: -------------------------------------------------------------------------------- 1 | from datetime import datetime 2 | from graphene_sqlalchemy import SQLAlchemyObjectType 3 | from database.base import db_session 4 | from database.model_planet import ModelPlanet 5 | import graphene 6 | import utils 7 | 8 | 9 | # Create a generic class to mutualize description of planet attributes for both queries and mutations 10 | class PlanetAttribute: 11 | name = graphene.String(description="Name of the planet.") 12 | rotation_period = graphene.String(description="Rotation period of the planet.") 13 | orbital_period = graphene.String(description="Orbital period of the planet.") 14 | diameter = graphene.String(description="Diameter of the planet.") 15 | climate = graphene.String(description="Climate period of the planet.") 16 | gravity = graphene.String(description="Gravity of the planet.") 17 | terrain = graphene.String(description="Terrain of the planet.") 18 | surface_water = graphene.String(description="Surface water of the planet.") 19 | population = graphene.String(description="Population of the planet.") 20 | url = graphene.String(description="URL of the planet in the Star Wars API.") 21 | 22 | 23 | class Planet(SQLAlchemyObjectType): 24 | """Planet node.""" 25 | 26 | class Meta: 27 | model = ModelPlanet 28 | interfaces = (graphene.relay.Node,) 29 | 30 | 31 | class CreatePlanetInput(graphene.InputObjectType, PlanetAttribute): 32 | """Arguments to create a planet.""" 33 | pass 34 | 35 | 36 | class CreatePlanet(graphene.Mutation): 37 | """Create a planet.""" 38 | planet = graphene.Field(lambda: Planet, description="Planet created by this mutation.") 39 | 40 | class Arguments: 41 | input = CreatePlanetInput(required=True) 42 | 43 | def mutate(self, info, input): 44 | data = utils.input_to_dictionary(input) 45 | data['created'] = datetime.utcnow() 46 | data['edited'] = datetime.utcnow() 47 | 48 | planet = ModelPlanet(**data) 49 | db_session.add(planet) 50 | db_session.commit() 51 | 52 | return CreatePlanet(planet=planet) 53 | 54 | 55 | class UpdatePlanetInput(graphene.InputObjectType, PlanetAttribute): 56 | """Arguments to update a planet.""" 57 | id = graphene.ID(required=True, description="Global Id of the planet.") 58 | 59 | 60 | class UpdatePlanet(graphene.Mutation): 61 | """Update a planet.""" 62 | planet = graphene.Field(lambda: Planet, description="Planet updated by this mutation.") 63 | 64 | class Arguments: 65 | input = UpdatePlanetInput(required=True) 66 | 67 | def mutate(self, info, input): 68 | data = utils.input_to_dictionary(input) 69 | data['edited'] = datetime.utcnow() 70 | 71 | planet = db_session.query(ModelPlanet).filter_by(id=data['id']) 72 | planet.update(data) 73 | db_session.commit() 74 | planet = db_session.query(ModelPlanet).filter_by(id=data['id']).first() 75 | 76 | return UpdatePlanet(planet=planet) 77 | -------------------------------------------------------------------------------- /test/test_api.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """Unit test for api module GraphQL queries.""" 3 | import requests 4 | import unittest 5 | 6 | 7 | class TestApi(unittest.TestCase): 8 | """Class to execute unit tests for api.py.""" 9 | 10 | @classmethod 11 | def setUpClass(self): 12 | """Set up function called when class is consructed.""" 13 | self.base_url = 'http://127.0.0.1:5000/graphql' 14 | self.headers = {'content-type': 'application/json'} 15 | 16 | def test_query_people(self): 17 | # Get batch list 18 | payload = '{"query": "{people(id:\\"UGVvcGxlOjE=\\"){name}}"}' 19 | response = requests.post(self.base_url, headers=self.headers, data=payload) 20 | json = response.json() 21 | 22 | self.assertEqual(response.status_code, 200) 23 | self.assertEqual(json['data']['people']['name'], 'Luke Skywalker') 24 | 25 | def test_query_people_list(self): 26 | # Get batch list 27 | payload = '{"query": "{peopleList{edges{node{id}}}}"}' 28 | response = requests.post(self.base_url, headers=self.headers, data=payload) 29 | json = response.json() 30 | 31 | self.assertEqual(response.status_code, 200) 32 | self.assertGreater(len(json['data']['peopleList']['edges']), 0) 33 | 34 | def test_query_planet(self): 35 | # Get batch list 36 | payload = '{"query": "{planet(id:\\"UGxhbmV0OjE=\\"){name}}"}' 37 | response = requests.post(self.base_url, headers=self.headers, data=payload) 38 | json = response.json() 39 | 40 | self.assertEqual(response.status_code, 200) 41 | self.assertEqual(json['data']['planet']['name'], 'Tatooine') 42 | 43 | def test_query_planet_list(self): 44 | # Get batch list 45 | payload = '{"query": "{planetList{edges{node{id}}}}"}' 46 | response = requests.post(self.base_url, headers=self.headers, data=payload) 47 | json = response.json() 48 | 49 | self.assertEqual(response.status_code, 200) 50 | self.assertGreater(len(json['data']['planetList']['edges']), 0) 51 | 52 | def test_create_person(self): 53 | # Get batch list 54 | payload = '{"query": "mutation{createPerson(input:{name:\\"Alexis ROLLAND\\"}){person{name}}}"}' 55 | response = requests.post(self.base_url, headers=self.headers, data=payload) 56 | json = response.json() 57 | 58 | self.assertEqual(response.status_code, 200) 59 | self.assertEqual(json['data']['createPerson']['person']['name'], 'Alexis ROLLAND') 60 | 61 | def test_update_person(self): 62 | # Get batch list 63 | payload = '{"query": "mutation{updatePerson(input:{id:\\"UGVvcGxlOjI=\\",height:\\"170\\"}){person{height}}}"}' 64 | response = requests.post(self.base_url, headers=self.headers, data=payload) 65 | json = response.json() 66 | 67 | self.assertEqual(response.status_code, 200) 68 | self.assertEqual(json['data']['updatePerson']['person']['height'], '170') 69 | 70 | def test_create_planet(self): 71 | # Get batch list 72 | payload = '{"query": "mutation{createPlanet(input:{name:\\"Earth\\"}){planet{name}}}"}' 73 | response = requests.post(self.base_url, headers=self.headers, data=payload) 74 | json = response.json() 75 | 76 | self.assertEqual(response.status_code, 200) 77 | self.assertEqual(json['data']['createPlanet']['planet']['name'], 'Earth') 78 | 79 | def test_update_planet(self): 80 | # Get batch list 81 | payload = '{"query": "mutation{updatePlanet(input:{id:\\"UGxhbmV0OjE=\\",rotationPeriod:\\"24\\"}){planet{rotationPeriod}}}"}' 82 | response = requests.post(self.base_url, headers=self.headers, data=payload) 83 | json = response.json() 84 | 85 | self.assertEqual(response.status_code, 200) 86 | self.assertEqual(json['data']['updatePlanet']['planet']['rotationPeriod'], '24') 87 | 88 | @classmethod 89 | def tearDownClass(self): 90 | """Tear down function called when class is deconstructed.""" 91 | pass 92 | 93 | 94 | if __name__ == '__main__': 95 | # Test api endpoints 96 | suite = unittest.TestLoader().loadTestsFromTestCase(TestApi) 97 | unittest.TextTestRunner(verbosity=2).run(suite) 98 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /example/database/data/planet.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "Alderaan", 4 | "rotation_period": "24", 5 | "orbital_period": "364", 6 | "diameter": "12500", 7 | "climate": "temperate", 8 | "gravity": "1 standard", 9 | "terrain": "grasslands, mountains", 10 | "surface_water": "40", 11 | "population": "2000000000", 12 | "created": "2014-12-10 11:35:48.479000Z", 13 | "edited": "2014-12-20 20:58:18.420000Z", 14 | "url": "https://swapi.co/api/planets/2/", 15 | "id": "2" 16 | }, 17 | { 18 | "name": "Yavin IV", 19 | "rotation_period": "24", 20 | "orbital_period": "4818", 21 | "diameter": "10200", 22 | "climate": "temperate, tropical", 23 | "gravity": "1 standard", 24 | "terrain": "jungle, rainforests", 25 | "surface_water": "8", 26 | "population": "1000", 27 | "created": "2014-12-10 11:37:19.144000Z", 28 | "edited": "2014-12-20 20:58:18.421000Z", 29 | "url": "https://swapi.co/api/planets/3/", 30 | "id": "3" 31 | }, 32 | { 33 | "name": "Hoth", 34 | "rotation_period": "23", 35 | "orbital_period": "549", 36 | "diameter": "7200", 37 | "climate": "frozen", 38 | "gravity": "1.1 standard", 39 | "terrain": "tundra, ice caves, mountain ranges", 40 | "surface_water": "100", 41 | "population": "unknown", 42 | "created": "2014-12-10 11:39:13.934000Z", 43 | "edited": "2014-12-20 20:58:18.423000Z", 44 | "url": "https://swapi.co/api/planets/4/", 45 | "id": "4" 46 | }, 47 | { 48 | "name": "Dagobah", 49 | "rotation_period": "23", 50 | "orbital_period": "341", 51 | "diameter": "8900", 52 | "climate": "murky", 53 | "gravity": "N/A", 54 | "terrain": "swamp, jungles", 55 | "surface_water": "8", 56 | "population": "unknown", 57 | "created": "2014-12-10 11:42:22.590000Z", 58 | "edited": "2014-12-20 20:58:18.425000Z", 59 | "url": "https://swapi.co/api/planets/5/", 60 | "id": "5" 61 | }, 62 | { 63 | "name": "Bespin", 64 | "rotation_period": "12", 65 | "orbital_period": "5110", 66 | "diameter": "118000", 67 | "climate": "temperate", 68 | "gravity": "1.5 (surface), 1 standard (Cloud City)", 69 | "terrain": "gas giant", 70 | "surface_water": "0", 71 | "population": "6000000", 72 | "created": "2014-12-10 11:43:55.240000Z", 73 | "edited": "2014-12-20 20:58:18.427000Z", 74 | "url": "https://swapi.co/api/planets/6/", 75 | "id": "6" 76 | }, 77 | { 78 | "name": "Endor", 79 | "rotation_period": "18", 80 | "orbital_period": "402", 81 | "diameter": "4900", 82 | "climate": "temperate", 83 | "gravity": "0.85 standard", 84 | "terrain": "forests, mountains, lakes", 85 | "surface_water": "8", 86 | "population": "30000000", 87 | "created": "2014-12-10 11:50:29.349000Z", 88 | "edited": "2014-12-20 20:58:18.429000Z", 89 | "url": "https://swapi.co/api/planets/7/", 90 | "id": "7" 91 | }, 92 | { 93 | "name": "Naboo", 94 | "rotation_period": "26", 95 | "orbital_period": "312", 96 | "diameter": "12120", 97 | "climate": "temperate", 98 | "gravity": "1 standard", 99 | "terrain": "grassy hills, swamps, forests, mountains", 100 | "surface_water": "12", 101 | "population": "4500000000", 102 | "created": "2014-12-10 11:52:31.066000Z", 103 | "edited": "2014-12-20 20:58:18.430000Z", 104 | "url": "https://swapi.co/api/planets/8/", 105 | "id": "8" 106 | }, 107 | { 108 | "name": "Coruscant", 109 | "rotation_period": "24", 110 | "orbital_period": "368", 111 | "diameter": "12240", 112 | "climate": "temperate", 113 | "gravity": "1 standard", 114 | "terrain": "cityscape, mountains", 115 | "surface_water": "unknown", 116 | "population": "1000000000000", 117 | "created": "2014-12-10 11:54:13.921000Z", 118 | "edited": "2014-12-20 20:58:18.432000Z", 119 | "url": "https://swapi.co/api/planets/9/", 120 | "id": "9" 121 | }, 122 | { 123 | "name": "Kamino", 124 | "rotation_period": "27", 125 | "orbital_period": "463", 126 | "diameter": "19720", 127 | "climate": "temperate", 128 | "gravity": "1 standard", 129 | "terrain": "ocean", 130 | "surface_water": "100", 131 | "population": "1000000000", 132 | "created": "2014-12-10 12:45:06.577000Z", 133 | "edited": "2014-12-20 20:58:18.434000Z", 134 | "url": "https://swapi.co/api/planets/10/", 135 | "id": "10" 136 | }, 137 | { 138 | "name": "Geonosis", 139 | "rotation_period": "30", 140 | "orbital_period": "256", 141 | "diameter": "11370", 142 | "climate": "temperate, arid", 143 | "gravity": "0.9 standard", 144 | "terrain": "rock, desert, mountain, barren", 145 | "surface_water": "5", 146 | "population": "100000000000", 147 | "created": "2014-12-10 12:47:22.350000Z", 148 | "edited": "2014-12-20 20:58:18.437000Z", 149 | "url": "https://swapi.co/api/planets/11/", 150 | "id": "11" 151 | }, 152 | { 153 | "name": "Utapau", 154 | "rotation_period": "27", 155 | "orbital_period": "351", 156 | "diameter": "12900", 157 | "climate": "temperate, arid, windy", 158 | "gravity": "1 standard", 159 | "terrain": "scrublands, savanna, canyons, sinkholes", 160 | "surface_water": "0.9", 161 | "population": "95000000", 162 | "created": "2014-12-10 12:49:01.491000Z", 163 | "edited": "2014-12-20 20:58:18.439000Z", 164 | "url": "https://swapi.co/api/planets/12/", 165 | "id": "12" 166 | }, 167 | { 168 | "name": "Mustafar", 169 | "rotation_period": "36", 170 | "orbital_period": "412", 171 | "diameter": "4200", 172 | "climate": "hot", 173 | "gravity": "1 standard", 174 | "terrain": "volcanoes, lava rivers, mountains, caves", 175 | "surface_water": "0", 176 | "population": "20000", 177 | "created": "2014-12-10 12:50:16.526000Z", 178 | "edited": "2014-12-20 20:58:18.440000Z", 179 | "url": "https://swapi.co/api/planets/13/", 180 | "id": "13" 181 | }, 182 | { 183 | "name": "Kashyyyk", 184 | "rotation_period": "26", 185 | "orbital_period": "381", 186 | "diameter": "12765", 187 | "climate": "tropical", 188 | "gravity": "1 standard", 189 | "terrain": "jungle, forests, lakes, rivers", 190 | "surface_water": "60", 191 | "population": "45000000", 192 | "created": "2014-12-10 13:32:00.124000Z", 193 | "edited": "2014-12-20 20:58:18.442000Z", 194 | "url": "https://swapi.co/api/planets/14/", 195 | "id": "14" 196 | }, 197 | { 198 | "name": "Polis Massa", 199 | "rotation_period": "24", 200 | "orbital_period": "590", 201 | "diameter": "0", 202 | "climate": "artificial temperate ", 203 | "gravity": "0.56 standard", 204 | "terrain": "airless asteroid", 205 | "surface_water": "0", 206 | "population": "1000000", 207 | "created": "2014-12-10 13:33:46.405000Z", 208 | "edited": "2014-12-20 20:58:18.444000Z", 209 | "url": "https://swapi.co/api/planets/15/", 210 | "id": "15" 211 | }, 212 | { 213 | "name": "Mygeeto", 214 | "rotation_period": "12", 215 | "orbital_period": "167", 216 | "diameter": "10088", 217 | "climate": "frigid", 218 | "gravity": "1 standard", 219 | "terrain": "glaciers, mountains, ice canyons", 220 | "surface_water": "unknown", 221 | "population": "19000000", 222 | "created": "2014-12-10 13:43:39.139000Z", 223 | "edited": "2014-12-20 20:58:18.446000Z", 224 | "url": "https://swapi.co/api/planets/16/", 225 | "id": "16" 226 | }, 227 | { 228 | "name": "Felucia", 229 | "rotation_period": "34", 230 | "orbital_period": "231", 231 | "diameter": "9100", 232 | "climate": "hot, humid", 233 | "gravity": "0.75 standard", 234 | "terrain": "fungus forests", 235 | "surface_water": "unknown", 236 | "population": "8500000", 237 | "created": "2014-12-10 13:44:50.397000Z", 238 | "edited": "2014-12-20 20:58:18.447000Z", 239 | "url": "https://swapi.co/api/planets/17/", 240 | "id": "17" 241 | }, 242 | { 243 | "name": "Cato Neimoidia", 244 | "rotation_period": "25", 245 | "orbital_period": "278", 246 | "diameter": "0", 247 | "climate": "temperate, moist", 248 | "gravity": "1 standard", 249 | "terrain": "mountains, fields, forests, rock arches", 250 | "surface_water": "unknown", 251 | "population": "10000000", 252 | "created": "2014-12-10 13:46:28.704000Z", 253 | "edited": "2014-12-20 20:58:18.449000Z", 254 | "url": "https://swapi.co/api/planets/18/", 255 | "id": "18" 256 | }, 257 | { 258 | "name": "Saleucami", 259 | "rotation_period": "26", 260 | "orbital_period": "392", 261 | "diameter": "14920", 262 | "climate": "hot", 263 | "gravity": "unknown", 264 | "terrain": "caves, desert, mountains, volcanoes", 265 | "surface_water": "unknown", 266 | "population": "1400000000", 267 | "created": "2014-12-10 13:47:46.874000Z", 268 | "edited": "2014-12-20 20:58:18.450000Z", 269 | "url": "https://swapi.co/api/planets/19/", 270 | "id": "19" 271 | }, 272 | { 273 | "name": "Stewjon", 274 | "rotation_period": "unknown", 275 | "orbital_period": "unknown", 276 | "diameter": "0", 277 | "climate": "temperate", 278 | "gravity": "1 standard", 279 | "terrain": "grass", 280 | "surface_water": "unknown", 281 | "population": "unknown", 282 | "created": "2014-12-10 16:16:26.566000Z", 283 | "edited": "2014-12-20 20:58:18.452000Z", 284 | "url": "https://swapi.co/api/planets/20/", 285 | "id": "20" 286 | }, 287 | { 288 | "name": "Eriadu", 289 | "rotation_period": "24", 290 | "orbital_period": "360", 291 | "diameter": "13490", 292 | "climate": "polluted", 293 | "gravity": "1 standard", 294 | "terrain": "cityscape", 295 | "surface_water": "unknown", 296 | "population": "22000000000", 297 | "created": "2014-12-10 16:26:54.384000Z", 298 | "edited": "2014-12-20 20:58:18.454000Z", 299 | "url": "https://swapi.co/api/planets/21/", 300 | "id": "21" 301 | }, 302 | { 303 | "name": "Corellia", 304 | "rotation_period": "25", 305 | "orbital_period": "329", 306 | "diameter": "11000", 307 | "climate": "temperate", 308 | "gravity": "1 standard", 309 | "terrain": "plains, urban, hills, forests", 310 | "surface_water": "70", 311 | "population": "3000000000", 312 | "created": "2014-12-10 16:49:12.453000Z", 313 | "edited": "2014-12-20 20:58:18.456000Z", 314 | "url": "https://swapi.co/api/planets/22/", 315 | "id": "22" 316 | }, 317 | { 318 | "name": "Rodia", 319 | "rotation_period": "29", 320 | "orbital_period": "305", 321 | "diameter": "7549", 322 | "climate": "hot", 323 | "gravity": "1 standard", 324 | "terrain": "jungles, oceans, urban, swamps", 325 | "surface_water": "60", 326 | "population": "1300000000", 327 | "created": "2014-12-10 17:03:28.110000Z", 328 | "edited": "2014-12-20 20:58:18.458000Z", 329 | "url": "https://swapi.co/api/planets/23/", 330 | "id": "23" 331 | }, 332 | { 333 | "name": "Nal Hutta", 334 | "rotation_period": "87", 335 | "orbital_period": "413", 336 | "diameter": "12150", 337 | "climate": "temperate", 338 | "gravity": "1 standard", 339 | "terrain": "urban, oceans, swamps, bogs", 340 | "surface_water": "unknown", 341 | "population": "7000000000", 342 | "created": "2014-12-10 17:11:29.452000Z", 343 | "edited": "2014-12-20 20:58:18.460000Z", 344 | "url": "https://swapi.co/api/planets/24/", 345 | "id": "24" 346 | }, 347 | { 348 | "name": "Dantooine", 349 | "rotation_period": "25", 350 | "orbital_period": "378", 351 | "diameter": "9830", 352 | "climate": "temperate", 353 | "gravity": "1 standard", 354 | "terrain": "oceans, savannas, mountains, grasslands", 355 | "surface_water": "unknown", 356 | "population": "1000", 357 | "created": "2014-12-10 17:23:29.896000Z", 358 | "edited": "2014-12-20 20:58:18.461000Z", 359 | "url": "https://swapi.co/api/planets/25/", 360 | "id": "25" 361 | }, 362 | { 363 | "name": "Bestine IV", 364 | "rotation_period": "26", 365 | "orbital_period": "680", 366 | "diameter": "6400", 367 | "climate": "temperate", 368 | "gravity": "unknown", 369 | "terrain": "rocky islands, oceans", 370 | "surface_water": "98", 371 | "population": "62000000", 372 | "created": "2014-12-12 11:16:55.078000Z", 373 | "edited": "2014-12-20 20:58:18.463000Z", 374 | "url": "https://swapi.co/api/planets/26/", 375 | "id": "26" 376 | }, 377 | { 378 | "name": "Ord Mantell", 379 | "rotation_period": "26", 380 | "orbital_period": "334", 381 | "diameter": "14050", 382 | "climate": "temperate", 383 | "gravity": "1 standard", 384 | "terrain": "plains, seas, mesas", 385 | "surface_water": "10", 386 | "population": "4000000000", 387 | "created": "2014-12-15 12:23:41.661000Z", 388 | "edited": "2014-12-20 20:58:18.464000Z", 389 | "url": "https://swapi.co/api/planets/27/", 390 | "id": "27" 391 | }, 392 | { 393 | "name": "unknown", 394 | "rotation_period": "0", 395 | "orbital_period": "0", 396 | "diameter": "0", 397 | "climate": "unknown", 398 | "gravity": "unknown", 399 | "terrain": "unknown", 400 | "surface_water": "unknown", 401 | "population": "unknown", 402 | "created": "2014-12-15 12:25:59.569000Z", 403 | "edited": "2014-12-20 20:58:18.466000Z", 404 | "url": "https://swapi.co/api/planets/28/", 405 | "id": "28" 406 | }, 407 | { 408 | "name": "Trandosha", 409 | "rotation_period": "25", 410 | "orbital_period": "371", 411 | "diameter": "0", 412 | "climate": "arid", 413 | "gravity": "0.62 standard", 414 | "terrain": "mountains, seas, grasslands, deserts", 415 | "surface_water": "unknown", 416 | "population": "42000000", 417 | "created": "2014-12-15 12:53:47.695000Z", 418 | "edited": "2014-12-20 20:58:18.468000Z", 419 | "url": "https://swapi.co/api/planets/29/", 420 | "id": "29" 421 | }, 422 | { 423 | "name": "Socorro", 424 | "rotation_period": "20", 425 | "orbital_period": "326", 426 | "diameter": "0", 427 | "climate": "arid", 428 | "gravity": "1 standard", 429 | "terrain": "deserts, mountains", 430 | "surface_water": "unknown", 431 | "population": "300000000", 432 | "created": "2014-12-15 12:56:31.121000Z", 433 | "edited": "2014-12-20 20:58:18.469000Z", 434 | "url": "https://swapi.co/api/planets/30/", 435 | "id": "30" 436 | }, 437 | { 438 | "name": "Mon Cala", 439 | "rotation_period": "21", 440 | "orbital_period": "398", 441 | "diameter": "11030", 442 | "climate": "temperate", 443 | "gravity": "1", 444 | "terrain": "oceans, reefs, islands", 445 | "surface_water": "100", 446 | "population": "27000000000", 447 | "created": "2014-12-18 11:07:01.792000Z", 448 | "edited": "2014-12-20 20:58:18.471000Z", 449 | "url": "https://swapi.co/api/planets/31/", 450 | "id": "31" 451 | }, 452 | { 453 | "name": "Chandrila", 454 | "rotation_period": "20", 455 | "orbital_period": "368", 456 | "diameter": "13500", 457 | "climate": "temperate", 458 | "gravity": "1", 459 | "terrain": "plains, forests", 460 | "surface_water": "40", 461 | "population": "1200000000", 462 | "created": "2014-12-18 11:11:51.872000Z", 463 | "edited": "2014-12-20 20:58:18.472000Z", 464 | "url": "https://swapi.co/api/planets/32/", 465 | "id": "32" 466 | }, 467 | { 468 | "name": "Sullust", 469 | "rotation_period": "20", 470 | "orbital_period": "263", 471 | "diameter": "12780", 472 | "climate": "superheated", 473 | "gravity": "1", 474 | "terrain": "mountains, volcanoes, rocky deserts", 475 | "surface_water": "5", 476 | "population": "18500000000", 477 | "created": "2014-12-18 11:25:40.243000Z", 478 | "edited": "2014-12-20 20:58:18.474000Z", 479 | "url": "https://swapi.co/api/planets/33/", 480 | "id": "33" 481 | }, 482 | { 483 | "name": "Toydaria", 484 | "rotation_period": "21", 485 | "orbital_period": "184", 486 | "diameter": "7900", 487 | "climate": "temperate", 488 | "gravity": "1", 489 | "terrain": "swamps, lakes", 490 | "surface_water": "unknown", 491 | "population": "11000000", 492 | "created": "2014-12-19 17:47:54.403000Z", 493 | "edited": "2014-12-20 20:58:18.476000Z", 494 | "url": "https://swapi.co/api/planets/34/", 495 | "id": "34" 496 | }, 497 | { 498 | "name": "Malastare", 499 | "rotation_period": "26", 500 | "orbital_period": "201", 501 | "diameter": "18880", 502 | "climate": "arid, temperate, tropical", 503 | "gravity": "1.56", 504 | "terrain": "swamps, deserts, jungles, mountains", 505 | "surface_water": "unknown", 506 | "population": "2000000000", 507 | "created": "2014-12-19 17:52:13.106000Z", 508 | "edited": "2014-12-20 20:58:18.478000Z", 509 | "url": "https://swapi.co/api/planets/35/", 510 | "id": "35" 511 | }, 512 | { 513 | "name": "Dathomir", 514 | "rotation_period": "24", 515 | "orbital_period": "491", 516 | "diameter": "10480", 517 | "climate": "temperate", 518 | "gravity": "0.9", 519 | "terrain": "forests, deserts, savannas", 520 | "surface_water": "unknown", 521 | "population": "5200", 522 | "created": "2014-12-19 18:00:40.142000Z", 523 | "edited": "2014-12-20 20:58:18.480000Z", 524 | "url": "https://swapi.co/api/planets/36/", 525 | "id": "36" 526 | }, 527 | { 528 | "name": "Ryloth", 529 | "rotation_period": "30", 530 | "orbital_period": "305", 531 | "diameter": "10600", 532 | "climate": "temperate, arid, subartic", 533 | "gravity": "1", 534 | "terrain": "mountains, valleys, deserts, tundra", 535 | "surface_water": "5", 536 | "population": "1500000000", 537 | "created": "2014-12-20 09:46:25.740000Z", 538 | "edited": "2014-12-20 20:58:18.481000Z", 539 | "url": "https://swapi.co/api/planets/37/", 540 | "id": "37" 541 | }, 542 | { 543 | "name": "Aleen Minor", 544 | "rotation_period": "unknown", 545 | "orbital_period": "unknown", 546 | "diameter": "unknown", 547 | "climate": "unknown", 548 | "gravity": "unknown", 549 | "terrain": "unknown", 550 | "surface_water": "unknown", 551 | "population": "unknown", 552 | "created": "2014-12-20 09:52:23.452000Z", 553 | "edited": "2014-12-20 20:58:18.483000Z", 554 | "url": "https://swapi.co/api/planets/38/", 555 | "id": "38" 556 | }, 557 | { 558 | "name": "Vulpter", 559 | "rotation_period": "22", 560 | "orbital_period": "391", 561 | "diameter": "14900", 562 | "climate": "temperate, artic", 563 | "gravity": "1", 564 | "terrain": "urban, barren", 565 | "surface_water": "unknown", 566 | "population": "421000000", 567 | "created": "2014-12-20 09:56:58.874000Z", 568 | "edited": "2014-12-20 20:58:18.485000Z", 569 | "url": "https://swapi.co/api/planets/39/", 570 | "id": "39" 571 | }, 572 | { 573 | "name": "Troiken", 574 | "rotation_period": "unknown", 575 | "orbital_period": "unknown", 576 | "diameter": "unknown", 577 | "climate": "unknown", 578 | "gravity": "unknown", 579 | "terrain": "desert, tundra, rainforests, mountains", 580 | "surface_water": "unknown", 581 | "population": "unknown", 582 | "created": "2014-12-20 10:01:37.395000Z", 583 | "edited": "2014-12-20 20:58:18.487000Z", 584 | "url": "https://swapi.co/api/planets/40/", 585 | "id": "40" 586 | }, 587 | { 588 | "name": "Tund", 589 | "rotation_period": "48", 590 | "orbital_period": "1770", 591 | "diameter": "12190", 592 | "climate": "unknown", 593 | "gravity": "unknown", 594 | "terrain": "barren, ash", 595 | "surface_water": "unknown", 596 | "population": "0", 597 | "created": "2014-12-20 10:07:29.578000Z", 598 | "edited": "2014-12-20 20:58:18.489000Z", 599 | "url": "https://swapi.co/api/planets/41/", 600 | "id": "41" 601 | }, 602 | { 603 | "name": "Haruun Kal", 604 | "rotation_period": "25", 605 | "orbital_period": "383", 606 | "diameter": "10120", 607 | "climate": "temperate", 608 | "gravity": "0.98", 609 | "terrain": "toxic cloudsea, plateaus, volcanoes", 610 | "surface_water": "unknown", 611 | "population": "705300", 612 | "created": "2014-12-20 10:12:28.980000Z", 613 | "edited": "2014-12-20 20:58:18.491000Z", 614 | "url": "https://swapi.co/api/planets/42/", 615 | "id": "42" 616 | }, 617 | { 618 | "name": "Cerea", 619 | "rotation_period": "27", 620 | "orbital_period": "386", 621 | "diameter": "unknown", 622 | "climate": "temperate", 623 | "gravity": "1", 624 | "terrain": "verdant", 625 | "surface_water": "20", 626 | "population": "450000000", 627 | "created": "2014-12-20 10:14:48.178000Z", 628 | "edited": "2014-12-20 20:58:18.493000Z", 629 | "url": "https://swapi.co/api/planets/43/", 630 | "id": "43" 631 | }, 632 | { 633 | "name": "Glee Anselm", 634 | "rotation_period": "33", 635 | "orbital_period": "206", 636 | "diameter": "15600", 637 | "climate": "tropical, temperate", 638 | "gravity": "1", 639 | "terrain": "lakes, islands, swamps, seas", 640 | "surface_water": "80", 641 | "population": "500000000", 642 | "created": "2014-12-20 10:18:26.110000Z", 643 | "edited": "2014-12-20 20:58:18.495000Z", 644 | "url": "https://swapi.co/api/planets/44/", 645 | "id": "44" 646 | }, 647 | { 648 | "name": "Iridonia", 649 | "rotation_period": "29", 650 | "orbital_period": "413", 651 | "diameter": "unknown", 652 | "climate": "unknown", 653 | "gravity": "unknown", 654 | "terrain": "rocky canyons, acid pools", 655 | "surface_water": "unknown", 656 | "population": "unknown", 657 | "created": "2014-12-20 10:26:05.788000Z", 658 | "edited": "2014-12-20 20:58:18.497000Z", 659 | "url": "https://swapi.co/api/planets/45/", 660 | "id": "45" 661 | }, 662 | { 663 | "name": "Tholoth", 664 | "rotation_period": "unknown", 665 | "orbital_period": "unknown", 666 | "diameter": "unknown", 667 | "climate": "unknown", 668 | "gravity": "unknown", 669 | "terrain": "unknown", 670 | "surface_water": "unknown", 671 | "population": "unknown", 672 | "created": "2014-12-20 10:28:31.117000Z", 673 | "edited": "2014-12-20 20:58:18.498000Z", 674 | "url": "https://swapi.co/api/planets/46/", 675 | "id": "46" 676 | }, 677 | { 678 | "name": "Iktotch", 679 | "rotation_period": "22", 680 | "orbital_period": "481", 681 | "diameter": "unknown", 682 | "climate": "arid, rocky, windy", 683 | "gravity": "1", 684 | "terrain": "rocky", 685 | "surface_water": "unknown", 686 | "population": "unknown", 687 | "created": "2014-12-20 10:31:32.413000Z", 688 | "edited": "2014-12-20 20:58:18.500000Z", 689 | "url": "https://swapi.co/api/planets/47/", 690 | "id": "47" 691 | }, 692 | { 693 | "name": "Quermia", 694 | "rotation_period": "unknown", 695 | "orbital_period": "unknown", 696 | "diameter": "unknown", 697 | "climate": "unknown", 698 | "gravity": "unknown", 699 | "terrain": "unknown", 700 | "surface_water": "unknown", 701 | "population": "unknown", 702 | "created": "2014-12-20 10:34:08.249000Z", 703 | "edited": "2014-12-20 20:58:18.502000Z", 704 | "url": "https://swapi.co/api/planets/48/", 705 | "id": "48" 706 | }, 707 | { 708 | "name": "Dorin", 709 | "rotation_period": "22", 710 | "orbital_period": "409", 711 | "diameter": "13400", 712 | "climate": "temperate", 713 | "gravity": "1", 714 | "terrain": "unknown", 715 | "surface_water": "unknown", 716 | "population": "unknown", 717 | "created": "2014-12-20 10:48:36.141000Z", 718 | "edited": "2014-12-20 20:58:18.504000Z", 719 | "url": "https://swapi.co/api/planets/49/", 720 | "id": "49" 721 | }, 722 | { 723 | "name": "Champala", 724 | "rotation_period": "27", 725 | "orbital_period": "318", 726 | "diameter": "unknown", 727 | "climate": "temperate", 728 | "gravity": "1", 729 | "terrain": "oceans, rainforests, plateaus", 730 | "surface_water": "unknown", 731 | "population": "3500000000", 732 | "created": "2014-12-20 10:52:51.524000Z", 733 | "edited": "2014-12-20 20:58:18.506000Z", 734 | "url": "https://swapi.co/api/planets/50/", 735 | "id": "50" 736 | }, 737 | { 738 | "name": "Mirial", 739 | "rotation_period": "unknown", 740 | "orbital_period": "unknown", 741 | "diameter": "unknown", 742 | "climate": "unknown", 743 | "gravity": "unknown", 744 | "terrain": "deserts", 745 | "surface_water": "unknown", 746 | "population": "unknown", 747 | "created": "2014-12-20 16:44:46.318000Z", 748 | "edited": "2014-12-20 20:58:18.508000Z", 749 | "url": "https://swapi.co/api/planets/51/", 750 | "id": "51" 751 | }, 752 | { 753 | "name": "Serenno", 754 | "rotation_period": "unknown", 755 | "orbital_period": "unknown", 756 | "diameter": "unknown", 757 | "climate": "unknown", 758 | "gravity": "unknown", 759 | "terrain": "rainforests, rivers, mountains", 760 | "surface_water": "unknown", 761 | "population": "unknown", 762 | "created": "2014-12-20 16:52:13.357000Z", 763 | "edited": "2014-12-20 20:58:18.510000Z", 764 | "url": "https://swapi.co/api/planets/52/", 765 | "id": "52" 766 | }, 767 | { 768 | "name": "Concord Dawn", 769 | "rotation_period": "unknown", 770 | "orbital_period": "unknown", 771 | "diameter": "unknown", 772 | "climate": "unknown", 773 | "gravity": "unknown", 774 | "terrain": "jungles, forests, deserts", 775 | "surface_water": "unknown", 776 | "population": "unknown", 777 | "created": "2014-12-20 16:54:39.909000Z", 778 | "edited": "2014-12-20 20:58:18.512000Z", 779 | "url": "https://swapi.co/api/planets/53/", 780 | "id": "53" 781 | }, 782 | { 783 | "name": "Zolan", 784 | "rotation_period": "unknown", 785 | "orbital_period": "unknown", 786 | "diameter": "unknown", 787 | "climate": "unknown", 788 | "gravity": "unknown", 789 | "terrain": "unknown", 790 | "surface_water": "unknown", 791 | "population": "unknown", 792 | "created": "2014-12-20 16:56:37.250000Z", 793 | "edited": "2014-12-20 20:58:18.514000Z", 794 | "url": "https://swapi.co/api/planets/54/", 795 | "id": "54" 796 | }, 797 | { 798 | "name": "Ojom", 799 | "rotation_period": "unknown", 800 | "orbital_period": "unknown", 801 | "diameter": "unknown", 802 | "climate": "frigid", 803 | "gravity": "unknown", 804 | "terrain": "oceans, glaciers", 805 | "surface_water": "100", 806 | "population": "500000000", 807 | "created": "2014-12-20 17:27:41.286000Z", 808 | "edited": "2014-12-20 20:58:18.516000Z", 809 | "url": "https://swapi.co/api/planets/55/", 810 | "id": "55" 811 | }, 812 | { 813 | "name": "Skako", 814 | "rotation_period": "27", 815 | "orbital_period": "384", 816 | "diameter": "unknown", 817 | "climate": "temperate", 818 | "gravity": "1", 819 | "terrain": "urban, vines", 820 | "surface_water": "unknown", 821 | "population": "500000000000", 822 | "created": "2014-12-20 17:50:47.864000Z", 823 | "edited": "2014-12-20 20:58:18.517000Z", 824 | "url": "https://swapi.co/api/planets/56/", 825 | "id": "56" 826 | }, 827 | { 828 | "name": "Muunilinst", 829 | "rotation_period": "28", 830 | "orbital_period": "412", 831 | "diameter": "13800", 832 | "climate": "temperate", 833 | "gravity": "1", 834 | "terrain": "plains, forests, hills, mountains", 835 | "surface_water": "25", 836 | "population": "5000000000", 837 | "created": "2014-12-20 17:57:47.420000Z", 838 | "edited": "2014-12-20 20:58:18.519000Z", 839 | "url": "https://swapi.co/api/planets/57/", 840 | "id": "57" 841 | }, 842 | { 843 | "name": "Shili", 844 | "rotation_period": "unknown", 845 | "orbital_period": "unknown", 846 | "diameter": "unknown", 847 | "climate": "temperate", 848 | "gravity": "1", 849 | "terrain": "cities, savannahs, seas, plains", 850 | "surface_water": "unknown", 851 | "population": "unknown", 852 | "created": "2014-12-20 18:43:14.049000Z", 853 | "edited": "2014-12-20 20:58:18.521000Z", 854 | "url": "https://swapi.co/api/planets/58/", 855 | "id": "58" 856 | }, 857 | { 858 | "name": "Kalee", 859 | "rotation_period": "23", 860 | "orbital_period": "378", 861 | "diameter": "13850", 862 | "climate": "arid, temperate, tropical", 863 | "gravity": "1", 864 | "terrain": "rainforests, cliffs, canyons, seas", 865 | "surface_water": "unknown", 866 | "population": "4000000000", 867 | "created": "2014-12-20 19:43:51.278000Z", 868 | "edited": "2014-12-20 20:58:18.523000Z", 869 | "url": "https://swapi.co/api/planets/59/", 870 | "id": "59" 871 | }, 872 | { 873 | "name": "Umbara", 874 | "rotation_period": "unknown", 875 | "orbital_period": "unknown", 876 | "diameter": "unknown", 877 | "climate": "unknown", 878 | "gravity": "unknown", 879 | "terrain": "unknown", 880 | "surface_water": "unknown", 881 | "population": "unknown", 882 | "created": "2014-12-20 20:18:36.256000Z", 883 | "edited": "2014-12-20 20:58:18.525000Z", 884 | "url": "https://swapi.co/api/planets/60/", 885 | "id": "60" 886 | }, 887 | { 888 | "name": "Tatooine", 889 | "rotation_period": "23", 890 | "orbital_period": "304", 891 | "diameter": "10465", 892 | "climate": "arid", 893 | "gravity": "1 standard", 894 | "terrain": "desert", 895 | "surface_water": "1", 896 | "population": "200000", 897 | "created": "2014-12-09 13:50:49.641000Z", 898 | "edited": "2014-12-21 20:48:04.175778Z", 899 | "url": "https://swapi.co/api/planets/1/", 900 | "id": "1" 901 | }, 902 | { 903 | "name": "Jakku", 904 | "rotation_period": "unknown", 905 | "orbital_period": "unknown", 906 | "diameter": "unknown", 907 | "climate": "unknown", 908 | "gravity": "unknown", 909 | "terrain": "deserts", 910 | "surface_water": "unknown", 911 | "population": "unknown", 912 | "created": "2015-04-17 06:55:57.556495Z", 913 | "edited": "2015-04-17 06:55:57.556551Z", 914 | "url": "https://swapi.co/api/planets/61/", 915 | "id": "61" 916 | } 917 | ] 918 | -------------------------------------------------------------------------------- /example/database/data/people.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "Luke Skywalker", 4 | "height": "172", 5 | "mass": "77", 6 | "hair_color": "blond", 7 | "skin_color": "fair", 8 | "eye_color": "blue", 9 | "birth_year": "19BBY", 10 | "gender": "male", 11 | "planet_id": "1", 12 | "created": "2014-12-09 13:50:51.644000Z", 13 | "edited": "2014-12-20 21:17:56.891000Z", 14 | "url": "https://swapi.co/api/people/1/", 15 | "id": "1" 16 | }, 17 | { 18 | "name": "C-3PO", 19 | "height": "167", 20 | "mass": "75", 21 | "hair_color": "n/a", 22 | "skin_color": "gold", 23 | "eye_color": "yellow", 24 | "birth_year": "112BBY", 25 | "gender": "n/a", 26 | "planet_id": "1", 27 | "created": "2014-12-10 15:10:51.357000Z", 28 | "edited": "2014-12-20 21:17:50.309000Z", 29 | "url": "https://swapi.co/api/people/2/", 30 | "id": "2" 31 | }, 32 | { 33 | "name": "R2-D2", 34 | "height": "96", 35 | "mass": "32", 36 | "hair_color": "n/a", 37 | "skin_color": "white, blue", 38 | "eye_color": "red", 39 | "birth_year": "33BBY", 40 | "gender": "n/a", 41 | "planet_id": "8", 42 | "created": "2014-12-10 15:11:50.376000Z", 43 | "edited": "2014-12-20 21:17:50.311000Z", 44 | "url": "https://swapi.co/api/people/3/", 45 | "id": "3" 46 | }, 47 | { 48 | "name": "Darth Vader", 49 | "height": "202", 50 | "mass": "136", 51 | "hair_color": "none", 52 | "skin_color": "white", 53 | "eye_color": "yellow", 54 | "birth_year": "41.9BBY", 55 | "gender": "male", 56 | "planet_id": "1", 57 | "created": "2014-12-10 15:18:20.704000Z", 58 | "edited": "2014-12-20 21:17:50.313000Z", 59 | "url": "https://swapi.co/api/people/4/", 60 | "id": "4" 61 | }, 62 | { 63 | "name": "Leia Organa", 64 | "height": "150", 65 | "mass": "49", 66 | "hair_color": "brown", 67 | "skin_color": "light", 68 | "eye_color": "brown", 69 | "birth_year": "19BBY", 70 | "gender": "female", 71 | "planet_id": "2", 72 | "created": "2014-12-10 15:20:09.791000Z", 73 | "edited": "2014-12-20 21:17:50.315000Z", 74 | "url": "https://swapi.co/api/people/5/", 75 | "id": "5" 76 | }, 77 | { 78 | "name": "Owen Lars", 79 | "height": "178", 80 | "mass": "120", 81 | "hair_color": "brown, grey", 82 | "skin_color": "light", 83 | "eye_color": "blue", 84 | "birth_year": "52BBY", 85 | "gender": "male", 86 | "planet_id": "1", 87 | "created": "2014-12-10 15:52:14.024000Z", 88 | "edited": "2014-12-20 21:17:50.317000Z", 89 | "url": "https://swapi.co/api/people/6/", 90 | "id": "6" 91 | }, 92 | { 93 | "name": "Beru Whitesun lars", 94 | "height": "165", 95 | "mass": "75", 96 | "hair_color": "brown", 97 | "skin_color": "light", 98 | "eye_color": "blue", 99 | "birth_year": "47BBY", 100 | "gender": "female", 101 | "planet_id": "1", 102 | "created": "2014-12-10 15:53:41.121000Z", 103 | "edited": "2014-12-20 21:17:50.319000Z", 104 | "url": "https://swapi.co/api/people/7/", 105 | "id": "7" 106 | }, 107 | { 108 | "name": "R5-D4", 109 | "height": "97", 110 | "mass": "32", 111 | "hair_color": "n/a", 112 | "skin_color": "white, red", 113 | "eye_color": "red", 114 | "birth_year": "unknown", 115 | "gender": "n/a", 116 | "planet_id": "1", 117 | "created": "2014-12-10 15:57:50.959000Z", 118 | "edited": "2014-12-20 21:17:50.321000Z", 119 | "url": "https://swapi.co/api/people/8/", 120 | "id": "8" 121 | }, 122 | { 123 | "name": "Biggs Darklighter", 124 | "height": "183", 125 | "mass": "84", 126 | "hair_color": "black", 127 | "skin_color": "light", 128 | "eye_color": "brown", 129 | "birth_year": "24BBY", 130 | "gender": "male", 131 | "planet_id": "1", 132 | "created": "2014-12-10 15:59:50.509000Z", 133 | "edited": "2014-12-20 21:17:50.323000Z", 134 | "url": "https://swapi.co/api/people/9/", 135 | "id": "9" 136 | }, 137 | { 138 | "name": "Obi-Wan Kenobi", 139 | "height": "182", 140 | "mass": "77", 141 | "hair_color": "auburn, white", 142 | "skin_color": "fair", 143 | "eye_color": "blue-gray", 144 | "birth_year": "57BBY", 145 | "gender": "male", 146 | "planet_id": "20", 147 | "created": "2014-12-10 16:16:29.192000Z", 148 | "edited": "2014-12-20 21:17:50.325000Z", 149 | "url": "https://swapi.co/api/people/10/", 150 | "id": "10" 151 | }, 152 | { 153 | "name": "Anakin Skywalker", 154 | "height": "188", 155 | "mass": "84", 156 | "hair_color": "blond", 157 | "skin_color": "fair", 158 | "eye_color": "blue", 159 | "birth_year": "41.9BBY", 160 | "gender": "male", 161 | "planet_id": "1", 162 | "created": "2014-12-10 16:20:44.310000Z", 163 | "edited": "2014-12-20 21:17:50.327000Z", 164 | "url": "https://swapi.co/api/people/11/", 165 | "id": "11" 166 | }, 167 | { 168 | "name": "Wilhuff Tarkin", 169 | "height": "180", 170 | "mass": "unknown", 171 | "hair_color": "auburn, grey", 172 | "skin_color": "fair", 173 | "eye_color": "blue", 174 | "birth_year": "64BBY", 175 | "gender": "male", 176 | "planet_id": "21", 177 | "created": "2014-12-10 16:26:56.138000Z", 178 | "edited": "2014-12-20 21:17:50.330000Z", 179 | "url": "https://swapi.co/api/people/12/", 180 | "id": "12" 181 | }, 182 | { 183 | "name": "Chewbacca", 184 | "height": "228", 185 | "mass": "112", 186 | "hair_color": "brown", 187 | "skin_color": "unknown", 188 | "eye_color": "blue", 189 | "birth_year": "200BBY", 190 | "gender": "male", 191 | "planet_id": "14", 192 | "created": "2014-12-10 16:42:45.066000Z", 193 | "edited": "2014-12-20 21:17:50.332000Z", 194 | "url": "https://swapi.co/api/people/13/", 195 | "id": "13" 196 | }, 197 | { 198 | "name": "Han Solo", 199 | "height": "180", 200 | "mass": "80", 201 | "hair_color": "brown", 202 | "skin_color": "fair", 203 | "eye_color": "brown", 204 | "birth_year": "29BBY", 205 | "gender": "male", 206 | "planet_id": "22", 207 | "created": "2014-12-10 16:49:14.582000Z", 208 | "edited": "2014-12-20 21:17:50.334000Z", 209 | "url": "https://swapi.co/api/people/14/", 210 | "id": "14" 211 | }, 212 | { 213 | "name": "Greedo", 214 | "height": "173", 215 | "mass": "74", 216 | "hair_color": "n/a", 217 | "skin_color": "green", 218 | "eye_color": "black", 219 | "birth_year": "44BBY", 220 | "gender": "male", 221 | "planet_id": "23", 222 | "created": "2014-12-10 17:03:30.334000Z", 223 | "edited": "2014-12-20 21:17:50.336000Z", 224 | "url": "https://swapi.co/api/people/15/", 225 | "id": "15" 226 | }, 227 | { 228 | "name": "Jabba Desilijic Tiure", 229 | "height": "175", 230 | "mass": "1,358", 231 | "hair_color": "n/a", 232 | "skin_color": "green-tan, brown", 233 | "eye_color": "orange", 234 | "birth_year": "600BBY", 235 | "gender": "hermaphrodite", 236 | "planet_id": "24", 237 | "created": "2014-12-10 17:11:31.638000Z", 238 | "edited": "2014-12-20 21:17:50.338000Z", 239 | "url": "https://swapi.co/api/people/16/", 240 | "id": "16" 241 | }, 242 | { 243 | "name": "Wedge Antilles", 244 | "height": "170", 245 | "mass": "77", 246 | "hair_color": "brown", 247 | "skin_color": "fair", 248 | "eye_color": "hazel", 249 | "birth_year": "21BBY", 250 | "gender": "male", 251 | "planet_id": "22", 252 | "created": "2014-12-12 11:08:06.469000Z", 253 | "edited": "2014-12-20 21:17:50.341000Z", 254 | "url": "https://swapi.co/api/people/18/", 255 | "id": "18" 256 | }, 257 | { 258 | "name": "Jek Tono Porkins", 259 | "height": "180", 260 | "mass": "110", 261 | "hair_color": "brown", 262 | "skin_color": "fair", 263 | "eye_color": "blue", 264 | "birth_year": "unknown", 265 | "gender": "male", 266 | "planet_id": "26", 267 | "created": "2014-12-12 11:16:56.569000Z", 268 | "edited": "2014-12-20 21:17:50.343000Z", 269 | "url": "https://swapi.co/api/people/19/", 270 | "id": "19" 271 | }, 272 | { 273 | "name": "Yoda", 274 | "height": "66", 275 | "mass": "17", 276 | "hair_color": "white", 277 | "skin_color": "green", 278 | "eye_color": "brown", 279 | "birth_year": "896BBY", 280 | "gender": "male", 281 | "planet_id": "28", 282 | "created": "2014-12-15 12:26:01.042000Z", 283 | "edited": "2014-12-20 21:17:50.345000Z", 284 | "url": "https://swapi.co/api/people/20/", 285 | "id": "20" 286 | }, 287 | { 288 | "name": "Palpatine", 289 | "height": "170", 290 | "mass": "75", 291 | "hair_color": "grey", 292 | "skin_color": "pale", 293 | "eye_color": "yellow", 294 | "birth_year": "82BBY", 295 | "gender": "male", 296 | "planet_id": "8", 297 | "created": "2014-12-15 12:48:05.971000Z", 298 | "edited": "2014-12-20 21:17:50.347000Z", 299 | "url": "https://swapi.co/api/people/21/", 300 | "id": "21" 301 | }, 302 | { 303 | "name": "Boba Fett", 304 | "height": "183", 305 | "mass": "78.2", 306 | "hair_color": "black", 307 | "skin_color": "fair", 308 | "eye_color": "brown", 309 | "birth_year": "31.5BBY", 310 | "gender": "male", 311 | "planet_id": "10", 312 | "created": "2014-12-15 12:49:32.457000Z", 313 | "edited": "2014-12-20 21:17:50.349000Z", 314 | "url": "https://swapi.co/api/people/22/", 315 | "id": "22" 316 | }, 317 | { 318 | "name": "IG-88", 319 | "height": "200", 320 | "mass": "140", 321 | "hair_color": "none", 322 | "skin_color": "metal", 323 | "eye_color": "red", 324 | "birth_year": "15BBY", 325 | "gender": "none", 326 | "planet_id": "28", 327 | "created": "2014-12-15 12:51:10.076000Z", 328 | "edited": "2014-12-20 21:17:50.351000Z", 329 | "url": "https://swapi.co/api/people/23/", 330 | "id": "23" 331 | }, 332 | { 333 | "name": "Bossk", 334 | "height": "190", 335 | "mass": "113", 336 | "hair_color": "none", 337 | "skin_color": "green", 338 | "eye_color": "red", 339 | "birth_year": "53BBY", 340 | "gender": "male", 341 | "planet_id": "29", 342 | "created": "2014-12-15 12:53:49.297000Z", 343 | "edited": "2014-12-20 21:17:50.355000Z", 344 | "url": "https://swapi.co/api/people/24/", 345 | "id": "24" 346 | }, 347 | { 348 | "name": "Lando Calrissian", 349 | "height": "177", 350 | "mass": "79", 351 | "hair_color": "black", 352 | "skin_color": "dark", 353 | "eye_color": "brown", 354 | "birth_year": "31BBY", 355 | "gender": "male", 356 | "planet_id": "30", 357 | "created": "2014-12-15 12:56:32.683000Z", 358 | "edited": "2014-12-20 21:17:50.357000Z", 359 | "url": "https://swapi.co/api/people/25/", 360 | "id": "25" 361 | }, 362 | { 363 | "name": "Lobot", 364 | "height": "175", 365 | "mass": "79", 366 | "hair_color": "none", 367 | "skin_color": "light", 368 | "eye_color": "blue", 369 | "birth_year": "37BBY", 370 | "gender": "male", 371 | "planet_id": "6", 372 | "created": "2014-12-15 13:01:57.178000Z", 373 | "edited": "2014-12-20 21:17:50.359000Z", 374 | "url": "https://swapi.co/api/people/26/", 375 | "id": "26" 376 | }, 377 | { 378 | "name": "Ackbar", 379 | "height": "180", 380 | "mass": "83", 381 | "hair_color": "none", 382 | "skin_color": "brown mottle", 383 | "eye_color": "orange", 384 | "birth_year": "41BBY", 385 | "gender": "male", 386 | "planet_id": "31", 387 | "created": "2014-12-18 11:07:50.584000Z", 388 | "edited": "2014-12-20 21:17:50.362000Z", 389 | "url": "https://swapi.co/api/people/27/", 390 | "id": "27" 391 | }, 392 | { 393 | "name": "Mon Mothma", 394 | "height": "150", 395 | "mass": "unknown", 396 | "hair_color": "auburn", 397 | "skin_color": "fair", 398 | "eye_color": "blue", 399 | "birth_year": "48BBY", 400 | "gender": "female", 401 | "planet_id": "32", 402 | "created": "2014-12-18 11:12:38.895000Z", 403 | "edited": "2014-12-20 21:17:50.364000Z", 404 | "url": "https://swapi.co/api/people/28/", 405 | "id": "28" 406 | }, 407 | { 408 | "name": "Arvel Crynyd", 409 | "height": "unknown", 410 | "mass": "unknown", 411 | "hair_color": "brown", 412 | "skin_color": "fair", 413 | "eye_color": "brown", 414 | "birth_year": "unknown", 415 | "gender": "male", 416 | "planet_id": "28", 417 | "created": "2014-12-18 11:16:33.020000Z", 418 | "edited": "2014-12-20 21:17:50.367000Z", 419 | "url": "https://swapi.co/api/people/29/", 420 | "id": "29" 421 | }, 422 | { 423 | "name": "Wicket Systri Warrick", 424 | "height": "88", 425 | "mass": "20", 426 | "hair_color": "brown", 427 | "skin_color": "brown", 428 | "eye_color": "brown", 429 | "birth_year": "8BBY", 430 | "gender": "male", 431 | "planet_id": "7", 432 | "created": "2014-12-18 11:21:58.954000Z", 433 | "edited": "2014-12-20 21:17:50.369000Z", 434 | "url": "https://swapi.co/api/people/30/", 435 | "id": "30" 436 | }, 437 | { 438 | "name": "Nien Nunb", 439 | "height": "160", 440 | "mass": "68", 441 | "hair_color": "none", 442 | "skin_color": "grey", 443 | "eye_color": "black", 444 | "birth_year": "unknown", 445 | "gender": "male", 446 | "planet_id": "33", 447 | "created": "2014-12-18 11:26:18.541000Z", 448 | "edited": "2014-12-20 21:17:50.371000Z", 449 | "url": "https://swapi.co/api/people/31/", 450 | "id": "31" 451 | }, 452 | { 453 | "name": "Qui-Gon Jinn", 454 | "height": "193", 455 | "mass": "89", 456 | "hair_color": "brown", 457 | "skin_color": "fair", 458 | "eye_color": "blue", 459 | "birth_year": "92BBY", 460 | "gender": "male", 461 | "planet_id": "28", 462 | "created": "2014-12-19 16:54:53.618000Z", 463 | "edited": "2014-12-20 21:17:50.375000Z", 464 | "url": "https://swapi.co/api/people/32/", 465 | "id": "32" 466 | }, 467 | { 468 | "name": "Nute Gunray", 469 | "height": "191", 470 | "mass": "90", 471 | "hair_color": "none", 472 | "skin_color": "mottled green", 473 | "eye_color": "red", 474 | "birth_year": "unknown", 475 | "gender": "male", 476 | "planet_id": "18", 477 | "created": "2014-12-19 17:05:57.357000Z", 478 | "edited": "2014-12-20 21:17:50.377000Z", 479 | "url": "https://swapi.co/api/people/33/", 480 | "id": "33" 481 | }, 482 | { 483 | "name": "Finis Valorum", 484 | "height": "170", 485 | "mass": "unknown", 486 | "hair_color": "blond", 487 | "skin_color": "fair", 488 | "eye_color": "blue", 489 | "birth_year": "91BBY", 490 | "gender": "male", 491 | "planet_id": "9", 492 | "created": "2014-12-19 17:21:45.915000Z", 493 | "edited": "2014-12-20 21:17:50.379000Z", 494 | "url": "https://swapi.co/api/people/34/", 495 | "id": "34" 496 | }, 497 | { 498 | "name": "Jar Jar Binks", 499 | "height": "196", 500 | "mass": "66", 501 | "hair_color": "none", 502 | "skin_color": "orange", 503 | "eye_color": "orange", 504 | "birth_year": "52BBY", 505 | "gender": "male", 506 | "planet_id": "8", 507 | "created": "2014-12-19 17:29:32.489000Z", 508 | "edited": "2014-12-20 21:17:50.383000Z", 509 | "url": "https://swapi.co/api/people/36/", 510 | "id": "36" 511 | }, 512 | { 513 | "name": "Roos Tarpals", 514 | "height": "224", 515 | "mass": "82", 516 | "hair_color": "none", 517 | "skin_color": "grey", 518 | "eye_color": "orange", 519 | "birth_year": "unknown", 520 | "gender": "male", 521 | "planet_id": "8", 522 | "created": "2014-12-19 17:32:56.741000Z", 523 | "edited": "2014-12-20 21:17:50.385000Z", 524 | "url": "https://swapi.co/api/people/37/", 525 | "id": "37" 526 | }, 527 | { 528 | "name": "Rugor Nass", 529 | "height": "206", 530 | "mass": "unknown", 531 | "hair_color": "none", 532 | "skin_color": "green", 533 | "eye_color": "orange", 534 | "birth_year": "unknown", 535 | "gender": "male", 536 | "planet_id": "8", 537 | "created": "2014-12-19 17:33:38.909000Z", 538 | "edited": "2014-12-20 21:17:50.388000Z", 539 | "url": "https://swapi.co/api/people/38/", 540 | "id": "38" 541 | }, 542 | { 543 | "name": "Ric Olié", 544 | "height": "183", 545 | "mass": "unknown", 546 | "hair_color": "brown", 547 | "skin_color": "fair", 548 | "eye_color": "blue", 549 | "birth_year": "unknown", 550 | "gender": "male", 551 | "planet_id": "8", 552 | "created": "2014-12-19 17:45:01.522000Z", 553 | "edited": "2014-12-20 21:17:50.392000Z", 554 | "url": "https://swapi.co/api/people/39/", 555 | "id": "39" 556 | }, 557 | { 558 | "name": "Watto", 559 | "height": "137", 560 | "mass": "unknown", 561 | "hair_color": "black", 562 | "skin_color": "blue, grey", 563 | "eye_color": "yellow", 564 | "birth_year": "unknown", 565 | "gender": "male", 566 | "planet_id": "34", 567 | "created": "2014-12-19 17:48:54.647000Z", 568 | "edited": "2014-12-20 21:17:50.395000Z", 569 | "url": "https://swapi.co/api/people/40/", 570 | "id": "40" 571 | }, 572 | { 573 | "name": "Sebulba", 574 | "height": "112", 575 | "mass": "40", 576 | "hair_color": "none", 577 | "skin_color": "grey, red", 578 | "eye_color": "orange", 579 | "birth_year": "unknown", 580 | "gender": "male", 581 | "planet_id": "35", 582 | "created": "2014-12-19 17:53:02.586000Z", 583 | "edited": "2014-12-20 21:17:50.397000Z", 584 | "url": "https://swapi.co/api/people/41/", 585 | "id": "41" 586 | }, 587 | { 588 | "name": "Quarsh Panaka", 589 | "height": "183", 590 | "mass": "unknown", 591 | "hair_color": "black", 592 | "skin_color": "dark", 593 | "eye_color": "brown", 594 | "birth_year": "62BBY", 595 | "gender": "male", 596 | "planet_id": "8", 597 | "created": "2014-12-19 17:55:43.348000Z", 598 | "edited": "2014-12-20 21:17:50.399000Z", 599 | "url": "https://swapi.co/api/people/42/", 600 | "id": "42" 601 | }, 602 | { 603 | "name": "Shmi Skywalker", 604 | "height": "163", 605 | "mass": "unknown", 606 | "hair_color": "black", 607 | "skin_color": "fair", 608 | "eye_color": "brown", 609 | "birth_year": "72BBY", 610 | "gender": "female", 611 | "planet_id": "1", 612 | "created": "2014-12-19 17:57:41.191000Z", 613 | "edited": "2014-12-20 21:17:50.401000Z", 614 | "url": "https://swapi.co/api/people/43/", 615 | "id": "43" 616 | }, 617 | { 618 | "name": "Darth Maul", 619 | "height": "175", 620 | "mass": "80", 621 | "hair_color": "none", 622 | "skin_color": "red", 623 | "eye_color": "yellow", 624 | "birth_year": "54BBY", 625 | "gender": "male", 626 | "planet_id": "36", 627 | "created": "2014-12-19 18:00:41.929000Z", 628 | "edited": "2014-12-20 21:17:50.403000Z", 629 | "url": "https://swapi.co/api/people/44/", 630 | "id": "44" 631 | }, 632 | { 633 | "name": "Bib Fortuna", 634 | "height": "180", 635 | "mass": "unknown", 636 | "hair_color": "none", 637 | "skin_color": "pale", 638 | "eye_color": "pink", 639 | "birth_year": "unknown", 640 | "gender": "male", 641 | "planet_id": "37", 642 | "created": "2014-12-20 09:47:02.512000Z", 643 | "edited": "2014-12-20 21:17:50.407000Z", 644 | "url": "https://swapi.co/api/people/45/", 645 | "id": "45" 646 | }, 647 | { 648 | "name": "Ayla Secura", 649 | "height": "178", 650 | "mass": "55", 651 | "hair_color": "none", 652 | "skin_color": "blue", 653 | "eye_color": "hazel", 654 | "birth_year": "48BBY", 655 | "gender": "female", 656 | "planet_id": "37", 657 | "created": "2014-12-20 09:48:01.172000Z", 658 | "edited": "2014-12-20 21:17:50.409000Z", 659 | "url": "https://swapi.co/api/people/46/", 660 | "id": "46" 661 | }, 662 | { 663 | "name": "Dud Bolt", 664 | "height": "94", 665 | "mass": "45", 666 | "hair_color": "none", 667 | "skin_color": "blue, grey", 668 | "eye_color": "yellow", 669 | "birth_year": "unknown", 670 | "gender": "male", 671 | "planet_id": "39", 672 | "created": "2014-12-20 09:57:31.858000Z", 673 | "edited": "2014-12-20 21:17:50.414000Z", 674 | "url": "https://swapi.co/api/people/48/", 675 | "id": "48" 676 | }, 677 | { 678 | "name": "Gasgano", 679 | "height": "122", 680 | "mass": "unknown", 681 | "hair_color": "none", 682 | "skin_color": "white, blue", 683 | "eye_color": "black", 684 | "birth_year": "unknown", 685 | "gender": "male", 686 | "planet_id": "40", 687 | "created": "2014-12-20 10:02:12.223000Z", 688 | "edited": "2014-12-20 21:17:50.416000Z", 689 | "url": "https://swapi.co/api/people/49/", 690 | "id": "49" 691 | }, 692 | { 693 | "name": "Ben Quadinaros", 694 | "height": "163", 695 | "mass": "65", 696 | "hair_color": "none", 697 | "skin_color": "grey, green, yellow", 698 | "eye_color": "orange", 699 | "birth_year": "unknown", 700 | "gender": "male", 701 | "planet_id": "41", 702 | "created": "2014-12-20 10:08:33.777000Z", 703 | "edited": "2014-12-20 21:17:50.417000Z", 704 | "url": "https://swapi.co/api/people/50/", 705 | "id": "50" 706 | }, 707 | { 708 | "name": "Mace Windu", 709 | "height": "188", 710 | "mass": "84", 711 | "hair_color": "none", 712 | "skin_color": "dark", 713 | "eye_color": "brown", 714 | "birth_year": "72BBY", 715 | "gender": "male", 716 | "planet_id": "42", 717 | "created": "2014-12-20 10:12:30.846000Z", 718 | "edited": "2014-12-20 21:17:50.420000Z", 719 | "url": "https://swapi.co/api/people/51/", 720 | "id": "51" 721 | }, 722 | { 723 | "name": "Ki-Adi-Mundi", 724 | "height": "198", 725 | "mass": "82", 726 | "hair_color": "white", 727 | "skin_color": "pale", 728 | "eye_color": "yellow", 729 | "birth_year": "92BBY", 730 | "gender": "male", 731 | "planet_id": "43", 732 | "created": "2014-12-20 10:15:32.293000Z", 733 | "edited": "2014-12-20 21:17:50.422000Z", 734 | "url": "https://swapi.co/api/people/52/", 735 | "id": "52" 736 | }, 737 | { 738 | "name": "Kit Fisto", 739 | "height": "196", 740 | "mass": "87", 741 | "hair_color": "none", 742 | "skin_color": "green", 743 | "eye_color": "black", 744 | "birth_year": "unknown", 745 | "gender": "male", 746 | "planet_id": "44", 747 | "created": "2014-12-20 10:18:57.202000Z", 748 | "edited": "2014-12-20 21:17:50.424000Z", 749 | "url": "https://swapi.co/api/people/53/", 750 | "id": "53" 751 | }, 752 | { 753 | "name": "Eeth Koth", 754 | "height": "171", 755 | "mass": "unknown", 756 | "hair_color": "black", 757 | "skin_color": "brown", 758 | "eye_color": "brown", 759 | "birth_year": "unknown", 760 | "gender": "male", 761 | "planet_id": "45", 762 | "created": "2014-12-20 10:26:47.902000Z", 763 | "edited": "2014-12-20 21:17:50.427000Z", 764 | "url": "https://swapi.co/api/people/54/", 765 | "id": "54" 766 | }, 767 | { 768 | "name": "Adi Gallia", 769 | "height": "184", 770 | "mass": "50", 771 | "hair_color": "none", 772 | "skin_color": "dark", 773 | "eye_color": "blue", 774 | "birth_year": "unknown", 775 | "gender": "female", 776 | "planet_id": "9", 777 | "created": "2014-12-20 10:29:11.661000Z", 778 | "edited": "2014-12-20 21:17:50.432000Z", 779 | "url": "https://swapi.co/api/people/55/", 780 | "id": "55" 781 | }, 782 | { 783 | "name": "Saesee Tiin", 784 | "height": "188", 785 | "mass": "unknown", 786 | "hair_color": "none", 787 | "skin_color": "pale", 788 | "eye_color": "orange", 789 | "birth_year": "unknown", 790 | "gender": "male", 791 | "planet_id": "47", 792 | "created": "2014-12-20 10:32:11.669000Z", 793 | "edited": "2014-12-20 21:17:50.434000Z", 794 | "url": "https://swapi.co/api/people/56/", 795 | "id": "56" 796 | }, 797 | { 798 | "name": "Yarael Poof", 799 | "height": "264", 800 | "mass": "unknown", 801 | "hair_color": "none", 802 | "skin_color": "white", 803 | "eye_color": "yellow", 804 | "birth_year": "unknown", 805 | "gender": "male", 806 | "planet_id": "48", 807 | "created": "2014-12-20 10:34:48.725000Z", 808 | "edited": "2014-12-20 21:17:50.437000Z", 809 | "url": "https://swapi.co/api/people/57/", 810 | "id": "57" 811 | }, 812 | { 813 | "name": "Plo Koon", 814 | "height": "188", 815 | "mass": "80", 816 | "hair_color": "none", 817 | "skin_color": "orange", 818 | "eye_color": "black", 819 | "birth_year": "22BBY", 820 | "gender": "male", 821 | "planet_id": "49", 822 | "created": "2014-12-20 10:49:19.859000Z", 823 | "edited": "2014-12-20 21:17:50.439000Z", 824 | "url": "https://swapi.co/api/people/58/", 825 | "id": "58" 826 | }, 827 | { 828 | "name": "Mas Amedda", 829 | "height": "196", 830 | "mass": "unknown", 831 | "hair_color": "none", 832 | "skin_color": "blue", 833 | "eye_color": "blue", 834 | "birth_year": "unknown", 835 | "gender": "male", 836 | "planet_id": "50", 837 | "created": "2014-12-20 10:53:26.457000Z", 838 | "edited": "2014-12-20 21:17:50.442000Z", 839 | "url": "https://swapi.co/api/people/59/", 840 | "id": "59" 841 | }, 842 | { 843 | "name": "Gregar Typho", 844 | "height": "185", 845 | "mass": "85", 846 | "hair_color": "black", 847 | "skin_color": "dark", 848 | "eye_color": "brown", 849 | "birth_year": "unknown", 850 | "gender": "male", 851 | "planet_id": "8", 852 | "created": "2014-12-20 11:10:10.381000Z", 853 | "edited": "2014-12-20 21:17:50.445000Z", 854 | "url": "https://swapi.co/api/people/60/", 855 | "id": "60" 856 | }, 857 | { 858 | "name": "Cordé", 859 | "height": "157", 860 | "mass": "unknown", 861 | "hair_color": "brown", 862 | "skin_color": "light", 863 | "eye_color": "brown", 864 | "birth_year": "unknown", 865 | "gender": "female", 866 | "planet_id": "8", 867 | "created": "2014-12-20 11:11:39.630000Z", 868 | "edited": "2014-12-20 21:17:50.449000Z", 869 | "url": "https://swapi.co/api/people/61/", 870 | "id": "61" 871 | }, 872 | { 873 | "name": "Cliegg Lars", 874 | "height": "183", 875 | "mass": "unknown", 876 | "hair_color": "brown", 877 | "skin_color": "fair", 878 | "eye_color": "blue", 879 | "birth_year": "82BBY", 880 | "gender": "male", 881 | "planet_id": "1", 882 | "created": "2014-12-20 15:59:03.958000Z", 883 | "edited": "2014-12-20 21:17:50.451000Z", 884 | "url": "https://swapi.co/api/people/62/", 885 | "id": "62" 886 | }, 887 | { 888 | "name": "Poggle the Lesser", 889 | "height": "183", 890 | "mass": "80", 891 | "hair_color": "none", 892 | "skin_color": "green", 893 | "eye_color": "yellow", 894 | "birth_year": "unknown", 895 | "gender": "male", 896 | "planet_id": "11", 897 | "created": "2014-12-20 16:40:43.977000Z", 898 | "edited": "2014-12-20 21:17:50.453000Z", 899 | "url": "https://swapi.co/api/people/63/", 900 | "id": "63" 901 | }, 902 | { 903 | "name": "Luminara Unduli", 904 | "height": "170", 905 | "mass": "56.2", 906 | "hair_color": "black", 907 | "skin_color": "yellow", 908 | "eye_color": "blue", 909 | "birth_year": "58BBY", 910 | "gender": "female", 911 | "planet_id": "51", 912 | "created": "2014-12-20 16:45:53.668000Z", 913 | "edited": "2014-12-20 21:17:50.455000Z", 914 | "url": "https://swapi.co/api/people/64/", 915 | "id": "64" 916 | }, 917 | { 918 | "name": "Barriss Offee", 919 | "height": "166", 920 | "mass": "50", 921 | "hair_color": "black", 922 | "skin_color": "yellow", 923 | "eye_color": "blue", 924 | "birth_year": "40BBY", 925 | "gender": "female", 926 | "planet_id": "51", 927 | "created": "2014-12-20 16:46:40.440000Z", 928 | "edited": "2014-12-20 21:17:50.457000Z", 929 | "url": "https://swapi.co/api/people/65/", 930 | "id": "65" 931 | }, 932 | { 933 | "name": "Dormé", 934 | "height": "165", 935 | "mass": "unknown", 936 | "hair_color": "brown", 937 | "skin_color": "light", 938 | "eye_color": "brown", 939 | "birth_year": "unknown", 940 | "gender": "female", 941 | "planet_id": "8", 942 | "created": "2014-12-20 16:49:14.640000Z", 943 | "edited": "2014-12-20 21:17:50.460000Z", 944 | "url": "https://swapi.co/api/people/66/", 945 | "id": "66" 946 | }, 947 | { 948 | "name": "Dooku", 949 | "height": "193", 950 | "mass": "80", 951 | "hair_color": "white", 952 | "skin_color": "fair", 953 | "eye_color": "brown", 954 | "birth_year": "102BBY", 955 | "gender": "male", 956 | "planet_id": "52", 957 | "created": "2014-12-20 16:52:14.726000Z", 958 | "edited": "2014-12-20 21:17:50.462000Z", 959 | "url": "https://swapi.co/api/people/67/", 960 | "id": "67" 961 | }, 962 | { 963 | "name": "Bail Prestor Organa", 964 | "height": "191", 965 | "mass": "unknown", 966 | "hair_color": "black", 967 | "skin_color": "tan", 968 | "eye_color": "brown", 969 | "birth_year": "67BBY", 970 | "gender": "male", 971 | "planet_id": "2", 972 | "created": "2014-12-20 16:53:08.575000Z", 973 | "edited": "2014-12-20 21:17:50.463000Z", 974 | "url": "https://swapi.co/api/people/68/", 975 | "id": "68" 976 | }, 977 | { 978 | "name": "Jango Fett", 979 | "height": "183", 980 | "mass": "79", 981 | "hair_color": "black", 982 | "skin_color": "tan", 983 | "eye_color": "brown", 984 | "birth_year": "66BBY", 985 | "gender": "male", 986 | "planet_id": "53", 987 | "created": "2014-12-20 16:54:41.620000Z", 988 | "edited": "2014-12-20 21:17:50.465000Z", 989 | "url": "https://swapi.co/api/people/69/", 990 | "id": "69" 991 | }, 992 | { 993 | "name": "Zam Wesell", 994 | "height": "168", 995 | "mass": "55", 996 | "hair_color": "blonde", 997 | "skin_color": "fair, green, yellow", 998 | "eye_color": "yellow", 999 | "birth_year": "unknown", 1000 | "gender": "female", 1001 | "planet_id": "54", 1002 | "created": "2014-12-20 16:57:44.471000Z", 1003 | "edited": "2014-12-20 21:17:50.468000Z", 1004 | "url": "https://swapi.co/api/people/70/", 1005 | "id": "70" 1006 | }, 1007 | { 1008 | "name": "Dexter Jettster", 1009 | "height": "198", 1010 | "mass": "102", 1011 | "hair_color": "none", 1012 | "skin_color": "brown", 1013 | "eye_color": "yellow", 1014 | "birth_year": "unknown", 1015 | "gender": "male", 1016 | "planet_id": "55", 1017 | "created": "2014-12-20 17:28:27.248000Z", 1018 | "edited": "2014-12-20 21:17:50.470000Z", 1019 | "url": "https://swapi.co/api/people/71/", 1020 | "id": "71" 1021 | }, 1022 | { 1023 | "name": "Lama Su", 1024 | "height": "229", 1025 | "mass": "88", 1026 | "hair_color": "none", 1027 | "skin_color": "grey", 1028 | "eye_color": "black", 1029 | "birth_year": "unknown", 1030 | "gender": "male", 1031 | "planet_id": "10", 1032 | "created": "2014-12-20 17:30:50.416000Z", 1033 | "edited": "2014-12-20 21:17:50.473000Z", 1034 | "url": "https://swapi.co/api/people/72/", 1035 | "id": "72" 1036 | }, 1037 | { 1038 | "name": "Taun We", 1039 | "height": "213", 1040 | "mass": "unknown", 1041 | "hair_color": "none", 1042 | "skin_color": "grey", 1043 | "eye_color": "black", 1044 | "birth_year": "unknown", 1045 | "gender": "female", 1046 | "planet_id": "10", 1047 | "created": "2014-12-20 17:31:21.195000Z", 1048 | "edited": "2014-12-20 21:17:50.474000Z", 1049 | "url": "https://swapi.co/api/people/73/", 1050 | "id": "73" 1051 | }, 1052 | { 1053 | "name": "Jocasta Nu", 1054 | "height": "167", 1055 | "mass": "unknown", 1056 | "hair_color": "white", 1057 | "skin_color": "fair", 1058 | "eye_color": "blue", 1059 | "birth_year": "unknown", 1060 | "gender": "female", 1061 | "planet_id": "9", 1062 | "created": "2014-12-20 17:32:51.996000Z", 1063 | "edited": "2014-12-20 21:17:50.476000Z", 1064 | "url": "https://swapi.co/api/people/74/", 1065 | "id": "74" 1066 | }, 1067 | { 1068 | "name": "Ratts Tyerell", 1069 | "height": "79", 1070 | "mass": "15", 1071 | "hair_color": "none", 1072 | "skin_color": "grey, blue", 1073 | "eye_color": "unknown", 1074 | "birth_year": "unknown", 1075 | "gender": "male", 1076 | "planet_id": "38", 1077 | "created": "2014-12-20 09:53:15.086000Z", 1078 | "edited": "2016-06-30 12:52:19.604868Z", 1079 | "url": "https://swapi.co/api/people/47/", 1080 | "id": "47" 1081 | }, 1082 | { 1083 | "name": "R4-P17", 1084 | "height": "96", 1085 | "mass": "unknown", 1086 | "hair_color": "none", 1087 | "skin_color": "silver, red", 1088 | "eye_color": "red, blue", 1089 | "birth_year": "unknown", 1090 | "gender": "female", 1091 | "planet_id": "28", 1092 | "created": "2014-12-20 17:43:36.409000Z", 1093 | "edited": "2014-12-20 21:17:50.478000Z", 1094 | "url": "https://swapi.co/api/people/75/", 1095 | "id": "75" 1096 | }, 1097 | { 1098 | "name": "Wat Tambor", 1099 | "height": "193", 1100 | "mass": "48", 1101 | "hair_color": "none", 1102 | "skin_color": "green, grey", 1103 | "eye_color": "unknown", 1104 | "birth_year": "unknown", 1105 | "gender": "male", 1106 | "planet_id": "56", 1107 | "created": "2014-12-20 17:53:52.607000Z", 1108 | "edited": "2014-12-20 21:17:50.481000Z", 1109 | "url": "https://swapi.co/api/people/76/", 1110 | "id": "76" 1111 | }, 1112 | { 1113 | "name": "San Hill", 1114 | "height": "191", 1115 | "mass": "unknown", 1116 | "hair_color": "none", 1117 | "skin_color": "grey", 1118 | "eye_color": "gold", 1119 | "birth_year": "unknown", 1120 | "gender": "male", 1121 | "planet_id": "57", 1122 | "created": "2014-12-20 17:58:17.049000Z", 1123 | "edited": "2014-12-20 21:17:50.484000Z", 1124 | "url": "https://swapi.co/api/people/77/", 1125 | "id": "77" 1126 | }, 1127 | { 1128 | "name": "Shaak Ti", 1129 | "height": "178", 1130 | "mass": "57", 1131 | "hair_color": "none", 1132 | "skin_color": "red, blue, white", 1133 | "eye_color": "black", 1134 | "birth_year": "unknown", 1135 | "gender": "female", 1136 | "planet_id": "58", 1137 | "created": "2014-12-20 18:44:01.103000Z", 1138 | "edited": "2014-12-20 21:17:50.486000Z", 1139 | "url": "https://swapi.co/api/people/78/", 1140 | "id": "78" 1141 | }, 1142 | { 1143 | "name": "Grievous", 1144 | "height": "216", 1145 | "mass": "159", 1146 | "hair_color": "none", 1147 | "skin_color": "brown, white", 1148 | "eye_color": "green, yellow", 1149 | "birth_year": "unknown", 1150 | "gender": "male", 1151 | "planet_id": "59", 1152 | "created": "2014-12-20 19:43:53.348000Z", 1153 | "edited": "2014-12-20 21:17:50.488000Z", 1154 | "url": "https://swapi.co/api/people/79/", 1155 | "id": "79" 1156 | }, 1157 | { 1158 | "name": "Tarfful", 1159 | "height": "234", 1160 | "mass": "136", 1161 | "hair_color": "brown", 1162 | "skin_color": "brown", 1163 | "eye_color": "blue", 1164 | "birth_year": "unknown", 1165 | "gender": "male", 1166 | "planet_id": "14", 1167 | "created": "2014-12-20 19:46:34.209000Z", 1168 | "edited": "2014-12-20 21:17:50.491000Z", 1169 | "url": "https://swapi.co/api/people/80/", 1170 | "id": "80" 1171 | }, 1172 | { 1173 | "name": "Raymus Antilles", 1174 | "height": "188", 1175 | "mass": "79", 1176 | "hair_color": "brown", 1177 | "skin_color": "light", 1178 | "eye_color": "brown", 1179 | "birth_year": "unknown", 1180 | "gender": "male", 1181 | "planet_id": "2", 1182 | "created": "2014-12-20 19:49:35.583000Z", 1183 | "edited": "2014-12-20 21:17:50.493000Z", 1184 | "url": "https://swapi.co/api/people/81/", 1185 | "id": "81" 1186 | }, 1187 | { 1188 | "name": "Sly Moore", 1189 | "height": "178", 1190 | "mass": "48", 1191 | "hair_color": "none", 1192 | "skin_color": "pale", 1193 | "eye_color": "white", 1194 | "birth_year": "unknown", 1195 | "gender": "female", 1196 | "planet_id": "60", 1197 | "created": "2014-12-20 20:18:37.619000Z", 1198 | "edited": "2014-12-20 21:17:50.496000Z", 1199 | "url": "https://swapi.co/api/people/82/", 1200 | "id": "82" 1201 | }, 1202 | { 1203 | "name": "Tion Medon", 1204 | "height": "206", 1205 | "mass": "80", 1206 | "hair_color": "none", 1207 | "skin_color": "grey", 1208 | "eye_color": "black", 1209 | "birth_year": "unknown", 1210 | "gender": "male", 1211 | "planet_id": "12", 1212 | "created": "2014-12-20 20:35:04.260000Z", 1213 | "edited": "2014-12-20 21:17:50.498000Z", 1214 | "url": "https://swapi.co/api/people/83/", 1215 | "id": "83" 1216 | }, 1217 | { 1218 | "name": "Finn", 1219 | "height": "unknown", 1220 | "mass": "unknown", 1221 | "hair_color": "black", 1222 | "skin_color": "dark", 1223 | "eye_color": "dark", 1224 | "birth_year": "unknown", 1225 | "gender": "male", 1226 | "planet_id": "28", 1227 | "created": "2015-04-17 06:52:40.793621Z", 1228 | "edited": "2015-04-17 06:52:40.793674Z", 1229 | "url": "https://swapi.co/api/people/84/", 1230 | "id": "84" 1231 | }, 1232 | { 1233 | "name": "Rey", 1234 | "height": "unknown", 1235 | "mass": "unknown", 1236 | "hair_color": "brown", 1237 | "skin_color": "light", 1238 | "eye_color": "hazel", 1239 | "birth_year": "unknown", 1240 | "gender": "female", 1241 | "planet_id": "28", 1242 | "created": "2015-04-17 06:54:01.495077Z", 1243 | "edited": "2015-04-17 06:54:01.495128Z", 1244 | "url": "https://swapi.co/api/people/85/", 1245 | "id": "85" 1246 | }, 1247 | { 1248 | "name": "Poe Dameron", 1249 | "height": "unknown", 1250 | "mass": "unknown", 1251 | "hair_color": "brown", 1252 | "skin_color": "light", 1253 | "eye_color": "brown", 1254 | "birth_year": "unknown", 1255 | "gender": "male", 1256 | "planet_id": "28", 1257 | "created": "2015-04-17 06:55:21.622786Z", 1258 | "edited": "2015-04-17 06:55:21.622835Z", 1259 | "url": "https://swapi.co/api/people/86/", 1260 | "id": "86" 1261 | }, 1262 | { 1263 | "name": "BB8", 1264 | "height": "unknown", 1265 | "mass": "unknown", 1266 | "hair_color": "none", 1267 | "skin_color": "none", 1268 | "eye_color": "black", 1269 | "birth_year": "unknown", 1270 | "gender": "none", 1271 | "planet_id": "28", 1272 | "created": "2015-04-17 06:57:38.061346Z", 1273 | "edited": "2015-04-17 06:57:38.061453Z", 1274 | "url": "https://swapi.co/api/people/87/", 1275 | "id": "87" 1276 | }, 1277 | { 1278 | "name": "Captain Phasma", 1279 | "height": "unknown", 1280 | "mass": "unknown", 1281 | "hair_color": "unknown", 1282 | "skin_color": "unknown", 1283 | "eye_color": "unknown", 1284 | "birth_year": "unknown", 1285 | "gender": "female", 1286 | "planet_id": "28", 1287 | "created": "2015-10-13 10:35:39.229823Z", 1288 | "edited": "2015-10-13 10:35:39.229894Z", 1289 | "url": "https://swapi.co/api/people/88/", 1290 | "id": "88" 1291 | }, 1292 | { 1293 | "name": "Padmé Amidala", 1294 | "height": "165", 1295 | "mass": "45", 1296 | "hair_color": "brown", 1297 | "skin_color": "light", 1298 | "eye_color": "brown", 1299 | "birth_year": "46BBY", 1300 | "gender": "female", 1301 | "planet_id": "8", 1302 | "created": "2014-12-19 17:28:26.926000Z", 1303 | "edited": "2016-04-20 17:06:31.502555Z", 1304 | "url": "https://swapi.co/api/people/35/", 1305 | "id": "35" 1306 | } 1307 | ] 1308 | --------------------------------------------------------------------------------