Why on Codeigniter 4 the REST outoput is not encoded? - rest

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?

Related

How to check for proper format in my API response

Currently running tests for my REST API which:
takes an endpoint from the user
using that endpoint, grabs info from a server
sends it to another server to be translated
then proceeds to jsonify the data.
I've written a series of automated tests running and I cannot get one to pass - the test that actually identifies the content of the response. I've tried including several variations of what the test is expecting but I feel it's the actual implementation that's the issue. Here's the expected API response from the client request:
{ "name": "random_character", "description": "Translated description of requested character is output here" }
Here is the testing class inside my test_main.py:
class Test_functions(unittest.TestCase):
# checking if response of 200 is returned
def test_healthcheck_PokeAPI(self):
manualtest = app.test_client(self)
response = manualtest.get("/pokemon/")
status_code = response.status_code
self.assertEqual(status_code, 200)
# the status code should be a redirect i.e. 308; so I made a separate test for this
def test_healthcheck_ShakesprAPI(self):
manualtest = app.test_client(self)
response = manualtest.get("/pokemon/charizard")
self.assertEqual(response.status_code, 308)
def test_response_content(self):
manualtest = app.test_client(self)
response = manualtest.get("/pokemon/charizard")
self.assertEqual(response.content_type,
'application/json') <<<< this test is failing
def test_trans_shakespeare_response(self):
manualtest = app.test_client(self)
response = manualtest.get("/pokemon/charizard")
self.assertFalse(b"doth" in response.data)
Traceback:
AssertionError: 'text/html; charset=utf-8' != 'application/json' - text/html; charset=utf-8 + application/json
Any help would be greatly appreciated

Azure media service job creation fails using rest api

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");

SLIM Framework post variables always null

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

Use of charter encoding with content type in JAX-RS 2.0 - Jersey

I am developing JAX-RS 2.0 client with Jersey implementation. REST API returns response with content type as 'application/json; UTF-8'
At client side, Jersey cannot recognize this content-type and throws error like
Unable to parse "Content-Type" header value: "application/json; UTF-8"
org.glassfish.jersey.message.internal.HeaderValueException: Unable to parse "Content-Type" header value: "application/json; UTF-8"
at org.glassfish.jersey.message.internal.InboundMessageContext.exception(InboundMessageContext.java:318)
at org.glassfish.jersey.message.internal.InboundMessageContext.singleHeader(InboundMessageContext.java:313)
at org.glassfish.jersey.message.internal.InboundMessageContext.getMediaType(InboundMessageContext.java:427)
If content type is "application/json" same code could process the response. I tried to search over google and some posts say that such character encoding along with content type is supported in Jersey but I didn't find it working.
Following is code I am trying with.
Client clientSaml = ClientBuilder.newBuilder().sslContext(context)
.hostnameVerifier(new HostnameVerifier() {
#Override
public boolean verify(String arg0, SSLSession arg1) {
// TODO Auto-generated method`enter code here` stub
return true;
}
}).build();
clientSaml.register(new SAMLAuthenticator(token));
clientSaml.register(new LoggingFilter());
WebTarget target = clientSaml
.target(URL_OF_API);
Response resp = target.request(MediaType.APPLICATION_JSON).get();
System.out.println(resp.getMediaType().toString());
Does anybody had this issue before and what could be possible solution of this ?? Does any other implementation of JAX-RS support it ?
You forgot charset=:
Content-Type: application/json; charset=UTF-8
See Section 14.17 Content-Type of HTTP 1.1.
I did workaround of this issue using ClientResponseFilter
Thanks to hint suggested in Jersey and #FormParam not working when charset is specified in the Content-Type

Apache Wink Client - Test a REST service using form auth

