Our Partner & Developer boards on the community are moving to a brand new home: the .dev community forums! While you can still access past discussions here, for all your future app and storefront building questions, head over to the new forums.

Returns Error 405 on embedded Node.js app

Solved

Returns Error 405 on embedded Node.js app

jojo_
Tourist
9 2 1

As said in my earlier post , somehow i managed to learn about the REST API and you can only create a SHOP metafield (Storefront) using GraphQL API. 

 

Now i'm trying to make a post request for a SHOP metafield. But it results in 405 method not allowed error. I searched the forums and found no clue about this. If anyone is willing to help, much appreciated. 

 

    axios({
      method: "post",
      url: "/admin/api/2020-04/metafields.json",
      data: {
        metafield: {
          namespace: "shop",
          key: "discount",
          value: discount,
          value_type: "string",
        },
      },
      headers: {
        "Content-Type": "application/json",
        "X-Shopify-Access-Token": accessToken,
      },
    });

 Here is the entire code of annotated-layout.js if that helps to understand the issue

 

import {
  Button,
  Card,
  Form,
  FormLayout,
  Layout,
  Page,
  SettingToggle,
  Stack,
  TextField,
  TextStyle,
} from "@shopify/polaris";
import axios from "axios";

class AnnotatedLayout extends React.Component {
  state = {
    discount: "10%",
    enabled: false,
  };

  render() {
    const { discount, enabled } = this.state;
    const contentStatus = enabled ? "Disable" : "Enable";
    const textStatus = enabled ? "enabled" : "disabled";

    return (
      <Page>
        <Layout>
          <Layout.AnnotatedSection
            title="Default discount"
            description="Add a product to Sample App, it will automatically be discounted."
          >
            <Card sectioned>
              <Form onSubmit={this.handleSubmit}>
                <FormLayout>
                  <TextField
                    value={discount}
                    onChange={this.handleChange("discount")}
                    label="Discount percentage"
                    type="discount"
                  />
                  <Stack distribution="trailing">
                    <Button primary submit>
                      Save
                    </Button>
                  </Stack>
                </FormLayout>
              </Form>
            </Card>
          </Layout.AnnotatedSection>
          <Layout.AnnotatedSection
            title="Price updates"
            description="Temporarily disable all Sample App price updates"
          >
            <SettingToggle
              action={{
                content: contentStatus,
                onAction: this.handleToggle,
              }}
              enabled={enabled}
            >
              This setting is{" "}
              <TextStyle variation="strong">{textStatus}</TextStyle>.
            </SettingToggle>
          </Layout.AnnotatedSection>
        </Layout>
      </Page>
    );
  }

  handleSubmit = () => {
    this.setState({
      discount: this.state.discount,
    });

    axios({
      method: "post",
      url: "/admin/api/2020-04/metafields.json",
      data: {
        metafield: {
          namespace: "shop",
          key: "discount",
          value: "10%",
          value_type: "string",
        },
      },
      headers: {
        "Content-Type": "application/json",
        "X-Shopify-Access-Token": xxxxxxxxxxxxxxxxx,
      },
    });

    console.log("submission", this.state);
  };

  handleChange = (field) => {
    return (value) => this.setState({ [field]: value });
  };

  handleToggle = () => {
    this.setState(({ enabled }) => {
      return { enabled: !enabled };
    });
  };
}

export default AnnotatedLayout;

 

 

Accepted Solution (1)
jojo_
Tourist
9 2 1

This is an accepted solution.

Okay, I finally figured it out. I was trying to do a post from client side and not from server side.  This post has been very helpful.

Also I was duplicating the router.get() for accepting the POST from client side.  I found this stackoverflow answer and update the code as below. Now its responding to axios post ( 200 ) and next thing would be adding an api call from server.js file. 

 

axios.post("/metafield", 
      {"metafield":{"namespace":"shop","key":"discount","value":"30%","value_type":"string"}},
      options)
      .then((response) => {
        console.log(response);
      }, (error) => {
        console.log(error);
      });
              
     
  router.post('/metafield', verifyRequest(), async ctx => {
    ctx.body = ctx.request.body;
    ctx.res.statusCode = 200;
});

@chipkeyes88 @SBD_  Thanks for your time.

 

 

View solution in original post

Replies 5 (5)

SBD_
Shopify Staff
1831 273 423

Hey @jojo_ 

 

405 indicates the wrong method. From first glance that code looks OK. Are you able to capture a request ID from the response headers?

Scott | Developer Advocate @ Shopify 

jojo_
Tourist
9 2 1

@SBD_  Thanks for looking into this.  I fixed the 405 error by adding a post method to router.

router.post("*", verifyRequest(), async ctx => {
    await handle(ctx.req, ctx.res);
    ctx.respond = false;
    ctx.res.statusCode = 200;
  });

But now its showing a new error Uncaught (in promise) Error: Request failed with status code 501

 

Initially i thought it is related to access scopes, but figured out there isn't any specific access code for shop resource. https://community.shopify.com/c/Shopify-APIs-SDKs/Which-scope-do-I-need-to-access-shop-metafields/td...

 

This is my latest code

let jsonData = JSON.stringify(
      {
        "metafield": {
          "namespace": "shop",
          "key": "discount",
          "value": "30%",
          "value_type": "string"
        }
      }
    );
    axios({
      method: "post",
      url: "/admin/api/2020-04/metafields.json",
      data: jsonData,
      headers: {
        "Content-Type": "application/json",
        "X-Shopify-Access-Token": accessToken,
      },
    });

 

And then I tried the same with Postman.  POST for the same value results in below error.

metafield: required parameter missing or invalid.

 

Thanks again!

 

 

 

 

 

 

 

 

 

chipkeyes88
Shopify Partner
14 3 13

Have you tried without calling JSON.stringify on the data payload. I think axios will work fine with straight JSON and the stringify may actually be throwing off how the body is sent in the request. Haven't tested but just a thought.

jojo_
Tourist
9 2 1

Still getting the same error 501 @chipkeyes88 

 

method=POST path="/admin/api/2020-04/metafields.json" host=demoo-app-new.herokuapp.com request_id=1999a2f8-c959-4d56-9113-46aee1a1669b fwd="111.92.74.226" dyno=web.1 connect=1ms service=168ms status=501 bytes=223 protocol=https
    const options = {
      headers : {"X-Shopify-Access-Token": accessToken, "Content-Type": "application/json"}
    };

    axios.post("/admin/api/2020-04/metafields.json", 
              {"metafield":{"namespace":"shop","key":"discount","value":"30%","value_type":"string"}},
              options);
     
jojo_
Tourist
9 2 1

This is an accepted solution.

Okay, I finally figured it out. I was trying to do a post from client side and not from server side.  This post has been very helpful.

Also I was duplicating the router.get() for accepting the POST from client side.  I found this stackoverflow answer and update the code as below. Now its responding to axios post ( 200 ) and next thing would be adding an api call from server.js file. 

 

axios.post("/metafield", 
      {"metafield":{"namespace":"shop","key":"discount","value":"30%","value_type":"string"}},
      options)
      .then((response) => {
        console.log(response);
      }, (error) => {
        console.log(error);
      });
              
     
  router.post('/metafield', verifyRequest(), async ctx => {
    ctx.body = ctx.request.body;
    ctx.res.statusCode = 200;
});

@chipkeyes88 @SBD_  Thanks for your time.