Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 10 additions & 6 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion example/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@ license = "MIT"
shopify_function = { path = "../shopify_function" }
serde = { version = "1.0.13", features = ["derive"] }
serde_json = "1.0"
graphql_client = "0.13.0"
graphql_client = "0.14.0"
graphql_client_codegen = "0.14.0"
3 changes: 0 additions & 3 deletions example_with_targets/.target_a.output.graphql

This file was deleted.

3 changes: 0 additions & 3 deletions example_with_targets/.target_b.output.graphql

This file was deleted.

3 changes: 2 additions & 1 deletion example_with_targets/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@ license = "MIT"
shopify_function = { path = "../shopify_function" }
serde = { version = "1.0.13", features = ["derive"] }
serde_json = "1.0"
graphql_client = "0.13.0"
graphql_client = "0.14.0"
graphql_client_codegen = "0.14.0"
25 changes: 14 additions & 11 deletions example_with_targets/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,36 +3,39 @@ use shopify_function::{run_function_with_input, Result};

#[test]
fn test_a() -> Result<()> {
let result = run_function_with_input(
target_a,
r#"
let result = serde_json::to_string(
&run_function_with_input(
target_a,
r#"
{
"id": "gid://shopify/Order/1234567890",
"num": 123,
"name": "test"
}
"#,
)
.unwrap(),
)?;
let expected = crate::target_a::output::FunctionTargetAResult { status: Some(200) };
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 Alternative to changing these tests to assert JSON output is to make this result type public.

Error:

d@Delta-Shopify shopify-function-rust % cargo t
warning: virtual workspace defaulting to `resolver = "1"` despite one or more workspace members being on edition 2021 which implies `resolver = "2"`
note: to keep the current resolver, specify `workspace.resolver = "1"` in the workspace root's manifest
note: to use the edition 2021 resolver, specify `workspace.resolver = "2"` in the workspace root's manifest
note: for more details see https://doc.rust-lang.org/cargo/reference/resolver.html#resolver-versions
   Compiling shopify_function_macro v0.5.0 (/Users/d/src/github.com/Shopify/shopify-function-rust/shopify_function_macro)
   Compiling shopify_function v0.5.0 (/Users/d/src/github.com/Shopify/shopify-function-rust/shopify_function)
   Compiling example_with_targets v1.0.0 (/Users/d/src/github.com/Shopify/shopify-function-rust/example_with_targets)
   Compiling example v1.0.0 (/Users/d/src/github.com/Shopify/shopify-function-rust/example)
error[E0603]: module `output` is private
  --> example_with_targets/src/tests.rs:16:37
   |
16 |     let expected = crate::target_a::output::FunctionTargetAResult { status: Some(200) };
   |                                     ^^^^^^  --------------------- struct `FunctionTargetAResult` is not publicly re-exported
   |                                     |
   |                                     private module
   |
note: the module `output` is defined here
  --> example_with_targets/src/lib.rs:4:1
   |
4  | / #[shopify_function_target(
5  | |     // Implicit target = "example.target-a"
6  | |     // Implicit generated module name = "target_a"
7  | |     query_path = "a.graphql",
8  | |     schema_path = "schema.graphql"
9  | | )]
   | |__^
   = note: this error originates in the attribute macro `shopify_function_target` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0603]: module `output` is private
  --> example_with_targets/src/tests.rs:32:34
   |
32 |     let expected = crate::mod_b::output::FunctionTargetBResult {
   |                                  ^^^^^^  --------------------- struct `FunctionTargetBResult` is not publicly re-exported
   |                                  |
   |                                  private module
   |
note: the module `output` is defined here
  --> example_with_targets/src/lib.rs:16:1
   |
16 | / #[shopify_function_target(
17 | |     // Explicit target if function name does not match target handle
18 | |     target = "example.target-b",
19 | |     // Override generated module name
...  |
22 | |     schema_path = "schema.graphql"
23 | | )]
   | |__^
   = note: this error originates in the attribute macro `shopify_function_target` (in Nightly builds, run with -Z macro-backtrace for more info)

For more information about this error, try `rustc --explain E0603`.
error: could not compile `example_with_targets` (lib test) due to 2 previous errors
warning: build failed, waiting for other jobs to finish...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe export a test helper function to assert expected JSON string?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What are the reasons not to make it public?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good question. I could do that 😆

let expected = r#"{"status":200}"#;
assert_eq!(result, expected);
Ok(())
}

