Conversations about creating, managing, and using metafields to store and retrieve custom data for apps and themes.
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;
Solved! Go to the solution
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.
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
@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!
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.
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);
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.