I am using SLIM Framework with a simple post route function like:
$app->post( '/addresses', 'addAddress' );
...
function addAddress()
{
global $app;
$request = $app->request();
$firstname = $request->params('firstname');
echo $firstname;
/* insert into action ... */
}
and want to get the post variables, but if I sent a post request with the Advanced Rest Client for Chrome like the following:
firstname=Test
the result is always null :(
EDIT:
the mistake was text/plain if I set it up to application/x-www-form-urlencoded it works
The mistake was to select text/plain for Advanced Rest Client, if I set it up to application/x-www-form-urlencoded it works
Related
I am using Codeigniter 4 to create a REST API. On my "production" environment, the response is returned as expected, but on my localhost it returns characters that are not encoded (or wrongly encoded):
API Service: /api/are_you/alive
Expected:
"timeout": "2023\/02\/19 21:01:27",
"payload": "yes"
Got:
���������������� (so many of these)
"timeout":"2023\/02\/19 20:58:40",
"payload":"yes"
The send response function is:
protected function send_response($response, $error = 0)
{
echo json_encode($output);
die();
}
And headers are set on the class constructor:
header('Content-Type: application/json');
header("Access-Control-Allow-Headers: X-API-KEY, Origin, X-Requested-With, Content-Type, Accept, Access-Control-Request-Method");
header("Access-Control-Allow-Methods: POST");
The same commit running in both environments.
What am I missing on my localhost?
My challenge here is to find the best way to test a Symfony (3.4) API application using Behat/Mink for functionnal test, in my CICD platform.
Because my testing processes must be called in a shell script, all the tests must be very linear. I have no way to start a standalone webserver like Apache or the PHP/Symfony webserver. Also, Docker is not an option.
For the moment, I can successfully test the GET verbs of the API using the Mink syntax :
-- file test.feature
#function1
Scenario Outline: Test my api
When I go to "/api/v1/hello"
Then the response is JSON
The "I go to" instruction is implemented by Mink (http://docs.behat.org/en/v2.5/cookbook/behat_and_mink.html) and it emulates a GET request only. When this instruction is called by BeHat, the app Symfony kernel is "spawned" and the "api/v1/hello" method is called internally : there is no network trafic, no TCP connection, there is no need for a dedicated webserver (apache, or the symfony standalone server). It looks like Behat is emulating a webserver and start by itself the Symfony app it its own user space.
Now I want to test the POST verbs of my API, with a json payload, but unfortunally Mink do not have other verbs than GET.
I have read some articles over the web (keyword : behat test post api) but all I have seen is based on a Guzzl/Curl client. So a real client-to-server connection is made to http://localhost and a real webserver have to respond to the request.
I want the Symfony API to be called internally without using an other webserver.
Is there a way to do that ? How to test a Symfony REST API and specially the POST verb without needing a standalone server to reply ?
Thank you.
Here is how I do a functional test of a POST API, with BeHat, without a local running webserver :
test.feature :
#function1
Scenario Outline: Test my api
Given I have the payload
"""
{ "data":"object"}
"""
When I request "POST /api/v1/post"
Then the response is JSON
The featureContext file implement two functions :
"I Have The Payload" : See here https://github.com/philsturgeon/build-apis-you-wont-hate/blob/master/chapter8/app/tests/behat/features/bootstrap/FeatureContext.php
"I request" : based on code provided by philsturgeon just above, I modify it to have something like that :
/**
* #When /^I request "(GET|PUT|POST|DELETE|PATCH) ([^"]*)"$/
*/
public function iRequest($httpMethod, $resource)
{
$this->lastResponse = $this->lastRequest = null;
$this->iAmOnHomepage();
$method = strtoupper($httpMethod);
$components = parse_url($this->getSession()->getCurrentUrl());
$baseUrl = $components['scheme'].'://'.$components['host'];
$this->requestUrl = $baseUrl.$resource;
$formParams = json_decode($this->requestPayload, true);
$formParamsList = [];
foreach($formParams as $param => $value) {
$formParamsList[$param] = json_encode($value);
}
// Construct request
$headers = [
'Accept'=>'application/json',
'Content-Type'=>'application/x-www-form-urlencoded'
];
try {
// Magic is here : allow to simulate any HTTP verb
$client = $this->getSession()->getDriver()->getClient();
$client->request(
$method,
$this->requestUrl,
$formParamsList,
[],
$headers,
null);
} catch (BadResponseException $e) {
$response = $e->getResponse();
// Sometimes the request will fail, at which point we have
// no response at all. Let Guzzle give an error here, it's
// pretty self-explanatory.
if (null === $response) {
throw $e;
}
$this->lastResponse = $e->getResponse();
throw new \Exception('Bad response.');
}
}
If you use Mink then it is quite easy
class FeatureContext extends RawMinkContext
{
/**
* #When make POST request to some Uri
*/
public function makePostRequestToSomeUri(): void
{
$uri = '/some-end-point';
/** #var \Symfony\Component\BrowserKit\Client $client */
$client = $this->getSession()->getDriver()->getClient();
$postParams = [];
$files = [];
$serverParams = [];
$rawContent = '';
$client->request(
\Symfony\Component\HttpFoundation\Request::METHOD_POST,
$uri,
$postParams,
$files,
$serverParams,
$rawContent
);
/** #var \Symfony\Component\HttpFoundation\Response $response */
$response = $client->getResponse();
//...
}
}
I am using Matlab's matlab.net.http library to launch get, put and post commands to a website. I can successfully launch get and post commands.
For example:
MyBody = matlab.net.http.MessageBody(struct('Id',YYYYYY,'WindfarmId',XXX,'Month','YYYY-MM-DD'));
Request = matlab.net.http.RequestMessage;
Request.Method = 'POST';
Request.Header = matlab.net.http.HeaderField('Content-Type','application/json','Authorization',['Basic ' matlab.net.base64encode([Username ':' Password])]);
Request.Body = MyBody;
uri = matlab.net.URI(ENTERURLHERE);
Response = Request.send(uri,MyHTTPOptions);
This works well. However using a PUT command I have to enter the equiavlent of this body (written in curl syntax):
-d '{ "InputValues": [ {"MetricLevelAId": 1, "MetricLevelBId": 1, "InputMetricId": 7, "Value": 56 } ] }'
I tried this:
data_InputValues = struct ('MetricLevelAId',1,'MetricLevelBId',1,'InputMetricId',7,'Value',56);
MyBody = matlab.net.http.MessageBody(struct('InputValues',dataInputValues));
However I keep receiving the following 'Bad Request' response from the server:
"Input values required"
I think this is linked to the way Matlab interprets the body part of the request and passes it to the server, i.e. it cannot pass the nested struct correctly. Anyone got any ideas how to solve this?
N.B. potentially linked to Translating curl into Matlab/Webwrite (it is dealing with a nested value)
Trying to consume Azure media service rest api. (following the tutorial : https://learn.microsoft.com/en-us/azure/media-services/media-services-rest-get-started)
Everything works fine until the point I try to create a Job. Sending the same request as in example (except asset id and token) and getting response :
Parsing request content failed due to: Make sure to only use property names that are defined by the type
Request:
POST https://wamsdubclus001rest-hs.cloudapp.net/api/Jobs HTTP/1.1
Connection: Keep-Alive
Content-Type: application/json
Accept: application/json; odata=verbose
Accept-Charset: UTF-8
Authorization: Bearer token -> here i send real token
DataServiceVersion: 1.0;NetFx
MaxDataServiceVersion: 3.0;NetFx
x-ms-version: 2.11
Content-Length: 458
Host: wamsdubclus001rest-hs.cloudapp.net
{
"Name":"TestJob",
"InputMediaAssets":[
{
"__metadata":{
"uri":"https://wamsdubclus001rest-hs.cloudapp.net/api/Assets('nb%3Acid%3AUUID%3A5168b52a-68ed-4df1-bac8-0648ce734ff6')"
}
}
],
"Tasks":[
{
"Configuration":"Adaptive Streaming",
"MediaProcessorId":"nb:mpid:UUID:ff4df607-d419-42f0-bc17-a481b1331e56",
"TaskBody":"<?xml version=\"1.0\" encoding=\"utf-8\"?><taskBody><inputAsset>JobInputAsset(0)</inputAsset> <outputAsset>JobOutputAsset(0)</outputAsset></taskBody>"
}
]
}
Response:
{
"error":{
"code":"",
"message":{
"lang":"en-US",
"value":"Parsing request content failed due to: Make sure to only use property names that are defined by the type"
}
}
}
It seems to be related with __metadata property. when I follow instruction from here : Creating Job from REST API returns a request property name error, the error changes:
"error":{
"code":"",
"message":{
"lang":"en-US",
"value":"Invalid input asset reference in TaskBody - "
}
}
}
Cant figure out whats wrong, thanks
Let me check on this, but it could be a couple issues that I have run into in the past.
First. Set both the Accept and Content-Type headers to:
"application/json; odata=verbose"
Next, double check that you are actually using the long underscore character on the metadata property. I've had issues where that was sending the wrong underscore character and it didn't match the property name.
Let me know if either of those helps.
It seems the issue was about "Content-Type". As I am using .net Core it was not easy to set the Conent-type as "application/json; odata=verbose".
1) Tried with RestSharp - dosnt support it, it cuts "odata=verbose" part out
2) Tried with Systsem.Net.Http.HttpClient -> Possible but difficult.
To add it as "Accept" :
MediaTypeWithQualityHeaderValue mtqhv;
MediaTypeWithQualityHeaderValue.TryParse("application/json;odata=verbose", out mtqhv);
client.DefaultRequestHeaders.Accept.Add(mtqhv);//ACCEPT header
To add it as "Content-Type" :
request.Content = new StringContent(content,
System.Text.Encoding.UTF8); //CONTENT-TYPE header -> default type will be text/html
request.Content.Headers.Clear(); // need to clear it - it will fail otherwise
request.Content.Headers.TryAddWithoutValidation("Content-Type","application/json;odata=verbose");
I am writing a test with PHPBowser, in Codeception v2.2.11 that uses the hidden API method of _loadpage.
I have added this into my \Helper\Api as follows:
public function loadpage($link)
{
$this->getModule('PhpBrowser')->_loadPage('POST', $link);
}
And call it in an Api Codeception test, as follows:
$link = 'http://www.fiercebiotech.com/contact';
$I->loadpage($link);
The issue I am facing is that when using _loadpage, it does not follow redirects. This exampled link when finally resolved is 301 redirected to:
http://www.fiercebiotech.com/contact-us.
Here is the header response console output when _loadpage opens $link.
I loadpage "http://www.fiercebiotech.com/contact"
[Request Headers] []
[Page] http://www.fiercebiotech.com/contact
[Response] 404
I need help getting _loadpage to not stop at ~/contact but follow the 301 redirect to ~/contact-us, so I can get the output header response to be
[page] http://www.fiercebiotech.com/contact-us
[response] 200
Currently I cant get _loadpage to follow 301 redirects. Anyone out there have success doing so?
Ive attempted to use Codeception REST function startFollowingRedirects and adding allow_redirects: true as follows, but neither technique seems to work (as the redirect is not followed).
class_name: ApiTester
modules:
enabled:
- WebDriver:
url: ''
browser: 'chrome'
window_size: 1200x993
clear_cookies: true
allow_redirects: true
- \Helper\Acceptance
- REST:
url: 'host'
depends: PhpBrowser
allow_redirects: true
- \Helper\Api
I found the solution to my issue:
The issue began with, as I suspected is that _loadpage does not follow redirects, it only loads the page requested and stops. In this case '~/contact-us', ignoring the fact that the page gets redirected to (with a 301) to '~/contact-us'.
I cant simply load the page (via _loadpage)
Get the header response
and assume that I will be getting the header response of the redirected URL
I will only get the header response of the original URL.
The Solution:
I have to in my foreach loop:
Go to the URL
send a GET
Grab the HTTP Header
Assert that the HTTP header has a 200OK response
Solution - As it is in Codeception code:
public function Validate_httpStatus_mainNav($mainNavLocator)
{
//Used to test main navigation -- 404 tests
$I = $this;
$mainNavLinks = $I->grabMultiple($mainNavLocator, 'href');
codecept_debug($mainNavLinks);
foreach ($mainNavLinks as $link) {
$I->amOnUrl($link);
$I->sendGET($link);
$I->grabHttpHeader($link);
$I->canSeeResponseCodeIs(HttpCode::OK);
}
}