I am trying to use the Wink RestClient to do functional testing on a Rest service endpoint. I use mocks for unit testing but I'd like to functionally test it as an endpoint consumer.
I understand some will object to me calling it a REST endpoint while using form-based auth but that is the current architecture I have.
The majority of the resources I want to test are protected resources and the application (running on Tomcat6) is protected by form authentication. (as in the below web.xml snippet).
What I've tried so far is to make an initial call to an unprotected resource, to obtain the set-cookie header, that contains JSESSIONID, and use that JSESSIONID in the header ( via Resource.cookie() ) in subsequent requests but that does not yield fruit.
web.xml
<login-config>
<auth-method>FORM</auth-method>
<form-login-config>
<form-login-page>/login.html</form-login-page>
<form-error-page>/login.html?failure=true</form-error-page>
</form-login-config>
</login-config>
My Wink RestClient code looks like below. All responses are 200, but two things I notice are that the response from the call to /j_security_check/ does not include the jsessionid cookie, and the call to the protected resource said I had a signin failure. The payload for the call to j_security_check was captured directly from a previous successful browser request intercepted.
ClientConfig config = new ClientConfig();
config.setBypassHostnameVerification(true);
RestClient restClient = new RestClient(config);
Resource unprotectedResource = restClient.resource( BASE_URL + "/");
unprotectedResource.header( "Accept", "*/*" );
ClientResponse clientResponse = unprotectedResource.get();
String response = clientResponse.getEntity(String.class);
// get jSession ID
String jSessionId = clientResponse.getHeaders().get("set-cookie").get(0);
jSessionId = jSessionId.split(";")[0];
System.out.println(jSessionId);
// create a request to login via j_security_check
Resource loginResource = restClient.resource(BASE_URL + "/j_security_check/");
loginResource.accept("text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
loginResource.header("referer", "http://localhost:8080/contextroot/");
loginResource.cookie( jSessionId );
loginResource.header("Connection", "keep-alive");
loginResource.header("Content-Type", "application/x-www-form-urlencoded");
loginResource.header("Content-Length", "41");
ClientResponse loginResponse = loginResource.post("j_username=*****&j_password=*************");
/* the loginResponse, as this point, does not have the jsessionid cookie, my browser client does */
Resource protectedResource = restClient.resource(BASE_URL + "/protected/test/");
systemResource.accept("application/json");
systemResource.cookie( jSessionId );
ClientResponse systemResponse = systemResource.get();
response = clientResponse.getEntity(String.class);
System.out.println(response);
Any thoughts or experience with using the Wink RestClient to exercise form-auth-protected resources would be greatly appreciated. I suppose I'd entertain other frameworks, I have heard of REST-Assured and others, but since the application uses Wink and the RestClient seems to provide me with what I need, I figured I'd stick with it.
Found the problem, and the solution
j_security_check was responding to my POST request (to authenticate), with a #302/redirect. That was being followed by the wink RestClient, but my JSESSIONID cookie was not being appended to it. That was causing the response (from the redirected URL) to contain a set-cookie header, with a new header. My subsequent calls, into which I inserted the JSESSIONID from the first call, failed, because that cookie was expired. All I needed to do was instruct the RestClient to NOT follow redirects. If the redirect were necessary, I would construct it on my own, containing the appropriate cookie.
Chromium and Firefox carry the cookie from the original request to the redirected request so it's all good.
Here is some code that worked for me, using JUnit4, RestClient from the Apache Wink project (and a Jackson ObjectMapper)
#Test
public void testGenerateZipEntryName() throws JsonGenerationException, JsonMappingException, IOException
{
final ObjectMapper mapper = new ObjectMapper();
final String BASE_URL = "http://localhost:8080/rest";
// Configure the Rest client
ClientConfig config = new ClientConfig();
config.proxyHost("localhost"); // helpful when sniffing traffic
config.proxyPort(50080); // helpful when sniffing traffic
config.followRedirects(false); // This is KEY for form auth
RestClient restClient = new RestClient(config);
// Get an unprotected resource -- to get a JSESSIONID
Resource resource = restClient.resource( BASE_URL + "/");
resource.header( "Accept", "*/*" );
ClientResponse response = resource.get();
// extract the jSession ID, in a brittle and ugly way
String jSessId = response.getHeaders().get("set-cookie").get(0).split(";")[0].split("=")[1];
// Get the login resource *j_security_check*
resource = restClient.resource(BASE_URL + "/j_security_check");
resource.cookie("j_username_tmp=admin; j_password_tmp=; JSESSIONID=" + jSessId);
resource.header("Content-Type", "application/x-www-form-urlencoded");
resource.header("Content-Length", "41");
// Verify that login resource redirects us
response = resource.post("j_username=admin&j_password=***********");
assertTrue( response.getStatusCode() == 302 );
// Grab a public resource
resource = restClient.resource(BASE_URL + "/");
resource.cookie("j_username_tmp=admin; j_password_tmp=; JSESSIONID=" + jSessId);
response = resource.get();
// verify status of response
assertTrue( response.getStatusCode() == 200 );
// Grab a protected resource
resource = restClient.resource(BASE_URL + "/rest/system");
resource.cookie("j_username_tmp=admin; j_password_tmp=; JSESSIONID=" + jSessId);
// Verify resource returned OK
response = resource.contentType("application/json").accept("*/*").get();
assertTrue( response.getStatusCode() == 200 );
// Deserialize body of protected response into domain object for further testing
MyObj myObj = mapper.readValue(response.getEntity(String.class), MyObj.class );
assertTrue( myObj.customerArchived() == false );
}