{"id":18620525,"url":"https://github.com/simonsobs/nextline-graphql","last_synced_at":"2025-10-25T04:43:10.095Z","repository":{"id":37530923,"uuid":"308675559","full_name":"simonsobs/nextline-graphql","owner":"simonsobs","description":"The plugin-based framework of the backend API server of Nextline.","archived":false,"fork":false,"pushed_at":"2025-04-11T21:13:35.000Z","size":831,"stargazers_count":3,"open_issues_count":5,"forks_count":0,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-04-11T21:39:20.539Z","etag":null,"topics":["nextline"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/simonsobs.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2020-10-30T15:48:02.000Z","updated_at":"2025-04-11T20:56:17.000Z","dependencies_parsed_at":"2023-02-19T11:01:28.668Z","dependency_job_id":"e2ba8715-3c1d-4bab-8aba-04416732292f","html_url":"https://github.com/simonsobs/nextline-graphql","commit_stats":null,"previous_names":[],"tags_count":70,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/simonsobs%2Fnextline-graphql","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/simonsobs%2Fnextline-graphql/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/simonsobs%2Fnextline-graphql/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/simonsobs%2Fnextline-graphql/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/simonsobs","download_url":"https://codeload.github.com/simonsobs/nextline-graphql/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":249678881,"owners_count":21309839,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["nextline"],"created_at":"2024-11-07T04:06:39.522Z","updated_at":"2025-10-25T04:43:10.075Z","avatar_url":"https://github.com/simonsobs.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# nextline-graphql\n\n_The plugin-based framework of a Python API server._\n\n---\n\n[![PyPI - Version](https://img.shields.io/pypi/v/nextline-graphql.svg)](https://pypi.org/project/nextline-graphql)\n[![PyPI - Python Version](https://img.shields.io/pypi/pyversions/nextline-graphql.svg)](https://pypi.org/project/nextline-graphql)\n\n[![Test Status](https://github.com/simonsobs/nextline-graphql/actions/workflows/unit-test.yml/badge.svg)](https://github.com/simonsobs/nextline-graphql/actions/workflows/unit-test.yml)\n[![Test Status](https://github.com/simonsobs/nextline-graphql/actions/workflows/unit-test-dev.yml/badge.svg)](https://github.com/simonsobs/nextline-graphql/actions/workflows/unit-test.yml)\n[![Test Status](https://github.com/simonsobs/nextline-graphql/actions/workflows/type-check.yml/badge.svg)](https://github.com/simonsobs/nextline-graphql/actions/workflows/type-check.yml)\n[![codecov](https://codecov.io/gh/simonsobs/nextline-graphql/branch/main/graph/badge.svg)](https://codecov.io/gh/simonsobs/nextline-graphql)\n\n---\n\n**Table of Contents**\n\n- [Introduction](#introduction)\n- [Citation](#citation)\n- [Packages](#packages)\n  - [Backend API server (Python)](#backend-api-server-python)\n    - [Core package](#core-package)\n    - [Plugin system](#plugin-system)\n    - [Plugins](#plugins)\n    - [Utility](#utility)\n  - [Frontend web app (TypeScript)](#frontend-web-app-typescript)\n- [How to run the Nextline backend API server](#how-to-run-the-nextline-backend-api-server)\n  - [As a Docker container](#as-a-docker-container)\n  - [In a virtual environment](#in-a-virtual-environment)\n- [Configuration](#configuration)\n  - [CORS](#cors)\n  - [Logging](#logging)\n  - [`graphql` plugin](#graphql-plugin)\n  - [`ctrl` plugin](#ctrl-plugin)\n- [Check out code for development](#check-out-code-for-development)\n\n## Introduction\n\nThis package provides the framework for a plugin-based Python API server.\nPlugins can implement endpoints and services.\n\nThis framework was originally developed as part of _Nextline_, a DAQ sequencer\nof the [Observatory Control System (OCS)](https://github.com/simonsobs/ocs/),\nwhich allows line-by-line execution of concurrent Python scripts, which control\ntelescopes, by multiple users simultaneously from web browsers.\n\n## Citation\n\nPlease use the following DOI for [the core\npackage](https://github.com/simonsobs/nextline) to cite Nextline in general\nunless you need to refer to a specific package.\n\n[![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.11451619.svg)](https://doi.org/10.5281/zenodo.11451619)\n\n## Packages\n\nNextline consists of multiple packages. This package, _nextline-graphql_,\nprovides the framework for the backend API server.\n\n| Package                                                                                   | Language   | Release                                                                                                                  | Build                                                                                                                                                                                          | Coverage                                                                                                                                           |\n| :---------------------------------------------------------------------------------------- | ---------- | :----------------------------------------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------- |\n| [**nextline**](https://github.com/simonsobs/nextline)                                     | Python     | [![PyPI - Version](https://img.shields.io/pypi/v/nextline.svg)](https://pypi.org/project/nextline)                       | [![Test Status](https://github.com/simonsobs/nextline/actions/workflows/unit-test.yml/badge.svg)](https://github.com/simonsobs/nextline/actions/workflows/unit-test.yml)                       |                                                                                                                                                    |\n| [**apluggy**](https://github.com/simonsobs/apluggy)                                       | Python     | [![PyPI - Version](https://img.shields.io/pypi/v/apluggy.svg)](https://pypi.org/project/apluggy)                         | [![Test Status](https://github.com/simonsobs/apluggy/actions/workflows/unit-test.yml/badge.svg)](https://github.com/simonsobs/apluggy/actions/workflows/unit-test.yml)                         | [![codecov](https://codecov.io/gh/simonsobs/apluggy/branch/main/graph/badge.svg)](https://codecov.io/gh/simonsobs/apluggy)                         |\n| [**nextline\u0026#x2011;graphql**](https://github.com/simonsobs/nextline-graphql)              | Python     | [![PyPI - Version](https://img.shields.io/pypi/v/nextline-graphql.svg)](https://pypi.org/project/nextline-graphql)       | [![Test Status](https://github.com/simonsobs/nextline-graphql/actions/workflows/unit-test.yml/badge.svg)](https://github.com/simonsobs/nextline-graphql/actions/workflows/unit-test.yml)       | [![codecov](https://codecov.io/gh/simonsobs/nextline-graphql/branch/main/graph/badge.svg)](https://codecov.io/gh/simonsobs/nextline-graphql)       |\n| [**nextline\u0026#x2011;rdb**](https://github.com/simonsobs/nextline-rdb)                      | Python     | [![PyPI - Version](https://img.shields.io/pypi/v/nextline-rdb.svg)](https://pypi.org/project/nextline-rdb)               | [![Test Status](https://github.com/simonsobs/nextline-rdb/actions/workflows/unit-test.yml/badge.svg)](https://github.com/simonsobs/nextline-rdb/actions/workflows/unit-test.yml)               | [![codecov](https://codecov.io/gh/simonsobs/nextline-rdb/branch/main/graph/badge.svg)](https://codecov.io/gh/simonsobs/nextline-rdb)               |\n| [**nextline\u0026#x2011;schedule**](https://github.com/simonsobs/nextline-schedule)            | Python     | [![PyPI - Version](https://img.shields.io/pypi/v/nextline-schedule.svg)](https://pypi.org/project/nextline-schedule)     | [![Test Status](https://github.com/simonsobs/nextline-schedule/actions/workflows/unit-test.yml/badge.svg)](https://github.com/simonsobs/nextline-schedule/actions/workflows/unit-test.yml)     | [![codecov](https://codecov.io/gh/simonsobs/nextline-schedule/branch/main/graph/badge.svg)](https://codecov.io/gh/simonsobs/nextline-schedule)     |\n| [**nextline\u0026#x2011;alert**](https://github.com/simonsobs/nextline-alert)                  | Python     | [![PyPI - Version](https://img.shields.io/pypi/v/nextline-alert.svg)](https://pypi.org/project/nextline-alert)           | [![Test Status](https://github.com/simonsobs/nextline-alert/actions/workflows/unit-test.yml/badge.svg)](https://github.com/simonsobs/nextline-alert/actions/workflows/unit-test.yml)           | [![codecov](https://codecov.io/gh/simonsobs/nextline-alert/branch/main/graph/badge.svg)](https://codecov.io/gh/simonsobs/nextline-alert)           |\n| [**nextline\u0026#x2011;test\u0026#x2011;utils**](https://github.com/simonsobs/nextline-test-utils) | Python     | [![PyPI - Version](https://img.shields.io/pypi/v/nextline-test-utils.svg)](https://pypi.org/project/nextline-test-utils) | [![Test Status](https://github.com/simonsobs/nextline-test-utils/actions/workflows/unit-test.yml/badge.svg)](https://github.com/simonsobs/nextline-test-utils/actions/workflows/unit-test.yml) | [![codecov](https://codecov.io/gh/simonsobs/nextline-test-utils/branch/main/graph/badge.svg)](https://codecov.io/gh/simonsobs/nextline-test-utils) |\n| [**nextline\u0026#x2011;web**](https://github.com/simonsobs/nextline-web)                      | TypeScript | [![npm](https://img.shields.io/npm/v/nextline-web)](https://www.npmjs.com/package/nextline-web)                          | [![Unit tests](https://github.com/simonsobs/nextline-web/actions/workflows/unit-test.yml/badge.svg)](https://github.com/simonsobs/nextline-web/actions/workflows/unit-test.yml)                |                                                                                                                                                    |\n\n### Backend API server (Python)\n\n#### Core package\n\n- [**nextline:**](https://github.com/simonsobs/nextline) The core functionality\n  of Nextline. It controls the execution of the Python scripts. It is used by\n  the plugin _ctrl_.\n\n#### Plugin system\n\nThe plugin system of _nextline-graphql_ is _apluggy_.\n\n- [**apluggy:**](https://github.com/simonsobs/apluggy) A wrapper of\n  [pluggy](https://pluggy.readthedocs.io/) to support asyncio and context\n  managers.\n\n#### Plugins\n\n##### Internal plugins\n\nThese plugins are included in this package.\n\n- [**graphql:**](./nextlinegraphql/plugins/graphql/) The entry point of the\n  GraphQL API, implemented with [strawberry-graphql](https://strawberry.rocks/).\n- [**ctrl:**](./nextlinegraphql/plugins/ctrl/) The core plugin that controls\n  the execution of the Python scripts. It uses the package\n  [_nextline_](https://github.com/simonsobs/nextline).\n\n##### External plugins\n\nThese plugins are not included in this package. They can be installed separately.\n\n- [**nextline-rdb:**](https://github.com/simonsobs/nextline-rdb) A relational database for nextline. It stores configuration, execution history, and other information. It is implemented with [SQLAlchemy 2](https://www.sqlalchemy.org/).\n- [**nextline-schedule:**](https://github.com/simonsobs/nextline-schedule) The **auto mode**. The **queue system**. An interface to the [_SO scheduler_](https://github.com/simonsobs/scheduler).\n- [**nextline-alert:**](https://github.com/simonsobs/nextline-alert) An interface to the alert system [_campana_](https://github.com/simonsobs/campana).\n\n#### Utility\n\n- [**nextline-test-utils:**](https://github.com/simonsobs/nextline-test-utils)\n  A collection of test utilities for backend development\n\n### Frontend web app (TypeScript)\n\nThe frontend web app is currently in a single package. The development of a\nplugin-based system is planned.\n\n- [**nextline-web:**](https://github.com/simonsobs/nextline-web)\n  The frontend web app of Nextline. It is a Vue.js app.\n\n## How to run the Nextline backend API server\n\nThe section shows how to run the Nextline backend API server. How to run the\nfrontend web app is described\n[elsewhere](https://github.com/simonsobs/nextline-web).\n\n### As a Docker container\n\nDocker images of the Nextline backend API server are created as\n[ghcr.io/simonsobs/nextline-graphql](https://github.com/simonsobs/nextline-graphql/pkgs/container/nextline-graphql).\nThese images are created by the\n[Dockerfile](https://github.com/simonsobs/nextline-graphql/blob/main/Dockerfile).\nNo external plugins are included in the images.\n\nUse, for example, the following command to run as a Docker container.\n\n```bash\ndocker run -p 8080:8000 ghcr.io/simonsobs/nextline-graphql\n```\n\nIf you access to the API server with a web browser, you will see the GraphQL\nIDE: \u003chttp://localhost:8080/\u003e.\n\nTo include external plugins, you can create a new Docker image with\n_ghcr.io/simonsobs/nextline-graphql_ as the base image. For example,\n[nextline-rdb](https://github.com/simonsobs/nextline-rdb) shows how to create a\nnew Docker image with _nextline-rdb_ as an external plugin.\n\n### In a virtual environment\n\nYou can create a virtual environment, install packages, and run the API server\nas follows.\n\n```bash\npython -m venv venv\nsource venv/bin/activate\npip install nextline-graphql\npip install uvicorn\nuvicorn --lifespan on --factory --port 8080 nextlinegraphql:create_app\n```\n\nCheck with a web browser at \u003chttp://localhost:8080/\u003e.\n\nIf you check out external plugins, nextline-graphql automatically detects them\nas plugins. An example can be described in\n[nextline-rdb](https://github.com/simonsobs/nextline-rdb).\n\n## Configuration\n\nnextline-graphql uses [dynaconf](https://www.dynaconf.com/) for configuration\nmanagement. The nextline-graphql framework itself has configuration for CORS\nand logging. The internal plugins have configurations. External plugins can\nextend the configuration.\n\n### CORS\n\nThese CORS (Cross-Origin Resource Sharing) settings will be given to\n`allow_origin` and `allow_headers` of Starlette's\n[`CORSMiddleware`](https://www.starlette.io/middleware/#corsmiddleware).\n\n| Environment variable               | Default value | Description                                                                                                                                                                                                                                                                                                                               |\n| ---------------------------------- | ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `NEXTLINE_CORS__ALLOW_ORIGINS`     | `['*']`       | A list of allowed origins, e.g., `[\"http://example.com:8080\"]`. The default value (`\"*\"`) allows any origins.                                                                                                                                                                                                                             |\n| `NEXTLINE_CORS__ALLOW_HEADERS`     | `['*']`       | A list of allowed HTTP request headers. For example, `['remote-user', 'remote-name', 'remote-email']` can be appropriate values if Authelia is used. Some headers such as `Content-Type` are always allowed (See [the Starlette doc](https://www.starlette.io/middleware/#corsmiddleware)). The default value (`\"*\"`) allows any headers. |\n| `NEXTLINE_CORS__ALLOW_CREDENTIALS` | `false`       | Whether to support cookies. If `true`, the wildcard (`\"*\"`) cannot be used for `NEXTLINE_CORS__ALLOW_ORIGINS` or `NEXTLINE_CORS__ALLOW_HEADERS`. They need to be listed explicitly.                                                                                                                                                       |\n\n### Logging\n\nSee [`default.toml`](./nextlinegraphql/config/default.toml).\n\n### `graphql` plugin\n\n| Environment variable                       | Default value | Description                                                                                      |\n| ------------------------------------------ | ------------- | ------------------------------------------------------------------------------------------------ |\n| `NEXTLINE_GRAPHQL__MUTATION_ALLOW_ORIGINS` | `[*]`         | A list of allowed origins for GraphQL Mutations. The default value (`\"*\"`) allows any origins.\\* |\n\n- In addition to the CORS settings above, this setting provides further access control for\n  GraphQL Mutations. With this setting, you can allow only GraphQL Queries and Subscriptions from\n  certain origins while prohibiting Mutations.\n\n### `ctrl` plugin\n\n| Environment variable           | Default value | Description                                                                                                                                 |\n| ------------------------------ | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------- |\n| `NEXTLINE_CTRL__TRACE_MODULES` | `false`       | By default (`false`), Nextline only traces the main Python script. If `true`, Nextline traces execution of imported Python modules as well. |\n| `NEXTLINE_CTRL__TRACE_THREADS` | `false`       | By default (`false`), Nextline only traces the main thread. If `true`, Nextline traces execution of other threads as well.                  |\n\n## Check out code for development\n\nHow to check out code from GitHub for development:\n\n```bash\ngit clone git@github.com:simonsobs/nextline-graphql.git\ncd nextline-graphql/\npython -m venv venv\nsource venv/bin/activate\npip install -e ./\"[tests,dev]\"\n```\n\nTo run\n\n```bash\nuvicorn --port 8080 --lifespan on --factory --reload nextlinegraphql:create_app\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsimonsobs%2Fnextline-graphql","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsimonsobs%2Fnextline-graphql","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsimonsobs%2Fnextline-graphql/lists"}