diff --git a/docs/custom_code.md b/docs/custom_code.md new file mode 100644 index 0000000..edf224a --- /dev/null +++ b/docs/custom_code.md @@ -0,0 +1,53 @@ +# How To: Extending Platformics Generated Code +Platformics will generate a GraphQL API that exposes CRUD operations for each entity type in your LinkML schema. It is often the case, however, that you will need to expose more functionality in your API than just CRUD. There are a few options for extending generated code to add custom business logic to your application. + +## Adding root-level queries and mutations +Platformics will generate basic read and aggregate queries in `api/queries.py`. These are inherited by a query class in `custom_queries.py`, which will gain access to all the codegenned queries as well as allow you to implement your own queries. To add a new root level field (query), add the field to the query class in `custom_queries.py`: + +``` +@strawberry.type +class Query(BaseQuery): + foo: str = my_custom_field +``` +The resolver for the custom field should be decorated with `@strawberry.field`: +``` +@strawberry.field +def my_custom_field(self) -> str: + return "foo" +``` + +Similarly, for custom mutations, root level mutations can be added to the `Mutation` class in `custom_mutations.py`, which inherits from the codegenned `Mutation` class in `api/mutations.py` + +``` +@strawberry.type +class Mutation(BaseMutation): + bar: str = my_custom_mutation +``` +The resolver for the custom mutation should be decorated with `@strawberry.mutation`: +``` +@strawberry.mutation +def my_custom_mutation(self) -> str: + return "bar" +``` +Both the custom query and mutation classes are imported into `main.py` and used by Strawberry to generate an API at runtime: +``` +from custom_mutations import Mutation +from custom_queries import Query + +schema = strawberry.Schema(query=Query, mutation=Mutation, config=get_strawberry_config(), extensions=[HandleErrors()]) +``` + +### Overriding queries and mutations +By creating a field with the same name as an existing codegenned query or mutation, you can override the codegenned resolver. +``` +@strawberry.mutation +def my_override_mutation(self) -> str: + return "Sorry, I overrode the mutation" + +@strawberry.type +class Mutation(BaseMutation): + create_sample: str = my_override_mutation +``` + +## Using your own templates +TODO: fill this out. Existing functionality. diff --git a/platformics/codegen/templates/api/mutations.py.j2 b/platformics/codegen/templates/api/mutations.py.j2 index 9f4b75b..f03570b 100644 --- a/platformics/codegen/templates/api/mutations.py.j2 +++ b/platformics/codegen/templates/api/mutations.py.j2 @@ -16,7 +16,7 @@ from api.types.{{ class.snake_name }} import {{ class.name }}, {%- if class.crea {%- endfor %} @strawberry.type -class BaseMutation: +class Mutation: {%- if render_files %} # File mutations create_file: File = create_file diff --git a/platformics/codegen/templates/api/queries.py.j2 b/platformics/codegen/templates/api/queries.py.j2 index 01e4108..5ba7be6 100644 --- a/platformics/codegen/templates/api/queries.py.j2 +++ b/platformics/codegen/templates/api/queries.py.j2 @@ -17,7 +17,7 @@ from api.types.{{ class.snake_name }} import {{ class.name }}, resolve_{{ class. @strawberry.type -class BaseQuery: +class Query: # Allow relay-style queries by node ID node: relay.Node = relay.node() nodes: List[relay.Node] = relay.node() diff --git a/test_app/customMutations.py b/test_app/customMutations.py deleted file mode 100644 index 83abc32..0000000 --- a/test_app/customMutations.py +++ /dev/null @@ -1,12 +0,0 @@ -import strawberry -from api.mutations import BaseMutation - - -@strawberry.mutation -def my_custom_mutation(self) -> str: - return "bar" - - -@strawberry.type -class Mutation(BaseMutation): - bar: str = my_custom_mutation diff --git a/test_app/custom_mutations.py b/test_app/custom_mutations.py new file mode 100644 index 0000000..151c8b3 --- /dev/null +++ b/test_app/custom_mutations.py @@ -0,0 +1,17 @@ +import strawberry +from api.mutations import Mutation as BaseMutation + + +@strawberry.mutation +def my_custom_mutation(self) -> str: + return "bar" + +@strawberry.mutation +def my_override_mutation(self) -> str: + return "Sorry, I overrode the mutation" + + +@strawberry.type +class Mutation(BaseMutation): + bar: str = my_custom_mutation + create_sample: str = my_override_mutation diff --git a/test_app/customQueries.py b/test_app/custom_queries.py similarity index 79% rename from test_app/customQueries.py rename to test_app/custom_queries.py index 19dbfa9..5df5753 100644 --- a/test_app/customQueries.py +++ b/test_app/custom_queries.py @@ -1,5 +1,5 @@ import strawberry -from api.queries import BaseQuery +from api.queries import Query as BaseQuery @strawberry.field @@ -9,5 +9,4 @@ def my_custom_field(self) -> str: @strawberry.type class Query(BaseQuery): - foo: str = my_custom_field diff --git a/test_app/main.py b/test_app/main.py index 5553aff..6d32a4c 100644 --- a/test_app/main.py +++ b/test_app/main.py @@ -9,9 +9,8 @@ from platformics.settings import APISettings from database import models -from customMutations import Mutation - -from customQueries import Query +from custom_mutations import Mutation +from custom_queries import Query settings = APISettings.model_validate({}) # Workaround for https://github.com/pydantic/pydantic/issues/3753