HTTP 405 (Method Not Allowed)

So basically I followed the tutorial to this:

I had done all the instructional steps, but I was met with this error whenever I tried to PostAsync.

image

My script is simple:

databaseService = require(script.DatabaseService)
local globalDatabase = databaseService:GetDatabase("Global")
game.Workspace.Model.Event.Event:Connect(function()
wait(10)
if globalDatabase:GetAsync("ifnuke")==true then
print("hi")
end
local a = true
p(a)
a = false
p(a)
end)
function p(a)
globalDatabase:PostAsync("ifnuke", a)
end

All the other scripts are from the devforum post, and I did not change them at all except for put my web app URL key.
I am able to PostAsync, but only once in a script. Any code after the PostAsync will not function. How do I fix this?

2 Likes

Well the error is pretty basic in my opinion, If it’s “Method Not Allowed” it is clearly explaining to you that it is not possible the use that method using HTTP/API. You just need to find a better method to do the same function as this script. I am not a web developer, just a programmer and usually errors give a very clear reason of why something doesn’t work.

1 Like

The problem is this is not just programming, this involves google spreadsheets and HTTPService. The devforum post linked gives this example so it’s official. I am not a web developer as well so I can’t find a different method to this

1 Like

Well, for starters Google Sheets isn’t a database, they’re probably taking steps to stop people from using it as such.

There’s plenty of other options that you can use as a free database solution that can be found here on the DevForum, I can suggest Datastores, Datastore2 or a SQLite3 Database from my experience with player data.

If you’re looking for the ability to get the data from different places, then you’re going to want to use the SQLite3 Database or another online database, otherwise, you can use Datastores or Datastore2.

2 Likes

I don’t have that much time to do SQLite3

1 Like

It’s a free tutorial that I linked that takes no more than 5 minutes to setup.

SQLite3 Database

3 Likes

This is an issue with the Google Sheets API. As stated in the about category post, please do not use Scripting Support to ask for help outside Roblox Lua programming.

2 Likes

Did you make sure you did all the steps properly as mentioned in that post? In my Discord-To-Roblox-Ban-Bot post, where I provided a free source modifying the system you are using, a lot of users contacted me about issues , the solutions usually include running the DataBaseMacro script, publishing it, getting the proper scriptID , and more, could you please confirm you did all these steps properly? And if you could, instead of posting this in this section as @ElliottLMz mentioned, take this post to the area where you got this source.

1 Like

So I followed every step in the SQLite3 Database tutorial and now I’m stuck at how to operate it.
Here is what I have so far.
const databaseFile = ‘./.data/rbx-sqlite3-db003.db’; // If you need to reset EVERYTHING, you can change this.

const tables = [ // These are created once if alwaysCreateTables is false, however if it is set to true these all will be made each time (will not reset data, but will create any new table entries)
    "table1", // All tables have two rows, key and value
    "table2",
    "table3"
];

const alwaysCreateTables = true;

const ApiToken = "secret"; // Highly recommended: https://www.grc.com/passwords.htm

const tableKeyLength = 150;
const tableValueLength = 3500;

const getAsyncAllowStar = true; // Allow "*" to be sent to the server to return all data from a table.

/*
  SETTINGS ABOVE
*/
var $stmt;
var fs = require('fs');

const sqlite3 = require('better-sqlite3');

var dbExists = fs.existsSync(databaseFile);
const Database = new sqlite3(databaseFile);
const json = JSON.stringify;

var express = require('express');
var bodyParser = require('body-parser');
var app = express();
app.use(bodyParser.json());
if (!dbExists || alwaysCreateTables) {
  /* fill database with tables */
  tables.forEach(function(v, i) {
    Database.prepare("CREATE TABLE IF NOT EXISTS "+v+" (key VARCHAR("+tableKeyLength+") PRIMARY KEY, value VARCHAR("+tableValueLength+") NOT NULL)").run();
  });
}
function isValidTable(tab) {
  return (tables.indexOf(tab) !== -1); // prepared statements don't allow you to specify a table, so we have to whitelist tables specified above.
}


app.delete("/deleteAsync", function(req, res) {
  if (req.headers["apitoken"] == ApiToken) {
    if (req.body.Key != null && req.body.Table != null) {
      if (isValidTable(req.body.Table)) {
        $stmt = Database.prepare("DELETE FROM `"+ req.body.Table +"` WHERE `key`=?");
        var data = $stmt.run(req.body.Key);
        res.status(200);
        res.send(json({
          Success: true,
          KeyDeleted: data.changes > 0
        }));
      } else {
        res.status(404);
        res.send(json({
          Success: false,
          Message: "Table doesn't exist"
        }));
      }
    } else {
      res.status(400);
      res.send(json({
        Success: false,
        Message: "Invalid request"
      }));
    }
  } else {
    res.status(403);
    res.send(json({
      Success: false,
      Message: "You are unauthorized to make requests to this host."
    }));
  }
});

