expl3 has a conditional just for that: \tl_if_single_token:nTF. It will return true only if the argument is exactly a single token. It returns false if the argument is empty, or if the argument is a braced group containing any number of tokens. expl3 also has \tl_if_single:nTF that returns true on x as well as on {x}, whereas \tl_if_single_token:nTF returns false on the latter.

\documentclass{article}
\ExplSyntaxOn
\cs_new_eq:NN \IfSingleTokenTF \tl_if_single_token:nTF
\cs_new_eq:NN \IfSingleItemTF \tl_if_single:nTF
\ExplSyntaxOff
\newcommand\foo[1]{%
\texttt{>#1: }%
\IfSingleTokenTF{#1}%
{\something}%
{\somethingelse}{#1}}
\newcommand\something[1]{(single:#1)}
\newcommand\somethingelse[1]{(multiple:#1)}
\begin{document}
\foo{}
\foo{ }
\foo{x}
\foo{ x}
\foo{xy}
\foo{{xy}}
\end{document}
As Frank noted in the comment, the code above works fine for XeTeX and LuaTeX because those engines tread UTF-8 characters like ä or as a single token. pdfTeX, on the other hand, treats ä as two and as four tokens, which when typesetting combine to produce a single glyph, thus the test above results as multiple tokens.
Depending on your use case (or if you want cross-engine compatibility) you might want to treat UTF-8 characters as a single token, in which case a bit more code is needed to check for those cases in pdfTeX:

The code first does the \tl_if_single_token:nTF test to eliminate the obvious case that the argument is indeed a single token. If that returns false, then we look at meaning of the first token in the argument, and if it is \UTFviii@(two|three|four)@octets then we know the first token is an UTF-8 char, in which case we remove the remaining tokens that compose the char and then test if what remains is empty: if it is, the only thing in the argument was the UTF-8 char, so return true, otherwise return false.
\documentclass{article}
\ExplSyntaxOn
\bool_lazy_or:nnTF
{ \sys_if_engine_luatex_p: }
{ \sys_if_engine_xetex_p: }
{
\cs_new_eq:NN \IfSingleTokenTF \tl_if_single_token:nTF
\use_none:n
}
{ \makeatletter \use:n }
{
\makeatother
\scan_new:N \s__fudo
\prg_new_conditional:Npnn \fudo_if_single_token:n #1 { T, F, TF }
{
\tl_if_single_token:nTF {#1}
{ \prg_return_true: }
{
\tl_if_head_is_N_type:nTF {#1}
{
\use:e
{
\exp_not:N __fudo_if_single_token_aux:w
\exp_not:o { \token_to_meaning:N #1 }
\tl_to_str:n { UTFviii@ one @octets } ~ \s__fudo
\exp_not:n {#1} \s__fudo
}
}
{ \prg_return_false: }
}
}
\use:e
{
\cs_new:Npn \exp_not:N __fudo_if_single_token_aux:w
#1 \tl_to_str:n { UTFviii@ } #2 \tl_to_str:n { @octets } ~
#3 \s__fudo #4 \s__fudo
}
{
\str_case:nnTF {#2}
{
{ one } { \exp_after:wN __fudo_single_chk:w \use_none:n }
{ two } { \exp_after:wN __fudo_single_chk:w \use_none:nn }
{ three } { \exp_after:wN __fudo_single_chk:w \use_none:nnn }
{ four } { \exp_after:wN __fudo_single_chk:w \use_none:nnnn }
}
{ #4 \s__fudo }
{ \prg_return_false: }
}
\cs_new:Npn __fudo_single_chk:w #1 \s__fudo
{
\tl_if_empty:nTF {#1}
{ \prg_return_true: }
{ \prg_return_false: }
}
\cs_new_eq:NN \IfSingleTokenTF \fudo_if_single_token:nTF
}
\ExplSyntaxOff
\newcommand\foo[1]{%
\texttt{>#1: }%
\IfSingleTokenTF{#1}%
{\something}%
{\somethingelse}{#1}}
\newcommand\something[1]{(single:#1)}
\newcommand\somethingelse[1]{(multiple:#1)}
\begin{document}
\foo{}
\foo{ }
\foo{x}
\foo{ä}
% \foo{鸟}
% \foo{}
\foo{ x}
\foo{xy}
\foo{{xy}}
\end{document}
The code does not understand é (U+0065 Latin Small Letter E + U+0301 Combining Acute Accent) as a single character. You have to input the proper Unicode U+00E9 Latin Small Letter E with Acute.
\expandafters by rewriting\expandafter\ifx\expandafter\relax\detokenize{#2}\relaxas\if\relax\detokenize{#2}\relax– Phelype Oleinik May 10 '21 at 15:55\foo's argument not being empty/blank and not containing the token\endfoounless as 1st token. If\foo's argument has leading space-tokens these will be discarded instead of being considered when\fooaux's 1st undelimited argument is gathered. – Ulrich Diez May 11 '21 at 12:40\endfoopoint is more of a quibble, as one chooses a delimiter that 100 monkeys typing at typewriters would require a million years to stumble across (though maybe\endfoois not quite that). The discarded space issue is more significant and I will think about addressing it. – Steven B. Segletes May 11 '21 at 14:11