#[test]
fn test_function_b() -> Result<()> {
let result = run_function_with_input(
function_b,
r#"
let result = serde_json::to_string(
&run_function_with_input(
function_b,
r#"
{
"id": "gid://shopify/Order/1234567890",
"aResult": 200
}
"#,
)
.unwrap(),
)?;
let expected = crate::mod_b::output::FunctionTargetBResult {
name: Some("new name: \"gid://shopify/Order/1234567890\"".to_string()),
};

let expected = r#"{"name":"new name: \"gid://shopify/Order/1234567890\""}"#;
assert_eq!(result, expected);
Ok(())
}
3 changes: 2 additions & 1 deletion shopify_function/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,5 @@ version = "1"
features = ["small"]

[dev-dependencies]
graphql_client = "0.13.0"
graphql_client = "0.14.0"
graphql_client_codegen = "0.14.0"
67 changes: 34 additions & 33 deletions shopify_function/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,57 +4,57 @@ A crate to help developers build [Shopify Functions].

## Dependencies

* Make sure you have `graphql_client` in your dependencies
- Make sure you have `graphql_client` in your dependencies

```
cargo add graphql_client@0.13.0
```
```
cargo add graphql_client@0.14.0
```

## Usage

* The [`generate_types`] macro allows you to generate structs based on your [input query]. It will also generate output/response types for the current Function API, based on the provided schema.
* It will automatically generate an `.output.graphql` file for code generation purposes. This file can be added to your `.gitignore`.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the relevant non-formatting change in the file.

* The [`shopify_function`] attribute macro marks the following function as the entry point for a Shopify Function. It manages the Functions `STDIN` input parsing and `STDOUT` output serialization for you.
* The [`run_function_with_input`] function is a utility for unit testing which allows you to quickly add new tests based on a given JSON input string.
- The [`generate_types`] macro allows you to generate structs based on your [input query]. It will also generate output/response types for the current Function API, based on the provided schema.
- The [`shopify_function`] attribute macro marks the following function as the entry point for a Shopify Function. It manages the Functions `STDIN` input parsing and `STDOUT` output serialization for you.
- The [`run_function_with_input`] function is a utility for unit testing which allows you to quickly add new tests based on a given JSON input string.

See the [example] for details on usage, or use the following guide to convert an existing Rust-based function.

## Updating an existing function to use `shopify_function`

1. `cargo add shopify_function`
1. `cargo add graphql_client@0.13.0`
1. `cargo add graphql_client@0.14.0`
1. Delete `src/api.rs`.
1. In `main.rs`:
1. Add imports for `shopify_function`.

```rust
use shopify_function::prelude::*;
use shopify_function::Result;
```
1. Add imports for `shopify_function`.

1. Remove references to `mod api`.
1. Add type generation, right under your imports.
```rust
use shopify_function::prelude::*;
use shopify_function::Result;
```

```rust
generate_types!(query_path = "./input.graphql", schema_path = "./schema.graphql");
```
1. Remove references to `mod api`.
1. Add type generation, right under your imports.

1. Remove the `main` function entirely.
1. Attribute the `function` function with the `shopify_function` macro, and change its return type.
```rust
generate_types!(query_path = "./input.graphql", schema_path = "./schema.graphql");
```

```rust
#[shopify_function]
fn function(input: input::ResponseData) -> Result<output::FunctionResult> {
```
1. Remove the `main` function entirely.
1. Attribute the `function` function with the `shopify_function` macro, and change its return type.

1. Update the types and fields utilized in the function to the new, auto-generated structs. For example:
| Old | New |
| --- | --- |
| `input::Input` | `input::ResponseData` |
| `input::Metafield` | `input::InputDiscountNodeMetafield` |
| `input::DiscountNode` | `input::InputDiscountNode` |
| `FunctionResult` | `output::FunctionResult` |
| `DiscountApplicationStrategy::First` | `output::DiscountApplicationStrategy::FIRST` |
```rust
#[shopify_function]
fn function(input: input::ResponseData) -> Result<output::FunctionResult> {
```

1. Update the types and fields utilized in the function to the new, auto-generated structs. For example:
| Old | New |
| --- | --- |
| `input::Input` | `input::ResponseData` |
| `input::Metafield` | `input::InputDiscountNodeMetafield` |
| `input::DiscountNode` | `input::InputDiscountNode` |
| `FunctionResult` | `output::FunctionResult` |
| `DiscountApplicationStrategy::First` | `output::DiscountApplicationStrategy::FIRST` |

1. Add `.output.graphql` to your `.gitignore`.

Expand All @@ -69,6 +69,7 @@ cargo doc --open
You can also use the [cargo-expand](https://github.com/dtolnay/cargo-expand) crate to view the generated source, or use the [rust-analyzer](https://marketplace.visualstudio.com/items?itemName=rust-lang.rust-analyzer) VSCode extension to get [IntelliSense](https://code.visualstudio.com/docs/editor/intellisense) for Rust and the generated types.

---

License Apache-2.0

[Shopify Functions]: https://shopify.dev/api/functions
Expand Down
1 change: 1 addition & 0 deletions shopify_function_macro/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,4 @@ syn = { version = "1.0", features = ["full"] }
quote = "1.0"
proc-macro2 = "1.0.43"
convert_case = "0.6.0"
graphql_client_codegen = "0.14.0"
Loading