app.post("/postAsync", function(req, res) {
  if (req.headers["apitoken"] == ApiToken) {
    if (req.body.Key != null && req.body.Value != null && req.body.Table != null) {
      if (isValidTable(req.body.Table)) {
        $stmt = Database.prepare("REPLACE INTO `"+ req.body.Table +"` (key, value) VALUES (?, ?)"); // Create value if not exist, change value if exist.
        var changes = $stmt.run(req.body.Key, req.body.Value).changes;
        res.status(200);
        res.send(json({
          Success: true,
          Changes: changes
        }));
      } else {
        res.status(404);
        res.send(json({
          Success: false,
          Message: "Table doesn't exist"
        }));
      }
    } else {
      res.status(400);
      res.send(json({
        Success: false,
        Message: "Invalid request"
      }));
    }
  } else {
    res.status(403);
    res.send(json({
      Success: false,
      Message: "You are unauthorized to make requests to this host."
    }));
  }
});

app.post("/getAsync", function(req, res) {
  if (req.headers["apitoken"] == ApiToken) {
    if (req.body.Key != null && req.body.Table != null) {
      if (isValidTable(req.body.Table)) {
        if (req.body.Key == "*" && getAsyncAllowStar) {
          $stmt = Database.prepare("SELECT * FROM `" + req.body.Table +"`");
          
          var data = $stmt.all();
          res.status(200);
          res.send(json({
            Success: true,
            ValueExists: data.length > 0,
            Value: data
          }));
        } else {
          $stmt = Database.prepare("SELECT * FROM `" + req.body.Table + "` WHERE `key`=?");
          var data = $stmt.get(req.body.Key);
          res.status(200);
          res.send(json({
            Success: true,
            ValueExists: (!data == null),
            Value: data
          }));
        }
      } else {
        res.status(404);
        res.send(json({
          Success: false,
          Message: "Table doesn't exist"
        }));
      }
    } else {
      res.status(400);
      res.send(json({
        Success: false,
        Message: "Invalid request"
      }));
    }
  } else {
    res.status(403);
    res.send(json({
      Success: false,
      Message: "You are unauthorized to make requests to this host."
    }));
  }
});

app.all("/", function(req, res) {
  res.send("Well, hello there Wanderer!");
});

var list = app.listen(process.env.PORT, function() {
  console.log('Server Online, Port ' + list.address().port);
});

And:

{
  "name": "rbx-mysql-server",
  "version": "1.0.0",
  "description": "Roblox MySQL Server",
  "main": "server.js",
  "scripts": {
    "start": "node server.js"
  },
  "dependencies": {
    "express": "^4.16.3",
    "sqlite3": "^4.0.0",
    "better-sqlite3": "^5.2.1"
  },
  "engines": {
    "node": "8.x"
  }
}

And:

local sql = {
	ApiUrl = "https://primeverse.glitch.me", -- Do not use a trailing slash.
	Token = "secret",
}
local http = game:GetService'HttpService';
local dummyFunction = function()end;
function sql:PostAsync(Table, Key, Value, Callback)
	if (Table == nil) then
		return error("Table is unspecified", 0);
	elseif (Key == nil) then
		return error("Key is unspecified", 0);
	elseif (Value == nil) then
		return error("Value is unspecified", 0);
	elseif (Callback == nil) then
		Callback = dummyFunction;
	end
	
	spawn(function()
		local data = http:RequestAsync({
			Url = sql.ApiUrl .. "/postAsync",
			Method = "POST",
			Headers = {
				ApiToken = sql.Token,
				["Content-Type"] = "application/json"
			},
			Body = http:JSONEncode{
				Key = Key,
				Value = Value,
				Table = Table
			}
		})
		local validJson, Resp = pcall(function()
			return http:JSONDecode(data.Body);
		end)
		if (validJson) then
			if (data.StatusCode == 200) then
				Callback(true, Resp);
			else
				Callback(false, "Request did not succeed. [" .. data.StatusCode .. "]", Resp);
			end
		else
			Callback(false, "Server returned invalid response", data.Body)
		end
	end)
end

function sql:DeleteAsync(Table, Key, Callback)
	if (Table == nil) then
		return error("Table is unspecified", 0);
	elseif (Key == nil) then
		return error("Key is unspecified", 0);
	elseif (Callback == nil) then
		Callback = dummyFunction;
	end
	
	spawn(function()
		local data = http:RequestAsync({
			Url = sql.ApiUrl .. "/deleteAsync",
			Method = "DELETE",
			Headers = {
				ApiToken = sql.Token,
				["Content-Type"] = "application/json"
			},
			Body = http:JSONEncode{
				Key = Key,
				Table = Table
			}
		})
		local validJson, Resp = pcall(function()
			return http:JSONDecode(data.Body);
		end)
		if (validJson) then
			if (data.StatusCode == 200) then
				Callback(true, Resp);
			else
				Callback(false, "Request did not succeed. [" .. data.StatusCode .. "]", Resp);
			end
		else
			Callback(false, "Server returned invalid response", data.Body)
		end
	end)
end


function sql:GetAsync(Table, Key, Callback)
	if (Table == nil) then
		return error("Table is unspecified", 0);
	elseif (Key == nil) then
		return error("Key is unspecified", 0);
	elseif (Callback == nil) then
		return error("Callback is unspecified", 0);
	end
	
	spawn(function()
		local data = http:RequestAsync({
			Url = sql.ApiUrl .. "/getAsync",
			Method = "POST",
			Headers = {
				ApiToken = sql.Token,
				["Content-Type"] = "application/json"
			},
			Body = http:JSONEncode{
				Key = Key,
				Table = Table
			}
		})
		local validJson, Resp = pcall(function()
			return http:JSONDecode(data.Body);
		end)
		if (validJson) then
			if (data.StatusCode == 200) then
				Callback(true, Resp);
			else
				Callback(false, "Request did not succeed. [" .. data.StatusCode .. "]", Resp);
			end
		else
			Callback(false, "Server returned invalid response", data.Body);
		end
	end)
end

return sql;

And:

sql = require(script.DatabaseService)

game.Workspace.Model.Event.Event:Connect(function()

wait(10)

if sql:GetAsync("ifnuke")==true then

print("hi")

end

local a = true

p(a)

a = false

p(a)

end)

function p(a)

sql:PostAsync("ifnuke", a)

end

but I keep getting this error: image

There’s a different method to getting data.

To get data,

sql:GetAsync("table1example", "Table 1 key", function(Success, Value, ServerResponse)
	if (Success) then
    	-- Value is 'Table 1 key's value or nil, if it doesn't exist.
    else
    	-- Value is the error message, however ServerResponse will contain more detailed information.
    end
end)

All the examples on how to use the SQLite3 Database are listed here.

You don’t understand. What I’m trying to do here is trying to see if “nuke” is true or false.

    game.Workspace.Model.Event.Event:Connect(function()
	wait(10)
	if sql:GetAsync("nuke", "key")==true then
		print("hi")
	end
	local a = true
	p(a)
	a = false
	p(a)
end)
function p(a)

sql:PostAsync("nuke", a)

end

I’m also trying to change the value of nuke.

Right, to get the value of nuke, you need to

sql:GetAsync("table1", "nuke", function(Success, Value, ServerResponse)
    if (Success) then
    	print(Value.Value.value) -- Prints the value of nuke.
    else
    	-- Value is the error message, however, ServerResponse will contain more detailed information.
    end
end)

This isn’t taking advantage of the full power of SQL. Just using key value pairs may not give you everything you need. You’d probably be best to take a look at some tutorials like this and learn SQL if you’re going to use it for your back-end. I’m not saying that there is something wrong with that method but it limits you a lot to what you can accomplish. If you set it up so that you can query and run statements from Roblox scripts then you can look here for a list. If you do decide to go this route feel free to DM me with any questions you may have, SQL isn’t always the easiest to learn.

Now it keeps saying table is unspecified
image

I haven’t read over your source code, but are you sure you are querying the right table?

You need to make sure that the table part matches up with the table part on glitch, I just used “Table1” as that’s the default settings.

Can you show me the first couple of lines in the glitch code, or specifically the part about the tables?

const tables = [
  // These are created once if alwaysCreateTables is false, however if it is set to true these all will be made each time (will not reset data, but will create any new table entries)
  "nuke", // All tables have two rows, key and value
  "table2",
  "table3"
];

Right, so in the first argument of the :GetASync(), change “table1” to “nuke” and let me know the results.